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"
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"
29 HttpServer::HttpServer(scoped_ptr
<ServerSocket
> server_socket
,
30 HttpServer::Delegate
* delegate
)
31 : server_socket_(server_socket
.Pass()),
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(
40 base::Bind(&HttpServer::DoAcceptLoop
, weak_ptr_factory_
.GetWeakPtr()));
43 HttpServer::~HttpServer() {
44 STLDeleteContainerPairSecondPointers(
45 id_to_connection_
.begin(), id_to_connection_
.end());
48 void HttpServer::AcceptWebSocket(
50 const HttpServerRequestInfo
& request
) {
51 HttpConnection
* connection
= FindConnection(connection_id
);
52 if (connection
== NULL
)
54 DCHECK(connection
->web_socket());
55 connection
->web_socket()->Accept(request
);
58 void HttpServer::SendOverWebSocket(int connection_id
,
59 const std::string
& data
) {
60 HttpConnection
* connection
= FindConnection(connection_id
);
61 if (connection
== NULL
)
63 DCHECK(connection
->web_socket());
64 connection
->web_socket()->Send(data
);
67 void HttpServer::SendRaw(int connection_id
, const std::string
& data
) {
68 HttpConnection
* connection
= FindConnection(connection_id
);
69 if (connection
== NULL
)
72 bool writing_in_progress
= !connection
->write_buf()->IsEmpty();
73 if (connection
->write_buf()->Append(data
) && !writing_in_progress
)
74 DoWriteLoop(connection
);
77 void HttpServer::SendResponse(int connection_id
,
78 const HttpServerResponseInfo
& response
) {
79 SendRaw(connection_id
, response
.Serialize());
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
);
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
);
98 void HttpServer::Send404(int connection_id
) {
99 SendResponse(connection_id
, HttpServerResponseInfo::CreateFor404());
102 void HttpServer::Send500(int connection_id
, const std::string
& message
) {
103 SendResponse(connection_id
, HttpServerResponseInfo::CreateFor500(message
));
106 void HttpServer::Close(int connection_id
) {
107 HttpConnection
* connection
= FindConnection(connection_id
);
108 if (connection
== NULL
)
111 id_to_connection_
.erase(connection_id
);
112 delegate_
->OnClose(connection_id
);
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
);
121 int HttpServer::GetLocalAddress(IPEndPoint
* address
) {
122 return server_socket_
->GetLocalAddress(address
);
125 void HttpServer::SetReceiveBufferSize(int connection_id
, int32 size
) {
126 HttpConnection
* connection
= FindConnection(connection_id
);
128 connection
->read_buf()->set_max_buffer_size(size
);
131 void HttpServer::SetSendBufferSize(int connection_id
, int32 size
) {
132 HttpConnection
* connection
= FindConnection(connection_id
);
134 connection
->write_buf()->set_max_buffer_size(size
);
137 void HttpServer::DoAcceptLoop() {
140 rv
= server_socket_
->Accept(&accepted_socket_
,
141 base::Bind(&HttpServer::OnAcceptCompleted
,
142 weak_ptr_factory_
.GetWeakPtr()));
143 if (rv
== ERR_IO_PENDING
)
145 rv
= HandleAcceptResult(rv
);
149 void HttpServer::OnAcceptCompleted(int rv
) {
150 if (HandleAcceptResult(rv
) == OK
)
154 int HttpServer::HandleAcceptResult(int rv
) {
156 LOG(ERROR
) << "Accept error: rv=" << rv
;
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
);
169 void HttpServer::DoReadLoop(HttpConnection
* connection
) {
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());
179 rv
= connection
->socket()->Read(
181 read_buf
->RemainingCapacity(),
182 base::Bind(&HttpServer::OnReadCompleted
,
183 weak_ptr_factory_
.GetWeakPtr(), connection
->id()));
184 if (rv
== ERR_IO_PENDING
)
186 rv
= HandleReadResult(connection
, rv
);
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.
195 if (HandleReadResult(connection
, rv
) == OK
)
196 DoReadLoop(connection
);
199 int HttpServer::HandleReadResult(HttpConnection
* connection
, int rv
) {
201 Close(connection
->id());
202 return rv
== 0 ? ERR_CONNECTION_CLOSED
: rv
;
205 HttpConnection::ReadIOBuffer
* read_buf
= connection
->read_buf();
206 read_buf
->DidRead(rv
);
208 // Handles http requests or websocket messages.
209 while (read_buf
->GetSize() > 0) {
210 if (connection
->web_socket()) {
212 WebSocket::ParseResult result
= connection
->web_socket()->Read(&message
);
213 if (result
== WebSocket::FRAME_INCOMPLETE
)
216 if (result
== WebSocket::FRAME_CLOSE
||
217 result
== WebSocket::FRAME_ERROR
) {
218 Close(connection
->id());
219 return ERR_CONNECTION_CLOSED
;
221 delegate_
->OnWebSocketMessage(connection
->id(), message
);
222 if (HasClosedConnection(connection
))
223 return ERR_CONNECTION_CLOSED
;
227 HttpServerRequestInfo request
;
229 if (!ParseHeaders(read_buf
->StartOfBuffer(), read_buf
->GetSize(),
234 // Sets peer address if exists.
235 connection
->socket()->GetPeerAddress(&request
.peer
);
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.
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
;
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
),
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
;
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
;
271 read_buf
->DidConsume(pos
);
272 delegate_
->OnHttpRequest(connection
->id(), request
);
273 if (HasClosedConnection(connection
))
274 return ERR_CONNECTION_CLOSED
;
280 void HttpServer::DoWriteLoop(HttpConnection
* connection
) {
282 HttpConnection::QueuedWriteIOBuffer
* write_buf
= connection
->write_buf();
283 while (rv
== OK
&& write_buf
->GetSizeToWrite() > 0) {
284 rv
= connection
->socket()->Write(
286 write_buf
->GetSizeToWrite(),
287 base::Bind(&HttpServer::OnWriteCompleted
,
288 weak_ptr_factory_
.GetWeakPtr(), connection
->id()));
289 if (rv
== ERR_IO_PENDING
|| rv
== OK
)
291 rv
= HandleWriteResult(connection
, rv
);
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.
300 if (HandleWriteResult(connection
, rv
) == OK
)
301 DoWriteLoop(connection
);
304 int HttpServer::HandleWriteResult(HttpConnection
* connection
, int rv
) {
306 Close(connection
->id());
310 connection
->write_buf()->DidConsume(rv
);
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.
323 // - does not handle whitespace on first HTTP line correctly. Expects
324 // a single space between the method/url and url/protocol.
326 // Input character types.
327 enum header_parse_inputs
{
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.
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
}
363 // Convert an input character to the parser's input token.
364 int charToInput(char ch
) {
376 return INPUT_DEFAULT
;
381 bool HttpServer::ParseHeaders(const char* data
,
383 HttpServerRequestInfo
* info
,
386 int state
= ST_METHOD
;
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
];
395 bool transition
= (next_state
!= state
);
396 HttpServerRequestInfo::HeadersMap::iterator it
;
398 // Do any actions based on state transitions.
401 info
->method
= buffer
;
409 // TODO(mbelshe): Deal better with parsing protocol.
410 DCHECK(buffer
== "HTTP/1.1");
414 header_name
= base::StringToLowerASCII(buffer
);
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
;
425 it
->second
.append(",");
426 it
->second
.append(header_value
);
435 // Do any actions based on current state
442 buffer
.append(&ch
, 1);
445 DCHECK(input
== INPUT_LF
);
452 // No more characters, but we haven't finished parsing yet.
456 HttpConnection
* HttpServer::FindConnection(int connection_id
) {
457 IdToConnectionMap::iterator it
= id_to_connection_
.find(connection_id
);
458 if (it
== id_to_connection_
.end())
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
467 bool HttpServer::HasClosedConnection(HttpConnection
* connection
) {
468 return FindConnection(connection
->id()) != connection
;