Speech refactoring: Reimplemented SpeechRecognitionManagerImpl as a FSM. (CL1.7)
[chromium-blink-merge.git] / net / server / http_server.cc
blobad1fa6ee938a9aacc2e8e1e4df25663e15d5b8ae
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"
18 namespace net {
20 HttpServer::HttpServer(const std::string& host,
21 int port,
22 HttpServer::Delegate* del)
23 : 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)
30 delete it->second;
32 server_ = NULL;
35 void HttpServer::Send(int connection_id, const std::string& data) {
36 HttpConnection* connection = FindConnection(connection_id);
37 if (connection == NULL)
38 return;
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)
45 return;
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)
55 return;
56 connection->Send200(data, content_type);
59 void HttpServer::Send404(int connection_id) {
60 HttpConnection* connection = FindConnection(connection_id);
61 if (connection == NULL)
62 return;
63 connection->Send404();
66 void HttpServer::Send500(int connection_id, const std::string& message) {
67 HttpConnection* connection = FindConnection(connection_id);
68 if (connection == NULL)
69 return;
70 connection->Send500(message);
73 void HttpServer::Close(int connection_id)
75 HttpConnection* connection = FindConnection(connection_id);
76 if (connection == NULL)
77 return;
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.
90 // Known issues:
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 {
96 INPUT_SPACE,
97 INPUT_CR,
98 INPUT_LF,
99 INPUT_COLON,
100 INPUT_DEFAULT,
101 MAX_INPUTS,
104 // Parser states.
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.
115 MAX_STATES
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) {
133 switch(ch) {
134 case ' ':
135 return INPUT_SPACE;
136 case '\r':
137 return INPUT_CR;
138 case '\n':
139 return INPUT_LF;
140 case ':':
141 return INPUT_COLON;
143 return INPUT_DEFAULT;
146 bool HttpServer::ParseHeaders(HttpConnection* connection,
147 HttpServerRequestInfo* info,
148 size_t* ppos) {
149 size_t& pos = *ppos;
150 size_t data_len = connection->recv_data_.length();
151 int state = ST_METHOD;
152 std::string buffer;
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);
161 if (transition) {
162 // Do any actions based on state transitions.
163 switch (state) {
164 case ST_METHOD:
165 info->method = buffer;
166 buffer.clear();
167 break;
168 case ST_URL:
169 info->path = buffer;
170 buffer.clear();
171 break;
172 case ST_PROTO:
173 // TODO(mbelshe): Deal better with parsing protocol.
174 DCHECK(buffer == "HTTP/1.1");
175 buffer.clear();
176 break;
177 case ST_NAME:
178 header_name = buffer;
179 buffer.clear();
180 break;
181 case ST_VALUE:
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;
186 buffer.clear();
187 break;
188 case ST_SEPARATOR:
189 buffer.append(&ch, 1);
190 break;
192 state = next_state;
193 } else {
194 // Do any actions based on current state
195 switch (state) {
196 case ST_METHOD:
197 case ST_URL:
198 case ST_PROTO:
199 case ST_VALUE:
200 case ST_NAME:
201 buffer.append(&ch, 1);
202 break;
203 case ST_DONE:
204 DCHECK(input == INPUT_LF);
205 return true;
206 case ST_ERR:
207 return false;
211 // No more characters, but we haven't finished parsing yet.
212 return false;
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,
223 const char* data,
224 int len) {
225 HttpConnection* connection = FindConnection(socket);
226 DCHECK(connection != NULL);
227 if (connection == NULL)
228 return;
230 connection->recv_data_.append(data, len);
231 while (connection->recv_data_.length()) {
232 if (connection->web_socket_.get()) {
233 std::string message;
234 WebSocket::ParseResult result = connection->web_socket_->Read(&message);
235 if (result == WebSocket::FRAME_INCOMPLETE)
236 break;
238 if (result == WebSocket::FRAME_CLOSE ||
239 result == WebSocket::FRAME_ERROR) {
240 Close(connection->id());
241 break;
243 delegate_->OnWebSocketMessage(connection->id(), message);
244 continue;
247 HttpServerRequestInfo request;
248 size_t pos = 0;
249 if (!ParseHeaders(connection, &request, &pos))
250 break;
252 std::string connection_header = request.GetHeaderValue("Connection");
253 if (connection_header == "Upgrade") {
254 connection->web_socket_.reset(WebSocket::CreateWebSocket(connection,
255 request,
256 &pos));
258 if (!connection->web_socket_.get()) // Not enought data was received.
259 break;
260 delegate_->OnWebSocketRequest(connection->id(), request);
261 connection->Shift(pos);
262 continue;
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_);
275 delete connection;
278 HttpConnection* HttpServer::FindConnection(int connection_id) {
279 IdToConnectionMap::iterator it = id_to_connection_.find(connection_id);
280 if (it == id_to_connection_.end())
281 return NULL;
282 return it->second;
285 HttpConnection* HttpServer::FindConnection(ListenSocket* socket) {
286 SocketToConnectionMap::iterator it = socket_to_connection_.find(socket);
287 if (it == socket_to_connection_.end())
288 return NULL;
289 return it->second;
292 void HttpServer::AcceptWebSocket(
293 int connection_id,
294 const HttpServerRequestInfo& request) {
295 HttpConnection* connection = FindConnection(connection_id);
296 if (connection == NULL)
297 return;
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)
307 return;
308 DCHECK(connection->web_socket_.get());
309 connection->web_socket_->Send(data);
312 } // namespace net