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"
24 HttpServer::HttpServer(const StreamListenSocketFactory& factory,
25 HttpServer::Delegate* delegate)
26 : delegate_(delegate),
27 server_(factory.CreateAndListen(this)) {
30 void HttpServer::AcceptWebSocket(
32 const HttpServerRequestInfo& request) {
33 HttpConnection* connection = FindConnection(connection_id);
34 if (connection == NULL)
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)
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)
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)
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)
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) {
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,
115 HttpConnection* connection = FindConnection(socket);
116 DCHECK(connection != NULL);
117 if (connection == NULL)
120 connection->recv_data_.append(data, len);
121 while (connection->recv_data_.length()) {
122 if (connection->web_socket_.get()) {
124 WebSocket::ParseResult result = connection->web_socket_->Read(&message);
125 if (result == WebSocket::FRAME_INCOMPLETE)
128 if (result == WebSocket::FRAME_CLOSE ||
129 result == WebSocket::FRAME_ERROR) {
130 Close(connection->id());
133 delegate_->OnWebSocketMessage(connection->id(), message);
137 HttpServerRequestInfo request;
139 if (!ParseHeaders(connection, &request, &pos))
142 // Sets peer address if exists.
143 socket->GetPeerAddress(&request.peer);
145 if (request.HasHeaderValue("connection", "upgrade")) {
146 connection->web_socket_.reset(WebSocket::CreateWebSocket(connection,
150 if (!connection->web_socket_.get()) // Not enough data was received.
152 delegate_->OnWebSocketRequest(connection->id(), request);
153 connection->Shift(pos);
157 const char kContentLength[] = "content-length";
158 if (request.headers.count(kContentLength)) {
159 size_t content_length = 0;
160 const size_t kMaxBodySize = 100 << 20;
161 if (!base::StringToSizeT(request.GetHeaderValue(kContentLength),
163 content_length > kMaxBodySize) {
164 connection->Send(HttpServerResponseInfo::CreateFor500(
165 "request content-length too big or unknown: " +
166 request.GetHeaderValue(kContentLength)));
171 if (connection->recv_data_.length() - pos < content_length)
172 break; // Not enough data was received yet.
173 request.data = connection->recv_data_.substr(pos, content_length);
174 pos += content_length;
177 delegate_->OnHttpRequest(connection->id(), request);
178 connection->Shift(pos);
182 void HttpServer::DidClose(StreamListenSocket* socket) {
183 HttpConnection* connection = FindConnection(socket);
184 DCHECK(connection != NULL);
185 id_to_connection_.erase(connection->id());
186 socket_to_connection_.erase(connection->socket_.get());
190 HttpServer::~HttpServer() {
191 STLDeleteContainerPairSecondPointers(
192 id_to_connection_.begin(), id_to_connection_.end());
196 // HTTP Request Parser
197 // This HTTP request parser uses a simple state machine to quickly parse
198 // through the headers. The parser is not 100% complete, as it is designed
199 // for use in this simple test driver.
202 // - does not handle whitespace on first HTTP line correctly. Expects
203 // a single space between the method/url and url/protocol.
205 // Input character types.
206 enum header_parse_inputs {
216 enum header_parse_states {
217 ST_METHOD, // Receiving the method
218 ST_URL, // Receiving the URL
219 ST_PROTO, // Receiving the protocol
220 ST_HEADER, // Starting a Request Header
221 ST_NAME, // Receiving a request header name
222 ST_SEPARATOR, // Receiving the separator between header name and value
223 ST_VALUE, // Receiving a request header value
224 ST_DONE, // Parsing is complete and successful
225 ST_ERR, // Parsing encountered invalid syntax.
229 // State transition table
230 int parser_state[MAX_STATES][MAX_INPUTS] = {
231 /* METHOD */ { ST_URL, ST_ERR, ST_ERR, ST_ERR, ST_METHOD },
232 /* URL */ { ST_PROTO, ST_ERR, ST_ERR, ST_URL, ST_URL },
233 /* PROTOCOL */ { ST_ERR, ST_HEADER, ST_NAME, ST_ERR, ST_PROTO },
234 /* HEADER */ { ST_ERR, ST_ERR, ST_NAME, ST_ERR, ST_ERR },
235 /* NAME */ { ST_SEPARATOR, ST_DONE, ST_ERR, ST_VALUE, ST_NAME },
236 /* SEPARATOR */ { ST_SEPARATOR, ST_ERR, ST_ERR, ST_VALUE, ST_ERR },
237 /* VALUE */ { ST_VALUE, ST_HEADER, ST_NAME, ST_VALUE, ST_VALUE },
238 /* DONE */ { ST_DONE, ST_DONE, ST_DONE, ST_DONE, ST_DONE },
239 /* ERR */ { ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_ERR }
242 // Convert an input character to the parser's input token.
243 int charToInput(char ch) {
255 return INPUT_DEFAULT;
258 bool HttpServer::ParseHeaders(HttpConnection* connection,
259 HttpServerRequestInfo* info,
262 size_t data_len = connection->recv_data_.length();
263 int state = ST_METHOD;
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 HttpServerRequestInfo::HeadersMap::iterator it;
275 // Do any actions based on state transitions.
278 info->method = buffer;
286 // TODO(mbelshe): Deal better with parsing protocol.
287 DCHECK(buffer == "HTTP/1.1");
291 header_name = base::StringToLowerASCII(buffer);
295 base::TrimWhitespaceASCII(buffer, base::TRIM_LEADING, &header_value);
296 it = info->headers.find(header_name);
297 // See last paragraph ("Multiple message-header fields...")
298 // of www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
299 if (it == info->headers.end()) {
300 info->headers[header_name] = header_value;
302 it->second.append(",");
303 it->second.append(header_value);
312 // Do any actions based on current state
319 buffer.append(&ch, 1);
322 DCHECK(input == INPUT_LF);
329 // No more characters, but we haven't finished parsing yet.
333 HttpConnection* HttpServer::FindConnection(int connection_id) {
334 IdToConnectionMap::iterator it = id_to_connection_.find(connection_id);
335 if (it == id_to_connection_.end())
340 HttpConnection* HttpServer::FindConnection(StreamListenSocket* socket) {
341 SocketToConnectionMap::iterator it = socket_to_connection_.find(socket);
342 if (it == socket_to_connection_.end())