OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/server/http_server.h" | 5 #include "net/server/http_server.h" |
6 | 6 |
7 #include "base/compiler_specific.h" | 7 #include "base/compiler_specific.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
10 #include "base/strings/string_number_conversions.h" | 10 #include "base/strings/string_number_conversions.h" |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
135 } | 135 } |
136 | 136 |
137 HttpServerRequestInfo request; | 137 HttpServerRequestInfo request; |
138 size_t pos = 0; | 138 size_t pos = 0; |
139 if (!ParseHeaders(connection, &request, &pos)) | 139 if (!ParseHeaders(connection, &request, &pos)) |
140 break; | 140 break; |
141 | 141 |
142 // Sets peer address if exists. | 142 // Sets peer address if exists. |
143 socket->GetPeerAddress(&request.peer); | 143 socket->GetPeerAddress(&request.peer); |
144 | 144 |
145 std::string connection_header = request.GetHeaderValue("connection"); | 145 if (request.HasHeaderValue("connection", "upgrade")) { |
146 if (connection_header == "Upgrade") { | |
147 connection->web_socket_.reset(WebSocket::CreateWebSocket(connection, | 146 connection->web_socket_.reset(WebSocket::CreateWebSocket(connection, |
148 request, | 147 request, |
149 &pos)); | 148 &pos)); |
150 | 149 |
151 if (!connection->web_socket_.get()) // Not enough data was received. | 150 if (!connection->web_socket_.get()) // Not enough data was received. |
152 break; | 151 break; |
153 delegate_->OnWebSocketRequest(connection->id(), request); | 152 delegate_->OnWebSocketRequest(connection->id(), request); |
154 connection->Shift(pos); | 153 connection->Shift(pos); |
155 continue; | 154 continue; |
156 } | 155 } |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
198 // This HTTP request parser uses a simple state machine to quickly parse | 197 // This HTTP request parser uses a simple state machine to quickly parse |
199 // through the headers. The parser is not 100% complete, as it is designed | 198 // through the headers. The parser is not 100% complete, as it is designed |
200 // for use in this simple test driver. | 199 // for use in this simple test driver. |
201 // | 200 // |
202 // Known issues: | 201 // Known issues: |
203 // - does not handle whitespace on first HTTP line correctly. Expects | 202 // - does not handle whitespace on first HTTP line correctly. Expects |
204 // a single space between the method/url and url/protocol. | 203 // a single space between the method/url and url/protocol. |
205 | 204 |
206 // Input character types. | 205 // Input character types. |
207 enum header_parse_inputs { | 206 enum header_parse_inputs { |
208 INPUT_SPACE, | 207 INPUT_LWS, |
209 INPUT_CR, | 208 INPUT_CR, |
210 INPUT_LF, | 209 INPUT_LF, |
211 INPUT_COLON, | 210 INPUT_COLON, |
212 INPUT_DEFAULT, | 211 INPUT_DEFAULT, |
213 MAX_INPUTS, | 212 MAX_INPUTS, |
214 }; | 213 }; |
215 | 214 |
216 // Parser states. | 215 // Parser states. |
217 enum header_parse_states { | 216 enum header_parse_states { |
218 ST_METHOD, // Receiving the method | 217 ST_METHOD, // Receiving the method |
(...skipping 18 matching lines...) Expand all Loading... |
237 /* SEPARATOR */ { ST_SEPARATOR, ST_ERR, ST_ERR, ST_VALUE, ST_ERR }, | 236 /* SEPARATOR */ { ST_SEPARATOR, ST_ERR, ST_ERR, ST_VALUE, ST_ERR }, |
238 /* VALUE */ { ST_VALUE, ST_HEADER, ST_NAME, ST_VALUE, ST_VALUE }, | 237 /* VALUE */ { ST_VALUE, ST_HEADER, ST_NAME, ST_VALUE, ST_VALUE }, |
239 /* DONE */ { ST_DONE, ST_DONE, ST_DONE, ST_DONE, ST_DONE }, | 238 /* DONE */ { ST_DONE, ST_DONE, ST_DONE, ST_DONE, ST_DONE }, |
240 /* ERR */ { ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_ERR } | 239 /* ERR */ { ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_ERR } |
241 }; | 240 }; |
242 | 241 |
243 // Convert an input character to the parser's input token. | 242 // Convert an input character to the parser's input token. |
244 int charToInput(char ch) { | 243 int charToInput(char ch) { |
245 switch(ch) { | 244 switch(ch) { |
246 case ' ': | 245 case ' ': |
247 return INPUT_SPACE; | 246 case '\t': |
| 247 return INPUT_LWS; |
248 case '\r': | 248 case '\r': |
249 return INPUT_CR; | 249 return INPUT_CR; |
250 case '\n': | 250 case '\n': |
251 return INPUT_LF; | 251 return INPUT_LF; |
252 case ':': | 252 case ':': |
253 return INPUT_COLON; | 253 return INPUT_COLON; |
254 } | 254 } |
255 return INPUT_DEFAULT; | 255 return INPUT_DEFAULT; |
256 } | 256 } |
257 | 257 |
258 bool HttpServer::ParseHeaders(HttpConnection* connection, | 258 bool HttpServer::ParseHeaders(HttpConnection* connection, |
259 HttpServerRequestInfo* info, | 259 HttpServerRequestInfo* info, |
260 size_t* ppos) { | 260 size_t* ppos) { |
261 size_t& pos = *ppos; | 261 size_t& pos = *ppos; |
262 size_t data_len = connection->recv_data_.length(); | 262 size_t data_len = connection->recv_data_.length(); |
263 int state = ST_METHOD; | 263 int state = ST_METHOD; |
264 std::string buffer; | 264 std::string buffer; |
265 std::string header_name; | 265 std::string header_name; |
266 std::string header_value; | 266 std::string header_value; |
267 while (pos < data_len) { | 267 while (pos < data_len) { |
268 char ch = connection->recv_data_[pos++]; | 268 char ch = connection->recv_data_[pos++]; |
269 int input = charToInput(ch); | 269 int input = charToInput(ch); |
270 int next_state = parser_state[state][input]; | 270 int next_state = parser_state[state][input]; |
271 | 271 |
272 bool transition = (next_state != state); | 272 bool transition = (next_state != state); |
| 273 HttpServerRequestInfo::HeadersMap::iterator it; |
273 if (transition) { | 274 if (transition) { |
274 // Do any actions based on state transitions. | 275 // Do any actions based on state transitions. |
275 switch (state) { | 276 switch (state) { |
276 case ST_METHOD: | 277 case ST_METHOD: |
277 info->method = buffer; | 278 info->method = buffer; |
278 buffer.clear(); | 279 buffer.clear(); |
279 break; | 280 break; |
280 case ST_URL: | 281 case ST_URL: |
281 info->path = buffer; | 282 info->path = buffer; |
282 buffer.clear(); | 283 buffer.clear(); |
283 break; | 284 break; |
284 case ST_PROTO: | 285 case ST_PROTO: |
285 // TODO(mbelshe): Deal better with parsing protocol. | 286 // TODO(mbelshe): Deal better with parsing protocol. |
286 DCHECK(buffer == "HTTP/1.1"); | 287 DCHECK(buffer == "HTTP/1.1"); |
287 buffer.clear(); | 288 buffer.clear(); |
288 break; | 289 break; |
289 case ST_NAME: | 290 case ST_NAME: |
290 header_name = StringToLowerASCII(buffer); | 291 header_name = StringToLowerASCII(buffer); |
291 buffer.clear(); | 292 buffer.clear(); |
292 break; | 293 break; |
293 case ST_VALUE: | 294 case ST_VALUE: |
294 base::TrimWhitespaceASCII(buffer, base::TRIM_LEADING, &header_value); | 295 base::TrimWhitespaceASCII(buffer, base::TRIM_LEADING, &header_value); |
295 // TODO(mbelshe): Deal better with duplicate headers | 296 it = info->headers.find(header_name); |
296 DCHECK(info->headers.find(header_name) == info->headers.end()); | 297 // See last paragraph ("Multiple message-header fields...") |
297 info->headers[header_name] = header_value; | 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; |
| 301 } else { |
| 302 it->second.append(","); |
| 303 it->second.append(header_value); |
| 304 } |
298 buffer.clear(); | 305 buffer.clear(); |
299 break; | 306 break; |
300 case ST_SEPARATOR: | 307 case ST_SEPARATOR: |
301 break; | 308 break; |
302 } | 309 } |
303 state = next_state; | 310 state = next_state; |
304 } else { | 311 } else { |
305 // Do any actions based on current state | 312 // Do any actions based on current state |
306 switch (state) { | 313 switch (state) { |
307 case ST_METHOD: | 314 case ST_METHOD: |
(...skipping 23 matching lines...) Expand all Loading... |
331 } | 338 } |
332 | 339 |
333 HttpConnection* HttpServer::FindConnection(StreamListenSocket* socket) { | 340 HttpConnection* HttpServer::FindConnection(StreamListenSocket* socket) { |
334 SocketToConnectionMap::iterator it = socket_to_connection_.find(socket); | 341 SocketToConnectionMap::iterator it = socket_to_connection_.find(socket); |
335 if (it == socket_to_connection_.end()) | 342 if (it == socket_to_connection_.end()) |
336 return NULL; | 343 return NULL; |
337 return it->second; | 344 return it->second; |
338 } | 345 } |
339 | 346 |
340 } // namespace net | 347 } // namespace net |
OLD | NEW |