Chromium Code Reviews| 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 bool connection_upgrade = false; |
| 146 if (connection_header == "Upgrade") { | 146 { |
|
pfeldman
2014/05/08 13:38:18
There is no need for this.
| |
| 147 std::string connection_header = request.GetHeaderValue("connection"); | |
|
pfeldman
2014/05/08 13:38:18
if (request.HasHeaderValue("connection", "upgrade"
| |
| 148 StringToLowerASCII(&connection_header); | |
| 149 std::vector<std::string> conn_items; | |
| 150 Tokenize(connection_header, ",", &conn_items); | |
| 151 for (std::vector<std::string>::iterator it = conn_items.begin(); | |
| 152 it != conn_items.end(); ++it) { | |
| 153 base::TrimString(*it, " \t", &*it); | |
| 154 if (*it == "upgrade") { | |
| 155 connection_upgrade = true; | |
| 156 break; | |
| 157 } | |
| 158 } | |
| 159 } | |
| 160 if (connection_upgrade) { | |
| 147 connection->web_socket_.reset(WebSocket::CreateWebSocket(connection, | 161 connection->web_socket_.reset(WebSocket::CreateWebSocket(connection, |
| 148 request, | 162 request, |
| 149 &pos)); | 163 &pos)); |
| 150 | 164 |
| 151 if (!connection->web_socket_.get()) // Not enough data was received. | 165 if (!connection->web_socket_.get()) // Not enough data was received. |
| 152 break; | 166 break; |
| 153 delegate_->OnWebSocketRequest(connection->id(), request); | 167 delegate_->OnWebSocketRequest(connection->id(), request); |
| 154 connection->Shift(pos); | 168 connection->Shift(pos); |
| 155 continue; | 169 continue; |
| 156 } | 170 } |
| (...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 | 212 // 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 | 213 // through the headers. The parser is not 100% complete, as it is designed |
| 200 // for use in this simple test driver. | 214 // for use in this simple test driver. |
| 201 // | 215 // |
| 202 // Known issues: | 216 // Known issues: |
| 203 // - does not handle whitespace on first HTTP line correctly. Expects | 217 // - does not handle whitespace on first HTTP line correctly. Expects |
| 204 // a single space between the method/url and url/protocol. | 218 // a single space between the method/url and url/protocol. |
| 205 | 219 |
| 206 // Input character types. | 220 // Input character types. |
| 207 enum header_parse_inputs { | 221 enum header_parse_inputs { |
| 208 INPUT_SPACE, | 222 INPUT_LWS, |
| 209 INPUT_CR, | 223 INPUT_CR, |
| 210 INPUT_LF, | 224 INPUT_LF, |
| 211 INPUT_COLON, | 225 INPUT_COLON, |
| 212 INPUT_DEFAULT, | 226 INPUT_DEFAULT, |
| 213 MAX_INPUTS, | 227 MAX_INPUTS, |
| 214 }; | 228 }; |
| 215 | 229 |
| 216 // Parser states. | 230 // Parser states. |
| 217 enum header_parse_states { | 231 enum header_parse_states { |
| 218 ST_METHOD, // Receiving the method | 232 ST_METHOD, // Receiving the method |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 237 /* SEPARATOR */ { ST_SEPARATOR, ST_ERR, ST_ERR, ST_VALUE, ST_ERR }, | 251 /* SEPARATOR */ { ST_SEPARATOR, ST_ERR, ST_ERR, ST_VALUE, ST_ERR }, |
| 238 /* VALUE */ { ST_VALUE, ST_HEADER, ST_NAME, ST_VALUE, ST_VALUE }, | 252 /* VALUE */ { ST_VALUE, ST_HEADER, ST_NAME, ST_VALUE, ST_VALUE }, |
| 239 /* DONE */ { ST_DONE, ST_DONE, ST_DONE, ST_DONE, ST_DONE }, | 253 /* DONE */ { ST_DONE, ST_DONE, ST_DONE, ST_DONE, ST_DONE }, |
| 240 /* ERR */ { ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_ERR } | 254 /* ERR */ { ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_ERR } |
| 241 }; | 255 }; |
| 242 | 256 |
| 243 // Convert an input character to the parser's input token. | 257 // Convert an input character to the parser's input token. |
| 244 int charToInput(char ch) { | 258 int charToInput(char ch) { |
| 245 switch(ch) { | 259 switch(ch) { |
| 246 case ' ': | 260 case ' ': |
| 247 return INPUT_SPACE; | 261 case '\t': |
| 262 return INPUT_LWS; | |
| 248 case '\r': | 263 case '\r': |
| 249 return INPUT_CR; | 264 return INPUT_CR; |
| 250 case '\n': | 265 case '\n': |
| 251 return INPUT_LF; | 266 return INPUT_LF; |
| 252 case ':': | 267 case ':': |
| 253 return INPUT_COLON; | 268 return INPUT_COLON; |
| 254 } | 269 } |
| 255 return INPUT_DEFAULT; | 270 return INPUT_DEFAULT; |
| 256 } | 271 } |
| 257 | 272 |
| 258 bool HttpServer::ParseHeaders(HttpConnection* connection, | 273 bool HttpServer::ParseHeaders(HttpConnection* connection, |
| 259 HttpServerRequestInfo* info, | 274 HttpServerRequestInfo* info, |
| 260 size_t* ppos) { | 275 size_t* ppos) { |
| 261 size_t& pos = *ppos; | 276 size_t& pos = *ppos; |
| 262 size_t data_len = connection->recv_data_.length(); | 277 size_t data_len = connection->recv_data_.length(); |
| 263 int state = ST_METHOD; | 278 int state = ST_METHOD; |
| 264 std::string buffer; | 279 std::string buffer; |
| 265 std::string header_name; | 280 std::string header_name; |
| 266 std::string header_value; | 281 std::string header_value; |
| 267 while (pos < data_len) { | 282 while (pos < data_len) { |
| 268 char ch = connection->recv_data_[pos++]; | 283 char ch = connection->recv_data_[pos++]; |
| 269 int input = charToInput(ch); | 284 int input = charToInput(ch); |
| 270 int next_state = parser_state[state][input]; | 285 int next_state = parser_state[state][input]; |
| 271 | 286 |
| 272 bool transition = (next_state != state); | 287 bool transition = (next_state != state); |
| 288 HttpServerRequestInfo::HeadersMap::iterator it; | |
| 273 if (transition) { | 289 if (transition) { |
| 274 // Do any actions based on state transitions. | 290 // Do any actions based on state transitions. |
| 275 switch (state) { | 291 switch (state) { |
| 276 case ST_METHOD: | 292 case ST_METHOD: |
| 277 info->method = buffer; | 293 info->method = buffer; |
| 278 buffer.clear(); | 294 buffer.clear(); |
| 279 break; | 295 break; |
| 280 case ST_URL: | 296 case ST_URL: |
| 281 info->path = buffer; | 297 info->path = buffer; |
| 282 buffer.clear(); | 298 buffer.clear(); |
| 283 break; | 299 break; |
| 284 case ST_PROTO: | 300 case ST_PROTO: |
| 285 // TODO(mbelshe): Deal better with parsing protocol. | 301 // TODO(mbelshe): Deal better with parsing protocol. |
| 286 DCHECK(buffer == "HTTP/1.1"); | 302 DCHECK(buffer == "HTTP/1.1"); |
| 287 buffer.clear(); | 303 buffer.clear(); |
| 288 break; | 304 break; |
| 289 case ST_NAME: | 305 case ST_NAME: |
| 290 header_name = StringToLowerASCII(buffer); | 306 header_name = StringToLowerASCII(buffer); |
| 291 buffer.clear(); | 307 buffer.clear(); |
| 292 break; | 308 break; |
| 293 case ST_VALUE: | 309 case ST_VALUE: |
| 294 base::TrimWhitespaceASCII(buffer, base::TRIM_LEADING, &header_value); | 310 base::TrimWhitespaceASCII(buffer, base::TRIM_LEADING, &header_value); |
| 295 // TODO(mbelshe): Deal better with duplicate headers | 311 it = info->headers.find(header_name); |
| 296 DCHECK(info->headers.find(header_name) == info->headers.end()); | 312 // See last paragraph ("Multiple message-header fields...") |
| 297 info->headers[header_name] = header_value; | 313 // of www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 |
| 314 if (it == info->headers.end()) { | |
| 315 info->headers[header_name] = header_value; | |
| 316 } else { | |
| 317 it->second.append(","); | |
| 318 it->second.append(header_value); | |
| 319 } | |
| 298 buffer.clear(); | 320 buffer.clear(); |
| 299 break; | 321 break; |
| 300 case ST_SEPARATOR: | 322 case ST_SEPARATOR: |
| 301 break; | 323 break; |
| 302 } | 324 } |
| 303 state = next_state; | 325 state = next_state; |
| 304 } else { | 326 } else { |
| 305 // Do any actions based on current state | 327 // Do any actions based on current state |
| 306 switch (state) { | 328 switch (state) { |
| 307 case ST_METHOD: | 329 case ST_METHOD: |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 331 } | 353 } |
| 332 | 354 |
| 333 HttpConnection* HttpServer::FindConnection(StreamListenSocket* socket) { | 355 HttpConnection* HttpServer::FindConnection(StreamListenSocket* socket) { |
| 334 SocketToConnectionMap::iterator it = socket_to_connection_.find(socket); | 356 SocketToConnectionMap::iterator it = socket_to_connection_.find(socket); |
| 335 if (it == socket_to_connection_.end()) | 357 if (it == socket_to_connection_.end()) |
| 336 return NULL; | 358 return NULL; |
| 337 return it->second; | 359 return it->second; |
| 338 } | 360 } |
| 339 | 361 |
| 340 } // namespace net | 362 } // namespace net |
| OLD | NEW |