Update SplitString calls to new form
[chromium-blink-merge.git] / net / server / http_server.cc
bloba3c4b5292650d49bd30d6c7153878e1412f02590
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/bind.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"
28 namespace net {
30 HttpServer::HttpServer(scoped_ptr<ServerSocket> server_socket,
31 HttpServer::Delegate* delegate)
32 : server_socket_(server_socket.Pass()),
33 delegate_(delegate),
34 last_id_(0),
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(
40 FROM_HERE,
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(
50 int connection_id,
51 const HttpServerRequestInfo& request) {
52 HttpConnection* connection = FindConnection(connection_id);
53 if (connection == NULL)
54 return;
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)
63 return;
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)
71 return;
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)
110 return;
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);
128 if (connection)
129 connection->read_buf()->set_max_buffer_size(size);
132 void HttpServer::SetSendBufferSize(int connection_id, int32 size) {
133 HttpConnection* connection = FindConnection(connection_id);
134 if (connection)
135 connection->write_buf()->set_max_buffer_size(size);
138 void HttpServer::DoAcceptLoop() {
139 int rv;
140 do {
141 rv = server_socket_->Accept(&accepted_socket_,
142 base::Bind(&HttpServer::OnAcceptCompleted,
143 weak_ptr_factory_.GetWeakPtr()));
144 if (rv == ERR_IO_PENDING)
145 return;
146 rv = HandleAcceptResult(rv);
147 } while (rv == OK);
150 void HttpServer::OnAcceptCompleted(int rv) {
151 if (HandleAcceptResult(rv) == OK)
152 DoAcceptLoop();
155 int HttpServer::HandleAcceptResult(int rv) {
156 if (rv < 0) {
157 LOG(ERROR) << "Accept error: rv=" << rv;
158 return 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);
167 return OK;
170 void HttpServer::DoReadLoop(HttpConnection* connection) {
171 int rv;
172 do {
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());
177 return;
180 rv = connection->socket()->Read(
181 read_buf,
182 read_buf->RemainingCapacity(),
183 base::Bind(&HttpServer::OnReadCompleted,
184 weak_ptr_factory_.GetWeakPtr(), connection->id()));
185 if (rv == ERR_IO_PENDING)
186 return;
187 rv = HandleReadResult(connection, rv);
188 } while (rv == OK);
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.
194 return;
196 if (HandleReadResult(connection, rv) == OK)
197 DoReadLoop(connection);
200 int HttpServer::HandleReadResult(HttpConnection* connection, int rv) {
201 if (rv <= 0) {
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()) {
212 std::string message;
213 WebSocket::ParseResult result = connection->web_socket()->Read(&message);
214 if (result == WebSocket::FRAME_INCOMPLETE)
215 break;
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;
225 continue;
228 HttpServerRequestInfo request;
229 size_t pos = 0;
230 if (!ParseHeaders(read_buf->StartOfBuffer(), read_buf->GetSize(),
231 &request, &pos)) {
232 break;
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.
242 break;
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;
248 continue;
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),
256 &content_length) ||
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;
278 return OK;
281 void HttpServer::DoWriteLoop(HttpConnection* connection) {
282 int rv = OK;
283 HttpConnection::QueuedWriteIOBuffer* write_buf = connection->write_buf();
284 while (rv == OK && write_buf->GetSizeToWrite() > 0) {
285 rv = connection->socket()->Write(
286 write_buf,
287 write_buf->GetSizeToWrite(),
288 base::Bind(&HttpServer::OnWriteCompleted,
289 weak_ptr_factory_.GetWeakPtr(), connection->id()));
290 if (rv == ERR_IO_PENDING || rv == OK)
291 return;
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.
299 return;
301 if (HandleWriteResult(connection, rv) == OK)
302 DoWriteLoop(connection);
305 int HttpServer::HandleWriteResult(HttpConnection* connection, int rv) {
306 if (rv < 0) {
307 Close(connection->id());
308 return rv;
311 connection->write_buf()->DidConsume(rv);
312 return OK;
315 namespace {
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.
323 // Known issues:
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 {
329 INPUT_LWS,
330 INPUT_CR,
331 INPUT_LF,
332 INPUT_COLON,
333 INPUT_DEFAULT,
334 MAX_INPUTS,
337 // Parser states.
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.
348 MAX_STATES
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) {
366 switch(ch) {
367 case ' ':
368 case '\t':
369 return INPUT_LWS;
370 case '\r':
371 return INPUT_CR;
372 case '\n':
373 return INPUT_LF;
374 case ':':
375 return INPUT_COLON;
377 return INPUT_DEFAULT;
380 } // namespace
382 bool HttpServer::ParseHeaders(const char* data,
383 size_t data_len,
384 HttpServerRequestInfo* info,
385 size_t* ppos) {
386 size_t& pos = *ppos;
387 int state = ST_METHOD;
388 std::string buffer;
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;
398 if (transition) {
399 // Do any actions based on state transitions.
400 switch (state) {
401 case ST_METHOD:
402 info->method = buffer;
403 buffer.clear();
404 break;
405 case ST_URL:
406 info->path = buffer;
407 buffer.clear();
408 break;
409 case ST_PROTO:
410 // TODO(mbelshe): Deal better with parsing protocol.
411 DCHECK(buffer == "HTTP/1.1");
412 buffer.clear();
413 break;
414 case ST_NAME:
415 header_name = base::StringToLowerASCII(buffer);
416 buffer.clear();
417 break;
418 case ST_VALUE:
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;
425 } else {
426 it->second.append(",");
427 it->second.append(header_value);
429 buffer.clear();
430 break;
431 case ST_SEPARATOR:
432 break;
434 state = next_state;
435 } else {
436 // Do any actions based on current state
437 switch (state) {
438 case ST_METHOD:
439 case ST_URL:
440 case ST_PROTO:
441 case ST_VALUE:
442 case ST_NAME:
443 buffer.append(&ch, 1);
444 break;
445 case ST_DONE:
446 DCHECK(input == INPUT_LF);
447 return true;
448 case ST_ERR:
449 return false;
453 // No more characters, but we haven't finished parsing yet.
454 return false;
457 HttpConnection* HttpServer::FindConnection(int connection_id) {
458 IdToConnectionMap::iterator it = id_to_connection_.find(connection_id);
459 if (it == id_to_connection_.end())
460 return NULL;
461 return it->second;
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
467 // loop.
468 bool HttpServer::HasClosedConnection(HttpConnection* connection) {
469 return FindConnection(connection->id()) != connection;
472 } // namespace net