Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / net / server / http_server.cc
blobdf77c3672daa423fe54127495aa18b7a4262a104
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/server/http_server.h"
7 #include "base/compiler_specific.h"
8 #include "base/logging.h"
9 #include "base/stl_util.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/sys_byteorder.h"
14 #include "build/build_config.h"
15 #include "net/base/net_errors.h"
16 #include "net/server/http_connection.h"
17 #include "net/server/http_server_request_info.h"
18 #include "net/server/http_server_response_info.h"
19 #include "net/server/web_socket.h"
20 #include "net/socket/tcp_listen_socket.h"
22 namespace net {
24 HttpServer::HttpServer(const StreamListenSocketFactory& factory,
25 HttpServer::Delegate* delegate)
26 : delegate_(delegate),
27 server_(factory.CreateAndListen(this)) {
30 void HttpServer::AcceptWebSocket(
31 int connection_id,
32 const HttpServerRequestInfo& request) {
33 HttpConnection* connection = FindConnection(connection_id);
34 if (connection == NULL)
35 return;
37 DCHECK(connection->web_socket_.get());
38 connection->web_socket_->Accept(request);
41 void HttpServer::SendOverWebSocket(int connection_id,
42 const std::string& data) {
43 HttpConnection* connection = FindConnection(connection_id);
44 if (connection == NULL)
45 return;
46 DCHECK(connection->web_socket_.get());
47 connection->web_socket_->Send(data);
50 void HttpServer::SendRaw(int connection_id, const std::string& data) {
51 HttpConnection* connection = FindConnection(connection_id);
52 if (connection == NULL)
53 return;
54 connection->Send(data);
57 void HttpServer::SendResponse(int connection_id,
58 const HttpServerResponseInfo& response) {
59 HttpConnection* connection = FindConnection(connection_id);
60 if (connection == NULL)
61 return;
62 connection->Send(response);
65 void HttpServer::Send(int connection_id,
66 HttpStatusCode status_code,
67 const std::string& data,
68 const std::string& content_type) {
69 HttpServerResponseInfo response(status_code);
70 response.SetBody(data, content_type);
71 SendResponse(connection_id, response);
74 void HttpServer::Send200(int connection_id,
75 const std::string& data,
76 const std::string& content_type) {
77 Send(connection_id, HTTP_OK, data, content_type);
80 void HttpServer::Send404(int connection_id) {
81 SendResponse(connection_id, HttpServerResponseInfo::CreateFor404());
84 void HttpServer::Send500(int connection_id, const std::string& message) {
85 SendResponse(connection_id, HttpServerResponseInfo::CreateFor500(message));
88 void HttpServer::Close(int connection_id) {
89 HttpConnection* connection = FindConnection(connection_id);
90 if (connection == NULL)
91 return;
93 // Initiating close from server-side does not lead to the DidClose call.
94 // Do it manually here.
95 DidClose(connection->socket_.get());
98 int HttpServer::GetLocalAddress(IPEndPoint* address) {
99 if (!server_)
100 return ERR_SOCKET_NOT_CONNECTED;
101 return server_->GetLocalAddress(address);
104 void HttpServer::DidAccept(StreamListenSocket* server,
105 scoped_ptr<StreamListenSocket> socket) {
106 HttpConnection* connection = new HttpConnection(this, socket.Pass());
107 id_to_connection_[connection->id()] = connection;
108 // TODO(szym): Fix socket access. Make HttpConnection the Delegate.
109 socket_to_connection_[connection->socket_.get()] = connection;
112 void HttpServer::DidRead(StreamListenSocket* socket,
113 const char* data,
114 int len) {
115 HttpConnection* connection = FindConnection(socket);
116 DCHECK(connection != NULL);
117 if (connection == NULL)
118 return;
120 connection->recv_data_.append(data, len);
121 while (connection->recv_data_.length()) {
122 if (connection->web_socket_.get()) {
123 std::string message;
124 WebSocket::ParseResult result = connection->web_socket_->Read(&message);
125 if (result == WebSocket::FRAME_INCOMPLETE)
126 break;
128 if (result == WebSocket::FRAME_CLOSE ||
129 result == WebSocket::FRAME_ERROR) {
130 Close(connection->id());
131 break;
133 delegate_->OnWebSocketMessage(connection->id(), message);
134 continue;
137 HttpServerRequestInfo request;
138 size_t pos = 0;
139 if (!ParseHeaders(connection, &request, &pos))
140 break;
142 // Sets peer address if exists.
143 socket->GetPeerAddress(&request.peer);
145 std::string connection_header = request.GetHeaderValue("connection");
146 if (connection_header == "Upgrade") {
147 connection->web_socket_.reset(WebSocket::CreateWebSocket(connection,
148 request,
149 &pos));
151 if (!connection->web_socket_.get()) // Not enough data was received.
152 break;
153 delegate_->OnWebSocketRequest(connection->id(), request);
154 connection->Shift(pos);
155 continue;
158 const char kContentLength[] = "content-length";
159 if (request.headers.count(kContentLength)) {
160 size_t content_length = 0;
161 const size_t kMaxBodySize = 100 << 20;
162 if (!base::StringToSizeT(request.GetHeaderValue(kContentLength),
163 &content_length) ||
164 content_length > kMaxBodySize) {
165 connection->Send(HttpServerResponseInfo::CreateFor500(
166 "request content-length too big or unknown: " +
167 request.GetHeaderValue(kContentLength)));
168 DidClose(socket);
169 break;
172 if (connection->recv_data_.length() - pos < content_length)
173 break; // Not enough data was received yet.
174 request.data = connection->recv_data_.substr(pos, content_length);
175 pos += content_length;
178 delegate_->OnHttpRequest(connection->id(), request);
179 connection->Shift(pos);
183 void HttpServer::DidClose(StreamListenSocket* socket) {
184 HttpConnection* connection = FindConnection(socket);
185 DCHECK(connection != NULL);
186 id_to_connection_.erase(connection->id());
187 socket_to_connection_.erase(connection->socket_.get());
188 delete connection;
191 HttpServer::~HttpServer() {
192 STLDeleteContainerPairSecondPointers(
193 id_to_connection_.begin(), id_to_connection_.end());
197 // HTTP Request Parser
198 // This HTTP request parser uses a simple state machine to quickly parse
199 // through the headers. The parser is not 100% complete, as it is designed
200 // for use in this simple test driver.
202 // Known issues:
203 // - does not handle whitespace on first HTTP line correctly. Expects
204 // a single space between the method/url and url/protocol.
206 // Input character types.
207 enum header_parse_inputs {
208 INPUT_SPACE,
209 INPUT_CR,
210 INPUT_LF,
211 INPUT_COLON,
212 INPUT_DEFAULT,
213 MAX_INPUTS,
216 // Parser states.
217 enum header_parse_states {
218 ST_METHOD, // Receiving the method
219 ST_URL, // Receiving the URL
220 ST_PROTO, // Receiving the protocol
221 ST_HEADER, // Starting a Request Header
222 ST_NAME, // Receiving a request header name
223 ST_SEPARATOR, // Receiving the separator between header name and value
224 ST_VALUE, // Receiving a request header value
225 ST_DONE, // Parsing is complete and successful
226 ST_ERR, // Parsing encountered invalid syntax.
227 MAX_STATES
230 // State transition table
231 int parser_state[MAX_STATES][MAX_INPUTS] = {
232 /* METHOD */ { ST_URL, ST_ERR, ST_ERR, ST_ERR, ST_METHOD },
233 /* URL */ { ST_PROTO, ST_ERR, ST_ERR, ST_URL, ST_URL },
234 /* PROTOCOL */ { ST_ERR, ST_HEADER, ST_NAME, ST_ERR, ST_PROTO },
235 /* HEADER */ { ST_ERR, ST_ERR, ST_NAME, ST_ERR, ST_ERR },
236 /* NAME */ { ST_SEPARATOR, ST_DONE, ST_ERR, ST_VALUE, ST_NAME },
237 /* SEPARATOR */ { ST_SEPARATOR, ST_ERR, ST_ERR, ST_VALUE, ST_ERR },
238 /* VALUE */ { ST_VALUE, ST_HEADER, ST_NAME, ST_VALUE, ST_VALUE },
239 /* DONE */ { ST_DONE, ST_DONE, ST_DONE, ST_DONE, ST_DONE },
240 /* ERR */ { ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_ERR }
243 // Convert an input character to the parser's input token.
244 int charToInput(char ch) {
245 switch(ch) {
246 case ' ':
247 return INPUT_SPACE;
248 case '\r':
249 return INPUT_CR;
250 case '\n':
251 return INPUT_LF;
252 case ':':
253 return INPUT_COLON;
255 return INPUT_DEFAULT;
258 bool HttpServer::ParseHeaders(HttpConnection* connection,
259 HttpServerRequestInfo* info,
260 size_t* ppos) {
261 size_t& pos = *ppos;
262 size_t data_len = connection->recv_data_.length();
263 int state = ST_METHOD;
264 std::string buffer;
265 std::string header_name;
266 std::string header_value;
267 while (pos < data_len) {
268 char ch = connection->recv_data_[pos++];
269 int input = charToInput(ch);
270 int next_state = parser_state[state][input];
272 bool transition = (next_state != state);
273 if (transition) {
274 // Do any actions based on state transitions.
275 switch (state) {
276 case ST_METHOD:
277 info->method = buffer;
278 buffer.clear();
279 break;
280 case ST_URL:
281 info->path = buffer;
282 buffer.clear();
283 break;
284 case ST_PROTO:
285 // TODO(mbelshe): Deal better with parsing protocol.
286 DCHECK(buffer == "HTTP/1.1");
287 buffer.clear();
288 break;
289 case ST_NAME:
290 header_name = StringToLowerASCII(buffer);
291 buffer.clear();
292 break;
293 case ST_VALUE:
294 base::TrimWhitespaceASCII(buffer, base::TRIM_LEADING, &header_value);
295 // TODO(mbelshe): Deal better with duplicate headers
296 DCHECK(info->headers.find(header_name) == info->headers.end());
297 info->headers[header_name] = header_value;
298 buffer.clear();
299 break;
300 case ST_SEPARATOR:
301 break;
303 state = next_state;
304 } else {
305 // Do any actions based on current state
306 switch (state) {
307 case ST_METHOD:
308 case ST_URL:
309 case ST_PROTO:
310 case ST_VALUE:
311 case ST_NAME:
312 buffer.append(&ch, 1);
313 break;
314 case ST_DONE:
315 DCHECK(input == INPUT_LF);
316 return true;
317 case ST_ERR:
318 return false;
322 // No more characters, but we haven't finished parsing yet.
323 return false;
326 HttpConnection* HttpServer::FindConnection(int connection_id) {
327 IdToConnectionMap::iterator it = id_to_connection_.find(connection_id);
328 if (it == id_to_connection_.end())
329 return NULL;
330 return it->second;
333 HttpConnection* HttpServer::FindConnection(StreamListenSocket* socket) {
334 SocketToConnectionMap::iterator it = socket_to_connection_.find(socket);
335 if (it == socket_to_connection_.end())
336 return NULL;
337 return it->second;
340 } // namespace net