| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 #ifdef _WIN32 | 5 #ifdef _WIN32 |
| 6 #include <winsock2.h> | 6 #include <winsock2.h> |
| 7 #else | 7 #else |
| 8 #include <arpa/inet.h> | 8 #include <arpa/inet.h> |
| 9 #endif | 9 #endif |
| 10 | 10 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 51 // TODO (ibrar): error handling | 51 // TODO (ibrar): error handling |
| 52 } else { | 52 } else { |
| 53 HttpListenSocket *serv = new HttpListenSocket(s, delegate); | 53 HttpListenSocket *serv = new HttpListenSocket(s, delegate); |
| 54 serv->Listen(); | 54 serv->Listen(); |
| 55 return serv; | 55 return serv; |
| 56 } | 56 } |
| 57 return NULL; | 57 return NULL; |
| 58 } | 58 } |
| 59 | 59 |
| 60 std::string GetHeaderValue( | 60 std::string GetHeaderValue( |
| 61 HttpServerRequestInfo* request, | 61 const HttpServerRequestInfo& request, |
| 62 const std::string& header_name) { | 62 const std::string& header_name) { |
| 63 HttpServerRequestInfo::HeadersMap::iterator it = | 63 HttpServerRequestInfo::HeadersMap::iterator it = |
| 64 request->headers.find(header_name); | 64 request.headers.find(header_name); |
| 65 if (it != request->headers.end()) | 65 if (it != request.headers.end()) |
| 66 return it->second; | 66 return it->second; |
| 67 return ""; | 67 return ""; |
| 68 } | 68 } |
| 69 | 69 |
| 70 uint32 WebSocketKeyFingerprint(const std::string& str) { | 70 uint32 WebSocketKeyFingerprint(const std::string& str) { |
| 71 std::string result; | 71 std::string result; |
| 72 const char* pChar = str.c_str(); | 72 const char* pChar = str.c_str(); |
| 73 int length = str.length(); | 73 int length = str.length(); |
| 74 int spaces = 0; | 74 int spaces = 0; |
| 75 for (int i = 0; i < length; ++i) { | 75 for (int i = 0; i < length; ++i) { |
| 76 if (pChar[i] >= '0' && pChar[i] <= '9') | 76 if (pChar[i] >= '0' && pChar[i] <= '9') |
| 77 result.append(&pChar[i], 1); | 77 result.append(&pChar[i], 1); |
| 78 else if (pChar[i] == ' ') | 78 else if (pChar[i] == ' ') |
| 79 spaces++; | 79 spaces++; |
| 80 } | 80 } |
| 81 if (spaces == 0) | 81 if (spaces == 0) |
| 82 return 0; | 82 return 0; |
| 83 int64 number = 0; | 83 int64 number = 0; |
| 84 if (!StringToInt64(result, &number)) | 84 if (!StringToInt64(result, &number)) |
| 85 return 0; | 85 return 0; |
| 86 return htonl(static_cast<uint32>(number / spaces)); | 86 return htonl(static_cast<uint32>(number / spaces)); |
| 87 } | 87 } |
| 88 | 88 |
| 89 void HttpListenSocket::AcceptWebSocket(HttpServerRequestInfo* request) { | 89 void HttpListenSocket::AcceptWebSocket(const HttpServerRequestInfo& request) { |
| 90 std::string key1 = GetHeaderValue(request, "Sec-WebSocket-Key1"); | 90 std::string key1 = GetHeaderValue(request, "Sec-WebSocket-Key1"); |
| 91 std::string key2 = GetHeaderValue(request, "Sec-WebSocket-Key2"); | 91 std::string key2 = GetHeaderValue(request, "Sec-WebSocket-Key2"); |
| 92 | 92 |
| 93 uint32 fp1 = WebSocketKeyFingerprint(key1); | 93 uint32 fp1 = WebSocketKeyFingerprint(key1); |
| 94 uint32 fp2 = WebSocketKeyFingerprint(key2); | 94 uint32 fp2 = WebSocketKeyFingerprint(key2); |
| 95 | 95 |
| 96 char data[16]; | 96 char data[16]; |
| 97 memcpy(data, &fp1, 4); | 97 memcpy(data, &fp1, 4); |
| 98 memcpy(data + 4, &fp2, 4); | 98 memcpy(data + 4, &fp2, 4); |
| 99 memcpy(data + 8, &request->data[0], 8); | 99 memcpy(data + 8, &request.data[0], 8); |
| 100 | 100 |
| 101 MD5Digest digest; | 101 MD5Digest digest; |
| 102 MD5Sum(data, 16, &digest); | 102 MD5Sum(data, 16, &digest); |
| 103 | 103 |
| 104 std::string origin = GetHeaderValue(request, "Origin"); | 104 std::string origin = GetHeaderValue(request, "Origin"); |
| 105 std::string host = GetHeaderValue(request, "Host"); | 105 std::string host = GetHeaderValue(request, "Host"); |
| 106 std::string location = "ws://" + host + request->path; | 106 std::string location = "ws://" + host + request.path; |
| 107 is_web_socket_ = true; | 107 is_web_socket_ = true; |
| 108 Send(StringPrintf("HTTP/1.1 101 WebSocket Protocol Handshake\r\n" | 108 Send(StringPrintf("HTTP/1.1 101 WebSocket Protocol Handshake\r\n" |
| 109 "Upgrade: WebSocket\r\n" | 109 "Upgrade: WebSocket\r\n" |
| 110 "Connection: Upgrade\r\n" | 110 "Connection: Upgrade\r\n" |
| 111 "Sec-WebSocket-Origin: %s\r\n" | 111 "Sec-WebSocket-Origin: %s\r\n" |
| 112 "Sec-WebSocket-Location: %s\r\n" | 112 "Sec-WebSocket-Location: %s\r\n" |
| 113 "\r\n", | 113 "\r\n", |
| 114 origin.c_str(), | 114 origin.c_str(), |
| 115 location.c_str())); | 115 location.c_str())); |
| 116 Send(reinterpret_cast<char*>(digest.a), 16); | 116 Send(reinterpret_cast<char*>(digest.a), 16); |
| 117 } | 117 } |
| 118 | 118 |
| 119 void HttpListenSocket::SendOverWebSocket(const std::string& data) { | 119 void HttpListenSocket::SendOverWebSocket(const std::string& data) { |
| 120 DCHECK(is_web_socket_); | 120 DCHECK(is_web_socket_); |
| 121 char message_start = 0; | 121 char message_start = 0; |
| 122 char message_end = -1; | 122 char message_end = -1; |
| 123 Send(&message_start, 1); | 123 Send(&message_start, 1); |
| 124 Send(data); | 124 Send(data); |
| 125 Send(&message_end, 1); | 125 Send(&message_end, 1); |
| 126 } | 126 } |
| 127 | 127 |
| 128 void HttpListenSocket::Send200(const std::string& data, |
| 129 const std::string& content_type) { |
| 130 Send(StringPrintf("HTTP/1.1 200 OK\r\n" |
| 131 "Content-Type:%s\r\n" |
| 132 "Content-Length:%d\r\n" |
| 133 "\r\n", |
| 134 content_type.c_str(), |
| 135 data.length())); |
| 136 Send(data); |
| 137 } |
| 138 |
| 139 void HttpListenSocket::Send404() { |
| 140 Send("HTTP/1.1 404 Not Found\r\n" |
| 141 "Content-Length: 0\r\n" |
| 142 "\r\n"); |
| 143 } |
| 144 |
| 145 void HttpListenSocket::Send500(const std::string& message) { |
| 146 Send(StringPrintf("HTTP/1.1 500 Internal Error\r\n" |
| 147 "Content-Type:text/html\r\n" |
| 148 "Content-Length:%d\r\n" |
| 149 "\r\n" |
| 150 "%s", |
| 151 message.length(), |
| 152 message.c_str())); |
| 153 } |
| 154 |
| 128 // | 155 // |
| 129 // HTTP Request Parser | 156 // HTTP Request Parser |
| 130 // This HTTP request parser uses a simple state machine to quickly parse | 157 // This HTTP request parser uses a simple state machine to quickly parse |
| 131 // through the headers. The parser is not 100% complete, as it is designed | 158 // through the headers. The parser is not 100% complete, as it is designed |
| 132 // for use in this simple test driver. | 159 // for use in this simple test driver. |
| 133 // | 160 // |
| 134 // Known issues: | 161 // Known issues: |
| 135 // - does not handle whitespace on first HTTP line correctly. Expects | 162 // - does not handle whitespace on first HTTP line correctly. Expects |
| 136 // a single space between the method/url and url/protocol. | 163 // a single space between the method/url and url/protocol. |
| 137 | 164 |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 192 case ':': | 219 case ':': |
| 193 return INPUT_COLON; | 220 return INPUT_COLON; |
| 194 case 0x0: | 221 case 0x0: |
| 195 return INPUT_00; | 222 return INPUT_00; |
| 196 case static_cast<char>(-1): | 223 case static_cast<char>(-1): |
| 197 return INPUT_FF; | 224 return INPUT_FF; |
| 198 } | 225 } |
| 199 return INPUT_DEFAULT; | 226 return INPUT_DEFAULT; |
| 200 } | 227 } |
| 201 | 228 |
| 202 HttpServerRequestInfo* HttpListenSocket::ParseHeaders() { | 229 bool HttpListenSocket::ParseHeaders(HttpServerRequestInfo* info) { |
| 203 int pos = 0; | 230 int pos = 0; |
| 204 int data_len = recv_data_.length(); | 231 int data_len = recv_data_.length(); |
| 205 int state = is_web_socket_ ? ST_WS_READY : ST_METHOD; | 232 int state = is_web_socket_ ? ST_WS_READY : ST_METHOD; |
| 206 scoped_ptr<HttpServerRequestInfo> info(new HttpServerRequestInfo()); | |
| 207 std::string buffer; | 233 std::string buffer; |
| 208 std::string header_name; | 234 std::string header_name; |
| 209 std::string header_value; | 235 std::string header_value; |
| 210 while (pos < data_len) { | 236 while (pos < data_len) { |
| 211 char ch = recv_data_[pos++]; | 237 char ch = recv_data_[pos++]; |
| 212 int input = charToInput(ch); | 238 int input = charToInput(ch); |
| 213 int next_state = parser_state[state][input]; | 239 int next_state = parser_state[state][input]; |
| 214 | 240 |
| 215 bool transition = (next_state != state); | 241 bool transition = (next_state != state); |
| 216 if (transition) { | 242 if (transition) { |
| (...skipping 23 matching lines...) Expand all Loading... |
| 240 info->headers[header_name] = header_value; | 266 info->headers[header_name] = header_value; |
| 241 buffer.clear(); | 267 buffer.clear(); |
| 242 break; | 268 break; |
| 243 case ST_SEPARATOR: | 269 case ST_SEPARATOR: |
| 244 buffer.append(&ch, 1); | 270 buffer.append(&ch, 1); |
| 245 break; | 271 break; |
| 246 case ST_WS_FRAME: | 272 case ST_WS_FRAME: |
| 247 recv_data_ = recv_data_.substr(pos); | 273 recv_data_ = recv_data_.substr(pos); |
| 248 info->data = buffer; | 274 info->data = buffer; |
| 249 buffer.clear(); | 275 buffer.clear(); |
| 250 return info.release(); | 276 return true; |
| 251 break; | 277 break; |
| 252 } | 278 } |
| 253 state = next_state; | 279 state = next_state; |
| 254 } else { | 280 } else { |
| 255 // Do any actions based on current state | 281 // Do any actions based on current state |
| 256 switch (state) { | 282 switch (state) { |
| 257 case ST_METHOD: | 283 case ST_METHOD: |
| 258 case ST_URL: | 284 case ST_URL: |
| 259 case ST_PROTO: | 285 case ST_PROTO: |
| 260 case ST_VALUE: | 286 case ST_VALUE: |
| 261 case ST_NAME: | 287 case ST_NAME: |
| 262 case ST_WS_FRAME: | 288 case ST_WS_FRAME: |
| 263 buffer.append(&ch, 1); | 289 buffer.append(&ch, 1); |
| 264 break; | 290 break; |
| 265 case ST_DONE: | 291 case ST_DONE: |
| 266 recv_data_ = recv_data_.substr(pos); | 292 recv_data_ = recv_data_.substr(pos); |
| 267 info->data = recv_data_; | 293 info->data = recv_data_; |
| 268 recv_data_.clear(); | 294 recv_data_.clear(); |
| 269 return info.release(); | 295 return true; |
| 270 case ST_WS_CLOSE: | 296 case ST_WS_CLOSE: |
| 271 is_web_socket_ = false; | 297 is_web_socket_ = false; |
| 272 return NULL; | 298 return false; |
| 273 case ST_ERR: | 299 case ST_ERR: |
| 274 return NULL; | 300 return false; |
| 275 } | 301 } |
| 276 } | 302 } |
| 277 } | 303 } |
| 278 // No more characters, but we haven't finished parsing yet. | 304 // No more characters, but we haven't finished parsing yet. |
| 279 return NULL; | 305 return false; |
| 280 } | 306 } |
| 281 | 307 |
| 282 void HttpListenSocket::DidAccept(ListenSocket* server, | 308 void HttpListenSocket::DidAccept(ListenSocket* server, |
| 283 ListenSocket* connection) { | 309 ListenSocket* connection) { |
| 284 connection->AddRef(); | 310 connection->AddRef(); |
| 285 } | 311 } |
| 286 | 312 |
| 287 void HttpListenSocket::DidRead(ListenSocket*, | 313 void HttpListenSocket::DidRead(ListenSocket*, |
| 288 const char* data, | 314 const char* data, |
| 289 int len) { | 315 int len) { |
| 290 recv_data_.append(data, len); | 316 recv_data_.append(data, len); |
| 291 while (recv_data_.length()) { | 317 while (recv_data_.length()) { |
| 292 scoped_ptr<HttpServerRequestInfo> request(ParseHeaders()); | 318 HttpServerRequestInfo request; |
| 293 if (!request.get()) | 319 if (!ParseHeaders(&request)) |
| 294 break; | 320 break; |
| 295 | 321 |
| 296 if (is_web_socket_) { | 322 if (is_web_socket_) { |
| 297 delegate_->OnWebSocketMessage(this, request->data); | 323 delegate_->OnWebSocketMessage(this, request.data); |
| 298 continue; | 324 continue; |
| 299 } | 325 } |
| 300 | 326 |
| 301 std::string connection = GetHeaderValue(request.get(), "Connection"); | 327 std::string connection = GetHeaderValue(request, "Connection"); |
| 302 if (connection == "Upgrade") { | 328 if (connection == "Upgrade") { |
| 303 // Is this WebSocket and if yes, upgrade the connection. | 329 // Is this WebSocket and if yes, upgrade the connection. |
| 304 std::string key1 = GetHeaderValue(request.get(), "Sec-WebSocket-Key1"); | 330 std::string key1 = GetHeaderValue(request, "Sec-WebSocket-Key1"); |
| 305 std::string key2 = GetHeaderValue(request.get(), "Sec-WebSocket-Key2"); | 331 std::string key2 = GetHeaderValue(request, "Sec-WebSocket-Key2"); |
| 306 if (!key1.empty() && !key2.empty()) { | 332 if (!key1.empty() && !key2.empty()) { |
| 307 delegate_->OnWebSocketRequest(this, request.get()); | 333 delegate_->OnWebSocketRequest(this, request); |
| 308 continue; | 334 continue; |
| 309 } | 335 } |
| 310 } | 336 } |
| 311 delegate_->OnHttpRequest(this, request.get()); | 337 delegate_->OnHttpRequest(this, request); |
| 312 } | 338 } |
| 313 } | 339 } |
| 314 | 340 |
| 315 void HttpListenSocket::DidClose(ListenSocket* sock) { | 341 void HttpListenSocket::DidClose(ListenSocket* sock) { |
| 316 sock->Release(); | 342 sock->Release(); |
| 317 delegate_->OnClose(this); | 343 delegate_->OnClose(this); |
| 318 } | 344 } |
| OLD | NEW |