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/string_util.h"
10 #include "base/stringprintf.h"
11 #include "base/sys_byteorder.h"
12 #include "build/build_config.h"
13 #include "net/base/tcp_listen_socket.h"
14 #include "net/server/http_connection.h"
15 #include "net/server/http_server_request_info.h"
16 #include "net/server/web_socket.h"
20 HttpServer::HttpServer(const std::string
& host
,
22 HttpServer::Delegate
* del
)
24 server_
= TCPListenSocket::CreateAndListen(host
, port
, this);
27 HttpServer::~HttpServer() {
28 IdToConnectionMap copy
= id_to_connection_
;
29 for (IdToConnectionMap::iterator it
= copy
.begin(); it
!= copy
.end(); ++it
)
35 void HttpServer::Send(int connection_id
, const std::string
& data
) {
36 HttpConnection
* connection
= FindConnection(connection_id
);
37 if (connection
== NULL
)
39 connection
->Send(data
);
42 void HttpServer::Send(int connection_id
, const char* bytes
, int len
) {
43 HttpConnection
* connection
= FindConnection(connection_id
);
44 if (connection
== NULL
)
47 connection
->Send(bytes
, len
);
50 void HttpServer::Send200(int connection_id
,
51 const std::string
& data
,
52 const std::string
& content_type
) {
53 HttpConnection
* connection
= FindConnection(connection_id
);
54 if (connection
== NULL
)
56 connection
->Send200(data
, content_type
);
59 void HttpServer::Send404(int connection_id
) {
60 HttpConnection
* connection
= FindConnection(connection_id
);
61 if (connection
== NULL
)
63 connection
->Send404();
66 void HttpServer::Send500(int connection_id
, const std::string
& message
) {
67 HttpConnection
* connection
= FindConnection(connection_id
);
68 if (connection
== NULL
)
70 connection
->Send500(message
);
73 void HttpServer::Close(int connection_id
)
75 HttpConnection
* connection
= FindConnection(connection_id
);
76 if (connection
== NULL
)
79 // Initiating close from server-side does not lead to the DidClose call.
80 // Do it manually here.
81 DidClose(connection
->socket_
);
85 // HTTP Request Parser
86 // This HTTP request parser uses a simple state machine to quickly parse
87 // through the headers. The parser is not 100% complete, as it is designed
88 // for use in this simple test driver.
91 // - does not handle whitespace on first HTTP line correctly. Expects
92 // a single space between the method/url and url/protocol.
94 // Input character types.
95 enum header_parse_inputs
{
105 enum header_parse_states
{
106 ST_METHOD
, // Receiving the method
107 ST_URL
, // Receiving the URL
108 ST_PROTO
, // Receiving the protocol
109 ST_HEADER
, // Starting a Request Header
110 ST_NAME
, // Receiving a request header name
111 ST_SEPARATOR
, // Receiving the separator between header name and value
112 ST_VALUE
, // Receiving a request header value
113 ST_DONE
, // Parsing is complete and successful
114 ST_ERR
, // Parsing encountered invalid syntax.
118 // State transition table
119 int parser_state
[MAX_STATES
][MAX_INPUTS
] = {
120 /* METHOD */ { ST_URL
, ST_ERR
, ST_ERR
, ST_ERR
, ST_METHOD
},
121 /* URL */ { ST_PROTO
, ST_ERR
, ST_ERR
, ST_URL
, ST_URL
},
122 /* PROTOCOL */ { ST_ERR
, ST_HEADER
, ST_NAME
, ST_ERR
, ST_PROTO
},
123 /* HEADER */ { ST_ERR
, ST_ERR
, ST_NAME
, ST_ERR
, ST_ERR
},
124 /* NAME */ { ST_SEPARATOR
, ST_DONE
, ST_ERR
, ST_SEPARATOR
, ST_NAME
},
125 /* SEPARATOR */ { ST_SEPARATOR
, ST_ERR
, ST_ERR
, ST_SEPARATOR
, ST_VALUE
},
126 /* VALUE */ { ST_VALUE
, ST_HEADER
, ST_NAME
, ST_VALUE
, ST_VALUE
},
127 /* DONE */ { ST_DONE
, ST_DONE
, ST_DONE
, ST_DONE
, ST_DONE
},
128 /* ERR */ { ST_ERR
, ST_ERR
, ST_ERR
, ST_ERR
, ST_ERR
}
131 // Convert an input character to the parser's input token.
132 int charToInput(char ch
) {
143 return INPUT_DEFAULT
;
146 bool HttpServer::ParseHeaders(HttpConnection
* connection
,
147 HttpServerRequestInfo
* info
,
150 size_t data_len
= connection
->recv_data_
.length();
151 int state
= ST_METHOD
;
153 std::string header_name
;
154 std::string header_value
;
155 while (pos
< data_len
) {
156 char ch
= connection
->recv_data_
[pos
++];
157 int input
= charToInput(ch
);
158 int next_state
= parser_state
[state
][input
];
160 bool transition
= (next_state
!= state
);
162 // Do any actions based on state transitions.
165 info
->method
= buffer
;
173 // TODO(mbelshe): Deal better with parsing protocol.
174 DCHECK(buffer
== "HTTP/1.1");
178 header_name
= buffer
;
182 header_value
= buffer
;
183 // TODO(mbelshe): Deal better with duplicate headers
184 DCHECK(info
->headers
.find(header_name
) == info
->headers
.end());
185 info
->headers
[header_name
] = header_value
;
189 buffer
.append(&ch
, 1);
194 // Do any actions based on current state
201 buffer
.append(&ch
, 1);
204 DCHECK(input
== INPUT_LF
);
211 // No more characters, but we haven't finished parsing yet.
215 void HttpServer::DidAccept(ListenSocket
* server
,
216 ListenSocket
* socket
) {
217 HttpConnection
* connection
= new HttpConnection(this, socket
);
218 id_to_connection_
[connection
->id()] = connection
;
219 socket_to_connection_
[socket
] = connection
;
222 void HttpServer::DidRead(ListenSocket
* socket
,
225 HttpConnection
* connection
= FindConnection(socket
);
226 DCHECK(connection
!= NULL
);
227 if (connection
== NULL
)
230 connection
->recv_data_
.append(data
, len
);
231 while (connection
->recv_data_
.length()) {
232 if (connection
->web_socket_
.get()) {
234 WebSocket::ParseResult result
= connection
->web_socket_
->Read(&message
);
235 if (result
== WebSocket::FRAME_INCOMPLETE
)
238 if (result
== WebSocket::FRAME_CLOSE
||
239 result
== WebSocket::FRAME_ERROR
) {
240 Close(connection
->id());
243 delegate_
->OnWebSocketMessage(connection
->id(), message
);
247 HttpServerRequestInfo request
;
249 if (!ParseHeaders(connection
, &request
, &pos
))
252 std::string connection_header
= request
.GetHeaderValue("Connection");
253 if (connection_header
== "Upgrade") {
254 connection
->web_socket_
.reset(WebSocket::CreateWebSocket(connection
,
258 if (!connection
->web_socket_
.get()) // Not enought data was received.
260 delegate_
->OnWebSocketRequest(connection
->id(), request
);
261 connection
->Shift(pos
);
264 // Request body is not supported. It is always empty.
265 delegate_
->OnHttpRequest(connection
->id(), request
);
266 connection
->Shift(pos
);
270 void HttpServer::DidClose(ListenSocket
* socket
) {
271 HttpConnection
* connection
= FindConnection(socket
);
272 DCHECK(connection
!= NULL
);
273 id_to_connection_
.erase(connection
->id());
274 socket_to_connection_
.erase(connection
->socket_
);
278 HttpConnection
* HttpServer::FindConnection(int connection_id
) {
279 IdToConnectionMap::iterator it
= id_to_connection_
.find(connection_id
);
280 if (it
== id_to_connection_
.end())
285 HttpConnection
* HttpServer::FindConnection(ListenSocket
* socket
) {
286 SocketToConnectionMap::iterator it
= socket_to_connection_
.find(socket
);
287 if (it
== socket_to_connection_
.end())
292 void HttpServer::AcceptWebSocket(
294 const HttpServerRequestInfo
& request
) {
295 HttpConnection
* connection
= FindConnection(connection_id
);
296 if (connection
== NULL
)
299 DCHECK(connection
->web_socket_
.get());
300 connection
->web_socket_
->Accept(request
);
303 void HttpServer::SendOverWebSocket(int connection_id
,
304 const std::string
& data
) {
305 HttpConnection
* connection
= FindConnection(connection_id
);
306 if (connection
== NULL
)
308 DCHECK(connection
->web_socket_
.get());
309 connection
->web_socket_
->Send(data
);