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/single_thread_task_runner.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 "base/thread_task_runner_handle.h"
18 #include "build/build_config.h"
19 #include "net/base/net_errors.h"
20 #include "net/server/http_connection.h"
21 #include "net/server/http_server_request_info.h"
22 #include "net/server/http_server_response_info.h"
23 #include "net/server/web_socket.h"
24 #include "net/socket/server_socket.h"
25 #include "net/socket/stream_socket.h"
26 #include "net/socket/tcp_server_socket.h"
30 HttpServer::HttpServer(scoped_ptr
<ServerSocket
> server_socket
,
31 HttpServer::Delegate
* delegate
)
32 : server_socket_(server_socket
.Pass()),
35 weak_ptr_factory_(this) {
36 DCHECK(server_socket_
);
37 // Start accepting connections in next run loop in case when delegate is not
38 // ready to get callbacks.
39 base::ThreadTaskRunnerHandle::Get()->PostTask(
41 base::Bind(&HttpServer::DoAcceptLoop
, weak_ptr_factory_
.GetWeakPtr()));
44 HttpServer::~HttpServer() {
45 STLDeleteContainerPairSecondPointers(
46 id_to_connection_
.begin(), id_to_connection_
.end());
49 void HttpServer::AcceptWebSocket(
51 const HttpServerRequestInfo
& request
) {
52 HttpConnection
* connection
= FindConnection(connection_id
);
53 if (connection
== NULL
)
55 DCHECK(connection
->web_socket());
56 connection
->web_socket()->Accept(request
);
59 void HttpServer::SendOverWebSocket(int connection_id
,
60 const std::string
& data
) {
61 HttpConnection
* connection
= FindConnection(connection_id
);
62 if (connection
== NULL
)
64 DCHECK(connection
->web_socket());
65 connection
->web_socket()->Send(data
);
68 void HttpServer::SendRaw(int connection_id
, const std::string
& data
) {
69 HttpConnection
* connection
= FindConnection(connection_id
);
70 if (connection
== NULL
)
73 bool writing_in_progress
= !connection
->write_buf()->IsEmpty();
74 if (connection
->write_buf()->Append(data
) && !writing_in_progress
)
75 DoWriteLoop(connection
);
78 void HttpServer::SendResponse(int connection_id
,
79 const HttpServerResponseInfo
& response
) {
80 SendRaw(connection_id
, response
.Serialize());
83 void HttpServer::Send(int connection_id
,
84 HttpStatusCode status_code
,
85 const std::string
& data
,
86 const std::string
& content_type
) {
87 HttpServerResponseInfo
response(status_code
);
88 response
.SetContentHeaders(data
.size(), content_type
);
89 SendResponse(connection_id
, response
);
90 SendRaw(connection_id
, data
);
93 void HttpServer::Send200(int connection_id
,
94 const std::string
& data
,
95 const std::string
& content_type
) {
96 Send(connection_id
, HTTP_OK
, data
, content_type
);
99 void HttpServer::Send404(int connection_id
) {
100 SendResponse(connection_id
, HttpServerResponseInfo::CreateFor404());
103 void HttpServer::Send500(int connection_id
, const std::string
& message
) {
104 SendResponse(connection_id
, HttpServerResponseInfo::CreateFor500(message
));
107 void HttpServer::Close(int connection_id
) {
108 HttpConnection
* connection
= FindConnection(connection_id
);
109 if (connection
== NULL
)
112 id_to_connection_
.erase(connection_id
);
113 delegate_
->OnClose(connection_id
);
115 // The call stack might have callbacks which still have the pointer of
116 // connection. Instead of referencing connection with ID all the time,
117 // destroys the connection in next run loop to make sure any pending
118 // callbacks in the call stack return.
119 base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE
, connection
);
122 int HttpServer::GetLocalAddress(IPEndPoint
* address
) {
123 return server_socket_
->GetLocalAddress(address
);
126 void HttpServer::SetReceiveBufferSize(int connection_id
, int32 size
) {
127 HttpConnection
* connection
= FindConnection(connection_id
);
129 connection
->read_buf()->set_max_buffer_size(size
);
132 void HttpServer::SetSendBufferSize(int connection_id
, int32 size
) {
133 HttpConnection
* connection
= FindConnection(connection_id
);
135 connection
->write_buf()->set_max_buffer_size(size
);
138 void HttpServer::DoAcceptLoop() {
141 rv
= server_socket_
->Accept(&accepted_socket_
,
142 base::Bind(&HttpServer::OnAcceptCompleted
,
143 weak_ptr_factory_
.GetWeakPtr()));
144 if (rv
== ERR_IO_PENDING
)
146 rv
= HandleAcceptResult(rv
);
150 void HttpServer::OnAcceptCompleted(int rv
) {
151 if (HandleAcceptResult(rv
) == OK
)
155 int HttpServer::HandleAcceptResult(int rv
) {
157 LOG(ERROR
) << "Accept error: rv=" << rv
;
161 HttpConnection
* connection
=
162 new HttpConnection(++last_id_
, accepted_socket_
.Pass());
163 id_to_connection_
[connection
->id()] = connection
;
164 delegate_
->OnConnect(connection
->id());
165 if (!HasClosedConnection(connection
))
166 DoReadLoop(connection
);
170 void HttpServer::DoReadLoop(HttpConnection
* connection
) {
173 HttpConnection::ReadIOBuffer
* read_buf
= connection
->read_buf();
174 // Increases read buffer size if necessary.
175 if (read_buf
->RemainingCapacity() == 0 && !read_buf
->IncreaseCapacity()) {
176 Close(connection
->id());
180 rv
= connection
->socket()->Read(
182 read_buf
->RemainingCapacity(),
183 base::Bind(&HttpServer::OnReadCompleted
,
184 weak_ptr_factory_
.GetWeakPtr(), connection
->id()));
185 if (rv
== ERR_IO_PENDING
)
187 rv
= HandleReadResult(connection
, rv
);
191 void HttpServer::OnReadCompleted(int connection_id
, int rv
) {
192 HttpConnection
* connection
= FindConnection(connection_id
);
193 if (!connection
) // It might be closed right before by write error.
196 if (HandleReadResult(connection
, rv
) == OK
)
197 DoReadLoop(connection
);
200 int HttpServer::HandleReadResult(HttpConnection
* connection
, int rv
) {
202 Close(connection
->id());
203 return rv
== 0 ? ERR_CONNECTION_CLOSED
: rv
;
206 HttpConnection::ReadIOBuffer
* read_buf
= connection
->read_buf();
207 read_buf
->DidRead(rv
);
209 // Handles http requests or websocket messages.
210 while (read_buf
->GetSize() > 0) {
211 if (connection
->web_socket()) {
213 WebSocket::ParseResult result
= connection
->web_socket()->Read(&message
);
214 if (result
== WebSocket::FRAME_INCOMPLETE
)
217 if (result
== WebSocket::FRAME_CLOSE
||
218 result
== WebSocket::FRAME_ERROR
) {
219 Close(connection
->id());
220 return ERR_CONNECTION_CLOSED
;
222 delegate_
->OnWebSocketMessage(connection
->id(), message
);
223 if (HasClosedConnection(connection
))
224 return ERR_CONNECTION_CLOSED
;
228 HttpServerRequestInfo request
;
230 if (!ParseHeaders(read_buf
->StartOfBuffer(), read_buf
->GetSize(),
235 // Sets peer address if exists.
236 connection
->socket()->GetPeerAddress(&request
.peer
);
238 if (request
.HasHeaderValue("connection", "upgrade")) {
239 scoped_ptr
<WebSocket
> websocket(
240 WebSocket::CreateWebSocket(this, connection
, request
, &pos
));
241 if (!websocket
) // Not enough data was received.
243 connection
->SetWebSocket(websocket
.Pass());
244 read_buf
->DidConsume(pos
);
245 delegate_
->OnWebSocketRequest(connection
->id(), request
);
246 if (HasClosedConnection(connection
))
247 return ERR_CONNECTION_CLOSED
;
251 const char kContentLength
[] = "content-length";
252 if (request
.headers
.count(kContentLength
) > 0) {
253 size_t content_length
= 0;
254 const size_t kMaxBodySize
= 100 << 20;
255 if (!base::StringToSizeT(request
.GetHeaderValue(kContentLength
),
257 content_length
> kMaxBodySize
) {
258 SendResponse(connection
->id(),
259 HttpServerResponseInfo::CreateFor500(
260 "request content-length too big or unknown: " +
261 request
.GetHeaderValue(kContentLength
)));
262 Close(connection
->id());
263 return ERR_CONNECTION_CLOSED
;
266 if (read_buf
->GetSize() - pos
< content_length
)
267 break; // Not enough data was received yet.
268 request
.data
.assign(read_buf
->StartOfBuffer() + pos
, content_length
);
269 pos
+= content_length
;
272 read_buf
->DidConsume(pos
);
273 delegate_
->OnHttpRequest(connection
->id(), request
);
274 if (HasClosedConnection(connection
))
275 return ERR_CONNECTION_CLOSED
;
281 void HttpServer::DoWriteLoop(HttpConnection
* connection
) {
283 HttpConnection::QueuedWriteIOBuffer
* write_buf
= connection
->write_buf();
284 while (rv
== OK
&& write_buf
->GetSizeToWrite() > 0) {
285 rv
= connection
->socket()->Write(
287 write_buf
->GetSizeToWrite(),
288 base::Bind(&HttpServer::OnWriteCompleted
,
289 weak_ptr_factory_
.GetWeakPtr(), connection
->id()));
290 if (rv
== ERR_IO_PENDING
|| rv
== OK
)
292 rv
= HandleWriteResult(connection
, rv
);
296 void HttpServer::OnWriteCompleted(int connection_id
, int rv
) {
297 HttpConnection
* connection
= FindConnection(connection_id
);
298 if (!connection
) // It might be closed right before by read error.
301 if (HandleWriteResult(connection
, rv
) == OK
)
302 DoWriteLoop(connection
);
305 int HttpServer::HandleWriteResult(HttpConnection
* connection
, int rv
) {
307 Close(connection
->id());
311 connection
->write_buf()->DidConsume(rv
);
318 // HTTP Request Parser
319 // This HTTP request parser uses a simple state machine to quickly parse
320 // through the headers. The parser is not 100% complete, as it is designed
321 // for use in this simple test driver.
324 // - does not handle whitespace on first HTTP line correctly. Expects
325 // a single space between the method/url and url/protocol.
327 // Input character types.
328 enum header_parse_inputs
{
338 enum header_parse_states
{
339 ST_METHOD
, // Receiving the method
340 ST_URL
, // Receiving the URL
341 ST_PROTO
, // Receiving the protocol
342 ST_HEADER
, // Starting a Request Header
343 ST_NAME
, // Receiving a request header name
344 ST_SEPARATOR
, // Receiving the separator between header name and value
345 ST_VALUE
, // Receiving a request header value
346 ST_DONE
, // Parsing is complete and successful
347 ST_ERR
, // Parsing encountered invalid syntax.
351 // State transition table
352 int parser_state
[MAX_STATES
][MAX_INPUTS
] = {
353 /* METHOD */ { ST_URL
, ST_ERR
, ST_ERR
, ST_ERR
, ST_METHOD
},
354 /* URL */ { ST_PROTO
, ST_ERR
, ST_ERR
, ST_URL
, ST_URL
},
355 /* PROTOCOL */ { ST_ERR
, ST_HEADER
, ST_NAME
, ST_ERR
, ST_PROTO
},
356 /* HEADER */ { ST_ERR
, ST_ERR
, ST_NAME
, ST_ERR
, ST_ERR
},
357 /* NAME */ { ST_SEPARATOR
, ST_DONE
, ST_ERR
, ST_VALUE
, ST_NAME
},
358 /* SEPARATOR */ { ST_SEPARATOR
, ST_ERR
, ST_ERR
, ST_VALUE
, ST_ERR
},
359 /* VALUE */ { ST_VALUE
, ST_HEADER
, ST_NAME
, ST_VALUE
, ST_VALUE
},
360 /* DONE */ { ST_DONE
, ST_DONE
, ST_DONE
, ST_DONE
, ST_DONE
},
361 /* ERR */ { ST_ERR
, ST_ERR
, ST_ERR
, ST_ERR
, ST_ERR
}
364 // Convert an input character to the parser's input token.
365 int charToInput(char ch
) {
377 return INPUT_DEFAULT
;
382 bool HttpServer::ParseHeaders(const char* data
,
384 HttpServerRequestInfo
* info
,
387 int state
= ST_METHOD
;
389 std::string header_name
;
390 std::string header_value
;
391 while (pos
< data_len
) {
392 char ch
= data
[pos
++];
393 int input
= charToInput(ch
);
394 int next_state
= parser_state
[state
][input
];
396 bool transition
= (next_state
!= state
);
397 HttpServerRequestInfo::HeadersMap::iterator it
;
399 // Do any actions based on state transitions.
402 info
->method
= buffer
;
410 // TODO(mbelshe): Deal better with parsing protocol.
411 DCHECK(buffer
== "HTTP/1.1");
415 header_name
= base::ToLowerASCII(buffer
);
419 base::TrimWhitespaceASCII(buffer
, base::TRIM_LEADING
, &header_value
);
420 it
= info
->headers
.find(header_name
);
421 // See the second paragraph ("A sender MUST NOT generate multiple
422 // header fields...") of tools.ietf.org/html/rfc7230#section-3.2.2.
423 if (it
== info
->headers
.end()) {
424 info
->headers
[header_name
] = header_value
;
426 it
->second
.append(",");
427 it
->second
.append(header_value
);
436 // Do any actions based on current state
443 buffer
.append(&ch
, 1);
446 DCHECK(input
== INPUT_LF
);
453 // No more characters, but we haven't finished parsing yet.
457 HttpConnection
* HttpServer::FindConnection(int connection_id
) {
458 IdToConnectionMap::iterator it
= id_to_connection_
.find(connection_id
);
459 if (it
== id_to_connection_
.end())
464 // This is called after any delegate callbacks are called to check if Close()
465 // has been called during callback processing. Using the pointer of connection,
466 // |connection| is safe here because Close() deletes the connection in next run
468 bool HttpServer::HasClosedConnection(HttpConnection
* connection
) {
469 return FindConnection(connection
->id()) != connection
;