1 // Copyright (c) 2011 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. 4 5 #include "net/server/http_server.h" 6 7 #include "base/compiler_specific.h" 8 #include "base/logging.h" 9 #include "base/md5.h" 10 #include "base/string_number_conversions.h" 11 #include "base/string_util.h" 12 #include "base/stringprintf.h" 13 #include "build/build_config.h" 14 #include "net/server/http_server_request_info.h" 15 16 #if defined(OS_WIN) 17 #include <winsock2.h> 18 #else 19 #include <arpa/inet.h> 20 #endif 21 22 namespace net { 23 24 int HttpServer::Connection::lastId_ = 0; 25 26 HttpServer::HttpServer(const std::string& host, 27 int port, 28 HttpServer::Delegate* del) 29 : delegate_(del) { 30 server_ = ListenSocket::Listen(host, port, this); 31 } 32 33 HttpServer::~HttpServer() { 34 IdToConnectionMap copy = id_to_connection_; 35 for (IdToConnectionMap::iterator it = copy.begin(); it != copy.end(); ++it) 36 delete it->second; 37 38 server_ = NULL; 39 } 40 41 std::string GetHeaderValue( 42 const HttpServerRequestInfo& request, 43 const std::string& header_name) { 44 HttpServerRequestInfo::HeadersMap::iterator it = 45 request.headers.find(header_name); 46 if (it != request.headers.end()) 47 return it->second; 48 return ""; 49 } 50 51 uint32 WebSocketKeyFingerprint(const std::string& str) { 52 std::string result; 53 const char* pChar = str.c_str(); 54 int length = str.length(); 55 int spaces = 0; 56 for (int i = 0; i < length; ++i) { 57 if (pChar[i] >= '0' && pChar[i] <= '9') 58 result.append(&pChar[i], 1); 59 else if (pChar[i] == ' ') 60 spaces++; 61 } 62 if (spaces == 0) 63 return 0; 64 int64 number = 0; 65 if (!base::StringToInt64(result, &number)) 66 return 0; 67 return htonl(static_cast<uint32>(number / spaces)); 68 } 69 70 void HttpServer::AcceptWebSocket( 71 int connection_id, 72 const HttpServerRequestInfo& request) { 73 Connection* connection = FindConnection(connection_id); 74 if (connection == NULL) 75 return; 76 77 std::string key1 = GetHeaderValue(request, "Sec-WebSocket-Key1"); 78 std::string key2 = GetHeaderValue(request, "Sec-WebSocket-Key2"); 79 80 uint32 fp1 = WebSocketKeyFingerprint(key1); 81 uint32 fp2 = WebSocketKeyFingerprint(key2); 82 83 char data[16]; 84 memcpy(data, &fp1, 4); 85 memcpy(data + 4, &fp2, 4); 86 memcpy(data + 8, &request.data[0], 8); 87 88 MD5Digest digest; 89 MD5Sum(data, 16, &digest); 90 91 std::string origin = GetHeaderValue(request, "Origin"); 92 std::string host = GetHeaderValue(request, "Host"); 93 std::string location = "ws://" + host + request.path; 94 connection->is_web_socket_ = true; 95 connection->socket_->Send(base::StringPrintf( 96 "HTTP/1.1 101 WebSocket Protocol Handshake\r\n" 97 "Upgrade: WebSocket\r\n" 98 "Connection: Upgrade\r\n" 99 "Sec-WebSocket-Origin: %s\r\n" 100 "Sec-WebSocket-Location: %s\r\n" 101 "\r\n", 102 origin.c_str(), 103 location.c_str())); 104 connection->socket_->Send(reinterpret_cast<char*>(digest.a), 16); 105 } 106 107 void HttpServer::SendOverWebSocket(int connection_id, 108 const std::string& data) { 109 Connection* connection = FindConnection(connection_id); 110 if (connection == NULL) 111 return; 112 113 DCHECK(connection->is_web_socket_); 114 char message_start = 0; 115 char message_end = -1; 116 connection->socket_->Send(&message_start, 1); 117 connection->socket_->Send(data); 118 connection->socket_->Send(&message_end, 1); 119 } 120 121 void HttpServer::Send(int connection_id, const std::string& data) { 122 Connection* connection = FindConnection(connection_id); 123 if (connection == NULL) 124 return; 125 126 connection->socket_->Send(data); 127 } 128 129 void HttpServer::Send(int connection_id, const char* bytes, int len) { 130 Connection* connection = FindConnection(connection_id); 131 if (connection == NULL) 132 return; 133 134 connection->socket_->Send(bytes, len); 135 } 136 137 void HttpServer::Send200(int connection_id, 138 const std::string& data, 139 const std::string& content_type) { 140 Connection* connection = FindConnection(connection_id); 141 if (connection == NULL) 142 return; 143 144 connection->socket_->Send(base::StringPrintf( 145 "HTTP/1.1 200 OK\r\n" 146 "Content-Type:%s\r\n" 147 "Content-Length:%d\r\n" 148 "\r\n", 149 content_type.c_str(), 150 static_cast<int>(data.length()))); 151 connection->socket_->Send(data); 152 } 153 154 void HttpServer::Send404(int connection_id) { 155 Connection* connection = FindConnection(connection_id); 156 if (connection == NULL) 157 return; 158 159 connection->socket_->Send( 160 "HTTP/1.1 404 Not Found\r\n" 161 "Content-Length: 0\r\n" 162 "\r\n"); 163 } 164 165 void HttpServer::Send500(int connection_id, const std::string& message) { 166 Connection* connection = FindConnection(connection_id); 167 if (connection == NULL) 168 return; 169 170 connection->socket_->Send(base::StringPrintf( 171 "HTTP/1.1 500 Internal Error\r\n" 172 "Content-Type:text/html\r\n" 173 "Content-Length:%d\r\n" 174 "\r\n" 175 "%s", 176 static_cast<int>(message.length()), 177 message.c_str())); 178 } 179 180 void HttpServer::Close(int connection_id) 181 { 182 Connection* connection = FindConnection(connection_id); 183 if (connection == NULL) 184 return; 185 186 connection->DetachSocket(); 187 } 188 189 HttpServer::Connection::Connection(HttpServer* server, ListenSocket* sock) 190 : server_(server), 191 socket_(sock), 192 is_web_socket_(false) { 193 id_ = lastId_++; 194 } 195 196 HttpServer::Connection::~Connection() { 197 DetachSocket(); 198 server_->delegate_->OnClose(id_); 199 } 200 201 void HttpServer::Connection::DetachSocket() { 202 socket_ = NULL; 203 } 204 205 void HttpServer::Connection::Shift(int num_bytes) { 206 recv_data_ = recv_data_.substr(num_bytes); 207 } 208 209 // 210 // HTTP Request Parser 211 // This HTTP request parser uses a simple state machine to quickly parse 212 // through the headers. The parser is not 100% complete, as it is designed 213 // for use in this simple test driver. 214 // 215 // Known issues: 216 // - does not handle whitespace on first HTTP line correctly. Expects 217 // a single space between the method/url and url/protocol. 218 219 // Input character types. 220 enum header_parse_inputs { 221 INPUT_SPACE, 222 INPUT_CR, 223 INPUT_LF, 224 INPUT_COLON, 225 INPUT_00, 226 INPUT_FF, 227 INPUT_DEFAULT, 228 MAX_INPUTS, 229 }; 230 231 // Parser states. 232 enum header_parse_states { 233 ST_METHOD, // Receiving the method 234 ST_URL, // Receiving the URL 235 ST_PROTO, // Receiving the protocol 236 ST_HEADER, // Starting a Request Header 237 ST_NAME, // Receiving a request header name 238 ST_SEPARATOR, // Receiving the separator between header name and value 239 ST_VALUE, // Receiving a request header value 240 ST_WS_READY, // Ready to receive web socket frame 241 ST_WS_FRAME, // Receiving WebSocket frame 242 ST_WS_CLOSE, // Closing the connection WebSocket connection 243 ST_DONE, // Parsing is complete and successful 244 ST_ERR, // Parsing encountered invalid syntax. 245 MAX_STATES 246 }; 247 248 // State transition table 249 int parser_state[MAX_STATES][MAX_INPUTS] = { 250 /* METHOD */ { ST_URL, ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_METHOD }, 251 /* URL */ { ST_PROTO, ST_ERR, ST_ERR, ST_URL, ST_ERR, ST_ERR, ST_URL }, 252 /* PROTOCOL */ { ST_ERR, ST_HEADER, ST_NAME, ST_ERR, ST_ERR, ST_ERR, ST_PROTO }, 253 /* HEADER */ { ST_ERR, ST_ERR, ST_NAME, ST_ERR, ST_ERR, ST_ERR, ST_ERR }, 254 /* NAME */ { ST_SEPARATOR, ST_DONE, ST_ERR, ST_SEPARATOR, ST_ERR, ST_ERR, ST_NAME }, 255 /* SEPARATOR */ { ST_SEPARATOR, ST_ERR, ST_ERR, ST_SEPARATOR, ST_ERR, ST_ERR, ST_VALUE }, 256 /* VALUE */ { ST_VALUE, ST_HEADER, ST_NAME, ST_VALUE, ST_ERR, ST_ERR, ST_VALUE }, 257 /* WS_READY */ { ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_WS_FRAME, ST_WS_CLOSE, ST_ERR}, 258 /* WS_FRAME */ { ST_WS_FRAME, ST_WS_FRAME, ST_WS_FRAME, ST_WS_FRAME, ST_ERR, ST_WS_READY, ST_WS_FRAME }, 259 /* WS_CLOSE */ { ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_WS_CLOSE, ST_ERR, ST_ERR }, 260 /* DONE */ { ST_DONE, ST_DONE, ST_DONE, ST_DONE, ST_DONE, ST_DONE, ST_DONE }, 261 /* ERR */ { ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_ERR, ST_ERR } 262 }; 263 264 // Convert an input character to the parser's input token. 265 int charToInput(char ch) { 266 switch(ch) { 267 case ' ': 268 return INPUT_SPACE; 269 case '\r': 270 return INPUT_CR; 271 case '\n': 272 return INPUT_LF; 273 case ':': 274 return INPUT_COLON; 275 case 0x0: 276 return INPUT_00; 277 case static_cast<char>(-1): 278 return INPUT_FF; 279 } 280 return INPUT_DEFAULT; 281 } 282 283 bool HttpServer::ParseHeaders(Connection* connection, 284 HttpServerRequestInfo* info, 285 int* ppos) { 286 int& pos = *ppos; 287 int data_len = connection->recv_data_.length(); 288 int state = connection->is_web_socket_ ? ST_WS_READY : ST_METHOD; 289 std::string buffer; 290 std::string header_name; 291 std::string header_value; 292 while (pos < data_len) { 293 char ch = connection->recv_data_[pos++]; 294 int input = charToInput(ch); 295 int next_state = parser_state[state][input]; 296 297 bool transition = (next_state != state); 298 if (transition) { 299 // Do any actions based on state transitions. 300 switch (state) { 301 case ST_METHOD: 302 info->method = buffer; 303 buffer.clear(); 304 break; 305 case ST_URL: 306 info->path = buffer; 307 buffer.clear(); 308 break; 309 case ST_PROTO: 310 // TODO(mbelshe): Deal better with parsing protocol. 311 DCHECK(buffer == "HTTP/1.1"); 312 buffer.clear(); 313 break; 314 case ST_NAME: 315 header_name = buffer; 316 buffer.clear(); 317 break; 318 case ST_VALUE: 319 header_value = buffer; 320 // TODO(mbelshe): Deal better with duplicate headers 321 DCHECK(info->headers.find(header_name) == info->headers.end()); 322 info->headers[header_name] = header_value; 323 buffer.clear(); 324 break; 325 case ST_SEPARATOR: 326 buffer.append(&ch, 1); 327 break; 328 case ST_WS_FRAME: 329 info->data = buffer; 330 buffer.clear(); 331 return true; 332 break; 333 } 334 state = next_state; 335 } else { 336 // Do any actions based on current state 337 switch (state) { 338 case ST_METHOD: 339 case ST_URL: 340 case ST_PROTO: 341 case ST_VALUE: 342 case ST_NAME: 343 case ST_WS_FRAME: 344 buffer.append(&ch, 1); 345 break; 346 case ST_DONE: 347 DCHECK(input == INPUT_LF); 348 return true; 349 case ST_WS_CLOSE: 350 connection->is_web_socket_ = false; 351 return false; 352 case ST_ERR: 353 return false; 354 } 355 } 356 } 357 // No more characters, but we haven't finished parsing yet. 358 return false; 359 } 360 361 void HttpServer::DidAccept(ListenSocket* server, 362 ListenSocket* socket) { 363 Connection* connection = new Connection(this, socket); 364 id_to_connection_[connection->id_] = connection; 365 socket_to_connection_[socket] = connection; 366 } 367 368 void HttpServer::DidRead(ListenSocket* socket, 369 const char* data, 370 int len) { 371 Connection* connection = FindConnection(socket); 372 DCHECK(connection != NULL); 373 if (connection == NULL) 374 return; 375 376 connection->recv_data_.append(data, len); 377 while (connection->recv_data_.length()) { 378 int pos = 0; 379 HttpServerRequestInfo request; 380 if (!ParseHeaders(connection, &request, &pos)) 381 break; 382 383 if (connection->is_web_socket_) { 384 delegate_->OnWebSocketMessage(connection->id_, request.data); 385 connection->Shift(pos); 386 continue; 387 } 388 389 std::string connection_header = GetHeaderValue(request, "Connection"); 390 if (connection_header == "Upgrade") { 391 // Is this WebSocket and if yes, upgrade the connection. 392 std::string key1 = GetHeaderValue(request, "Sec-WebSocket-Key1"); 393 std::string key2 = GetHeaderValue(request, "Sec-WebSocket-Key2"); 394 395 const int websocket_handshake_body_len = 8; 396 if (pos + websocket_handshake_body_len > 397 static_cast<int>(connection->recv_data_.length())) { 398 // We haven't received websocket handshake body yet. Wait. 399 break; 400 } 401 402 if (!key1.empty() && !key2.empty()) { 403 request.data = connection->recv_data_.substr( 404 pos, 405 pos + websocket_handshake_body_len); 406 pos += websocket_handshake_body_len; 407 delegate_->OnWebSocketRequest(connection->id_, request); 408 connection->Shift(pos); 409 continue; 410 } 411 } 412 // Request body is not supported. It is always empty. 413 delegate_->OnHttpRequest(connection->id_, request); 414 connection->Shift(pos); 415 } 416 } 417 418 void HttpServer::DidClose(ListenSocket* socket) { 419 Connection* connection = FindConnection(socket); 420 DCHECK(connection != NULL); 421 id_to_connection_.erase(connection->id_); 422 socket_to_connection_.erase(connection->socket_); 423 delete connection; 424 } 425 426 HttpServer::Connection* HttpServer::FindConnection(int connection_id) { 427 IdToConnectionMap::iterator it = id_to_connection_.find(connection_id); 428 if (it == id_to_connection_.end()) 429 return NULL; 430 return it->second; 431 } 432 433 HttpServer::Connection* HttpServer::FindConnection(ListenSocket* socket) { 434 SocketToConnectionMap::iterator it = socket_to_connection_.find(socket); 435 if (it == socket_to_connection_.end()) 436 return NULL; 437 return it->second; 438 } 439 440 } // namespace net 441