OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "net/server/http_server.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/compiler_specific.h" | |
9 #include "base/location.h" | |
10 #include "base/logging.h" | |
11 #include "base/message_loop/message_loop_proxy.h" | |
12 #include "base/stl_util.h" | |
13 #include "base/strings/string_number_conversions.h" | |
14 #include "base/strings/string_util.h" | |
15 #include "base/strings/stringprintf.h" | |
16 #include "base/sys_byteorder.h" | |
17 #include "build/build_config.h" | |
18 #include "net/base/net_errors.h" | |
19 #include "net/server/http_connection.h" | |
20 #include "net/server/http_server_request_info.h" | |
21 #include "net/server/http_server_response_info.h" | |
22 #include "net/server/web_socket.h" | |
23 #include "net/socket/server_socket.h" | |
24 #include "net/socket/stream_socket.h" | |
25 #include "net/socket/tcp_server_socket.h" | |
26 | |
27 namespace net { | |
28 | |
29 HttpServer::HttpServer(scoped_ptr<ServerSocket> server_socket, | |
30 HttpServer::Delegate* delegate) | |
31 : server_socket_(server_socket.Pass()), | |
32 delegate_(delegate), | |
33 last_id_(0), | |
34 weak_ptr_factory_(this) { | |
35 DCHECK(server_socket_); | |
36 // Start accepting connections in next run loop in case when delegate is not | |
37 // ready to get callbacks. | |
38 base::MessageLoopProxy::current()->PostTask( | |
39 FROM_HERE, | |
40 base::Bind(&HttpServer::DoAcceptLoop, weak_ptr_factory_.GetWeakPtr())); | |
41 } | |
42 | |
43 HttpServer::~HttpServer() { | |
44 STLDeleteContainerPairSecondPointers( | |
45 id_to_connection_.begin(), id_to_connection_.end()); | |
46 } | |
47 | |
48 void HttpServer::AcceptWebSocket( | |
49 int connection_id, | |
50 const HttpServerRequestInfo& request) { | |
51 HttpConnection* connection = FindConnection(connection_id); | |
52 if (connection == NULL) | |
53 return; | |
54 DCHECK(connection->web_socket()); | |
55 connection->web_socket()->Accept(request); | |
56 } | |
57 | |
58 void HttpServer::SendOverWebSocket(int connection_id, | |
59 const std::string& data) { | |
60 HttpConnection* connection = FindConnection(connection_id); | |
61 if (connection == NULL) | |
62 return; | |
63 DCHECK(connection->web_socket()); | |
64 connection->web_socket()->Send(data); | |
65 } | |
66 | |
67 void HttpServer::SendRaw(int connection_id, const std::string& data) { | |
68 HttpConnection* connection = FindConnection(connection_id); | |
69 if (connection == NULL) | |
70 return; | |
71 | |
72 bool writing_in_progress = !connection->write_buf()->IsEmpty(); | |
73 if (connection->write_buf()->Append(data) && !writing_in_progress) | |
74 DoWriteLoop(connection); | |
75 } | |
76 | |
77 void HttpServer::SendResponse(int connection_id, | |
78 const HttpServerResponseInfo& response) { | |
79 SendRaw(connection_id, response.Serialize()); | |
80 } | |
81 | |
82 void HttpServer::Send(int connection_id, | |
83 HttpStatusCode status_code, | |
84 const std::string& data, | |
85 const std::string& content_type) { | |
86 HttpServerResponseInfo response(status_code); | |
87 response.SetContentHeaders(data.size(), content_type); | |
88 SendResponse(connection_id, response); | |
89 SendRaw(connection_id, data); | |
90 } | |
91 | |
92 void HttpServer::Send200(int connection_id, | |
93 const std::string& data, | |
94 const std::string& content_type) { | |
95 Send(connection_id, HTTP_OK, data, content_type); | |
96 } | |
97 | |
98 void HttpServer::Send404(int connection_id) { | |
99 SendResponse(connection_id, HttpServerResponseInfo::CreateFor404()); | |
100 } | |
101 | |
102 void HttpServer::Send500(int connection_id, const std::string& message) { | |
103 SendResponse(connection_id, HttpServerResponseInfo::CreateFor500(message)); | |
104 } | |
105 | |
106 void HttpServer::Close(int connection_id) { | |
107 HttpConnection* connection = FindConnection(connection_id); | |
108 if (connection == NULL) | |
109 return; | |
110 | |
111 id_to_connection_.erase(connection_id); | |
112 delegate_->OnClose(connection_id); | |
113 | |
114 // The call stack might have callbacks which still have the pointer of | |
115 // connection. Instead of referencing connection with ID all the time, | |
116 // destroys the connection in next run loop to make sure any pending | |
117 // callbacks in the call stack return. | |
118 base::MessageLoopProxy::current()->DeleteSoon(FROM_HERE, connection); | |
119 } | |
120 | |
121 int HttpServer::GetLocalAddress(IPEndPoint* address) { | |
122 return server_socket_->GetLocalAddress(address); | |
123 } | |
124 | |
125 void HttpServer::SetReceiveBufferSize(int connection_id, int32 size) { | |
126 HttpConnection* connection = FindConnection(connection_id); | |
127 DCHECK(connection); | |
128 connection->read_buf()->set_max_buffer_size(size); | |
129 } | |
130 | |
131 void HttpServer::SetSendBufferSize(int connection_id, int32 size) { | |
132 HttpConnection* connection = FindConnection(connection_id); | |
133 DCHECK(connection); | |
134 connection->write_buf()->set_max_buffer_size(size); | |
135 } | |
136 | |
137 void HttpServer::DoAcceptLoop() { | |
138 int rv; | |
139 do { | |
140 rv = server_socket_->Accept(&accepted_socket_, | |
141 base::Bind(&HttpServer::OnAcceptCompleted, | |
142 weak_ptr_factory_.GetWeakPtr())); | |
143 if (rv == ERR_IO_PENDING) | |
144 return; | |
145 rv = HandleAcceptResult(rv); | |
146 } while (rv == OK); | |
147 } | |
148 | |
149 void HttpServer::OnAcceptCompleted(int rv) { | |
150 if (HandleAcceptResult(rv) == OK) | |
151 DoAcceptLoop(); | |
152 } | |
153 | |
154 int HttpServer::HandleAcceptResult(int rv) { | |
155 if (rv < 0) { | |
156 LOG(ERROR) << "Accept error: rv=" << rv; | |
157 return rv; | |
158 } | |
159 | |
160 HttpConnection* connection = | |
161 new HttpConnection(++last_id_, accepted_socket_.Pass()); | |
162 id_to_connection_[connection->id()] = connection; | |
163 delegate_->OnConnect(connection->id()); | |
164 if (!HasClosedConnection(connection)) | |
165 DoReadLoop(connection); | |
166 return OK; | |
167 } | |
168 | |
169 void HttpServer::DoReadLoop(HttpConnection* connection) { | |
170 int rv; | |
171 do { | |
172 HttpConnection::ReadIOBuffer* read_buf = connection->read_buf(); | |
173 // Increases read buffer size if necessary. | |
174 if (read_buf->RemainingCapacity() == 0 && !read_buf->IncreaseCapacity()) { | |
175 Close(connection->id()); | |
176 return; | |
177 } | |
178 | |
179 rv = connection->socket()->Read( | |
180 read_buf, | |
181 read_buf->RemainingCapacity(), | |
182 base::Bind(&HttpServer::OnReadCompleted, | |
183 weak_ptr_factory_.GetWeakPtr(), connection->id())); | |
184 if (rv == ERR_IO_PENDING) | |
185 return; | |
186 rv = HandleReadResult(connection, rv); | |
187 } while (rv == OK); | |
188 } | |
189 | |
190 void HttpServer::OnReadCompleted(int connection_id, int rv) { | |
191 HttpConnection* connection = FindConnection(connection_id); | |
192 if (!connection) // It might be closed right before by write error. | |
193 return; | |
194 | |
195 if (HandleReadResult(connection, rv) == OK) | |
196 DoReadLoop(connection); | |
197 } | |
198 | |
199 int HttpServer::HandleReadResult(HttpConnection* connection, int rv) { | |
200 if (rv <= 0) { | |
201 Close(connection->id()); | |
202 return rv == 0 ? ERR_CONNECTION_CLOSED : rv; | |
203 } | |
204 | |
205 HttpConnection::ReadIOBuffer* read_buf = connection->read_buf(); | |
206 read_buf->DidRead(rv); | |
207 | |
208 // Handles http requests or websocket messages. | |
209 while (read_buf->GetSize() > 0) { | |
210 if (connection->web_socket()) { | |
211 std::string message; | |
212 WebSocket::ParseResult result = connection->web_socket()->Read(&message); | |
213 if (result == WebSocket::FRAME_INCOMPLETE) | |
214 break; | |
215 | |
216 if (result == WebSocket::FRAME_CLOSE || | |
217 result == WebSocket::FRAME_ERROR) { | |
218 Close(connection->id()); | |
219 return ERR_CONNECTION_CLOSED; | |
220 } | |
221 delegate_->OnWebSocketMessage(connection->id(), message); | |
222 if (HasClosedConnection(connection)) | |
223 return ERR_CONNECTION_CLOSED; | |
224 continue; | |
225 } | |
226 | |
227 HttpServerRequestInfo request; | |
228 size_t pos = 0; | |
229 if (!ParseHeaders(read_buf->StartOfBuffer(), read_buf->GetSize(), | |
230 &request, &pos)) { | |
231 break; | |
232 } | |
233 | |
234 // Sets peer address if exists. | |
235 connection->socket()->GetPeerAddress(&request.peer); | |
236 | |
237 if (request.HasHeaderValue("connection", "upgrade")) { | |
238 scoped_ptr<WebSocket> websocket( | |
239 WebSocket::CreateWebSocket(this, connection, request, &pos)); | |
240 if (!websocket) // Not enough data was received. | |
241 break; | |
242 connection->SetWebSocket(websocket.Pass()); | |
243 read_buf->DidConsume(pos); | |
244 delegate_->OnWebSocketRequest(connection->id(), request); | |
245 if (HasClosedConnection(connection)) | |
246 return ERR_CONNECTION_CLOSED; | |
247 continue; | |
248 } | |
249 | |
250 const char kContentLength[] = "content-length"; | |
251 if (request.headers.count(kContentLength) > 0) { | |
252 size_t content_length = 0; | |
253 const size_t kMaxBodySize = 100 << 20; | |
254 if (!base::StringToSizeT(request.GetHeaderValue(kContentLength), | |
255 &content_length) || | |
256 content_length > kMaxBodySize) { | |
257 SendResponse(connection->id(), | |
258 HttpServerResponseInfo::CreateFor500( | |
259 "request content-length too big or unknown: " + | |
260 request.GetHeaderValue(kContentLength))); | |
261 Close(connection->id()); | |
262 return ERR_CONNECTION_CLOSED; | |
263 } | |
264 | |
265 if (read_buf->GetSize() - pos < content_length) | |
266 break; // Not enough data was received yet. | |
267 request.data.assign(read_buf->StartOfBuffer() + pos, content_length); | |
268 pos += content_length; | |
269 } | |
270 | |
271 read_buf->DidConsume(pos); | |
272 delegate_->OnHttpRequest(connection->id(), request); | |
273 if (HasClosedConnection(connection)) | |
274 return ERR_CONNECTION_CLOSED; | |
275 } | |
276 | |
277 return OK; | |
278 } | |
279 | |
280 void HttpServer::DoWriteLoop(HttpConnection* connection) { | |
281 int rv = OK; | |
282 HttpConnection::QueuedWriteIOBuffer* write_buf = connection->write_buf(); | |
283 while (rv == OK && write_buf->GetSizeToWrite() > 0) { | |
284 rv = connection->socket()->Write( | |
285 write_buf, | |
286 write_buf->GetSizeToWrite(), | |
287 base::Bind(&HttpServer::OnWriteCompleted, | |
288 weak_ptr_factory_.GetWeakPtr(), connection->id())); | |
289 if (rv == ERR_IO_PENDING || rv == OK) | |
290 return; | |
291 rv = HandleWriteResult(connection, rv); | |
292 } | |
293 } | |
294 | |
295 void HttpServer::OnWriteCompleted(int connection_id, int rv) { | |
296 HttpConnection* connection = FindConnection(connection_id); | |
297 if (!connection) // It might be closed right before by read error. | |
298 return; | |
299 | |
300 if (HandleWriteResult(connection, rv) == OK) | |
301 DoWriteLoop(connection); | |
302 } | |
303 | |
304 int HttpServer::HandleWriteResult(HttpConnection* connection, int rv) { | |
305 if (rv < 0) { | |
306 Close(connection->id()); | |
307 return rv; | |
308 } | |
309 | |
310 connection->write_buf()->DidConsume(rv); | |
311 return OK; | |
312 } | |
313 | |
314 namespace { | |
315 | |
316 // | |
317 // HTTP Request Parser | |
318 // This HTTP request parser uses a simple state machine to quickly parse | |
319 // through the headers. The parser is not 100% complete, as it is designed | |
320 // for use in this simple test driver. | |
321 // | |
322 // Known issues: | |
323 // - does not handle whitespace on first HTTP line correctly. Expects | |
324 // a single space between the method/url and url/protocol. | |
325 | |
326 // Input character types. | |
327 enum header_parse_inputs { | |
328 INPUT_LWS, | |
329 INPUT_CR, | |
330 INPUT_LF, | |
331 INPUT_COLON, | |
332 INPUT_DEFAULT, | |
333 MAX_INPUTS, | |
334 }; | |
335 | |
336 // Parser states. | |
337 enum header_parse_states { | |
338 ST_METHOD, // Receiving the method | |
339 ST_URL, // Receiving the URL | |
340 ST_PROTO, // Receiving the protocol | |
341 ST_HEADER, // Starting a Request Header | |
342 ST_NAME, // Receiving a request header name | |
343 ST_SEPARATOR, // Receiving the separator between header name and value | |
344 ST_VALUE, // Receiving a request header value | |
345 ST_DONE, // Parsing is complete and successful | |
346 ST_ERR, // Parsing encountered invalid syntax. | |
347 MAX_STATES | |
348 }; | |
349 | |
350 // State transition table | |
351 int parser_state[MAX_STATES][MAX_INPUTS] = { | |
352 /* METHOD */ { ST_URL, ST_ERR, ST_ERR, ST_ERR, ST_METHOD }, | |
353 /* URL */ { ST_PROTO, ST_ERR, ST_ERR, ST_URL, ST_URL }, | |
354 /* PROTOCOL */ { ST_ERR, ST_HEADER, ST_NAME, ST_ERR, ST_PROTO }, | |
355 /* HEADER */ { ST_ERR, ST_ERR, ST_NAME, ST_ERR, ST_ERR }, | |
356 /* NAME */ { ST_SEPARATOR, ST_DONE, ST_ERR, ST_VALUE, ST_NAME }, | |
357 /* SEPARATOR */ { ST_SEPARATOR, ST_ERR, ST_ERR, ST_VALUE, ST_ERR }, | |
358 /* VALUE */ { ST_VALUE, ST_HEADER, ST_NAME, ST_VALUE, ST_VALUE }, | |
359 /* DONE */ { ST_DONE, ST_DONE, ST_DONE, ST_DONE, ST_DONE }, | |
360 /* ERR */ { ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_ERR } | |
361 }; | |
362 | |
363 // Convert an input character to the parser's input token. | |
364 int charToInput(char ch) { | |
365 switch(ch) { | |
366 case ' ': | |
367 case '\t': | |
368 return INPUT_LWS; | |
369 case '\r': | |
370 return INPUT_CR; | |
371 case '\n': | |
372 return INPUT_LF; | |
373 case ':': | |
374 return INPUT_COLON; | |
375 } | |
376 return INPUT_DEFAULT; | |
377 } | |
378 | |
379 } // namespace | |
380 | |
381 bool HttpServer::ParseHeaders(const char* data, | |
382 size_t data_len, | |
383 HttpServerRequestInfo* info, | |
384 size_t* ppos) { | |
385 size_t& pos = *ppos; | |
386 int state = ST_METHOD; | |
387 std::string buffer; | |
388 std::string header_name; | |
389 std::string header_value; | |
390 while (pos < data_len) { | |
391 char ch = data[pos++]; | |
392 int input = charToInput(ch); | |
393 int next_state = parser_state[state][input]; | |
394 | |
395 bool transition = (next_state != state); | |
396 HttpServerRequestInfo::HeadersMap::iterator it; | |
397 if (transition) { | |
398 // Do any actions based on state transitions. | |
399 switch (state) { | |
400 case ST_METHOD: | |
401 info->method = buffer; | |
402 buffer.clear(); | |
403 break; | |
404 case ST_URL: | |
405 info->path = buffer; | |
406 buffer.clear(); | |
407 break; | |
408 case ST_PROTO: | |
409 // TODO(mbelshe): Deal better with parsing protocol. | |
410 DCHECK(buffer == "HTTP/1.1"); | |
411 buffer.clear(); | |
412 break; | |
413 case ST_NAME: | |
414 header_name = base::StringToLowerASCII(buffer); | |
415 buffer.clear(); | |
416 break; | |
417 case ST_VALUE: | |
418 base::TrimWhitespaceASCII(buffer, base::TRIM_LEADING, &header_value); | |
419 it = info->headers.find(header_name); | |
420 // See last paragraph ("Multiple message-header fields...") | |
421 // of www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 | |
422 if (it == info->headers.end()) { | |
423 info->headers[header_name] = header_value; | |
424 } else { | |
425 it->second.append(","); | |
426 it->second.append(header_value); | |
427 } | |
428 buffer.clear(); | |
429 break; | |
430 case ST_SEPARATOR: | |
431 break; | |
432 } | |
433 state = next_state; | |
434 } else { | |
435 // Do any actions based on current state | |
436 switch (state) { | |
437 case ST_METHOD: | |
438 case ST_URL: | |
439 case ST_PROTO: | |
440 case ST_VALUE: | |
441 case ST_NAME: | |
442 buffer.append(&ch, 1); | |
443 break; | |
444 case ST_DONE: | |
445 DCHECK(input == INPUT_LF); | |
446 return true; | |
447 case ST_ERR: | |
448 return false; | |
449 } | |
450 } | |
451 } | |
452 // No more characters, but we haven't finished parsing yet. | |
453 return false; | |
454 } | |
455 | |
456 HttpConnection* HttpServer::FindConnection(int connection_id) { | |
457 IdToConnectionMap::iterator it = id_to_connection_.find(connection_id); | |
458 if (it == id_to_connection_.end()) | |
459 return NULL; | |
460 return it->second; | |
461 } | |
462 | |
463 // This is called after any delegate callbacks are called to check if Close() | |
464 // has been called during callback processing. Using the pointer of connection, | |
465 // |connection| is safe here because Close() deletes the connection in next run | |
466 // loop. | |
467 bool HttpServer::HasClosedConnection(HttpConnection* connection) { | |
468 return FindConnection(connection->id()) != connection; | |
469 } | |
470 | |
471 } // namespace net | |
OLD | NEW |