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