| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "net/server/web_socket.h" | |
| 6 | |
| 7 #include "base/base64.h" | |
| 8 #include "base/logging.h" | |
| 9 #include "base/md5.h" | |
| 10 #include "base/sha1.h" | |
| 11 #include "base/strings/string_number_conversions.h" | |
| 12 #include "base/strings/stringprintf.h" | |
| 13 #include "base/sys_byteorder.h" | |
| 14 #include "net/server/http_connection.h" | |
| 15 #include "net/server/http_server.h" | |
| 16 #include "net/server/http_server_request_info.h" | |
| 17 #include "net/server/http_server_response_info.h" | |
| 18 #include "net/server/web_socket_encoder.h" | |
| 19 | |
| 20 namespace net { | |
| 21 | |
| 22 namespace { | |
| 23 | |
| 24 static uint32 WebSocketKeyFingerprint(const std::string& str) { | |
| 25 std::string result; | |
| 26 const char* p_char = str.c_str(); | |
| 27 int length = str.length(); | |
| 28 int spaces = 0; | |
| 29 for (int i = 0; i < length; ++i) { | |
| 30 if (p_char[i] >= '0' && p_char[i] <= '9') | |
| 31 result.append(&p_char[i], 1); | |
| 32 else if (p_char[i] == ' ') | |
| 33 spaces++; | |
| 34 } | |
| 35 if (spaces == 0) | |
| 36 return 0; | |
| 37 int64 number = 0; | |
| 38 if (!base::StringToInt64(result, &number)) | |
| 39 return 0; | |
| 40 return base::HostToNet32(static_cast<uint32>(number / spaces)); | |
| 41 } | |
| 42 | |
| 43 class WebSocketHixie76 : public net::WebSocket { | |
| 44 public: | |
| 45 static net::WebSocket* Create(HttpServer* server, | |
| 46 HttpConnection* connection, | |
| 47 const HttpServerRequestInfo& request, | |
| 48 size_t* pos) { | |
| 49 if (connection->read_buf()->GetSize() < | |
| 50 static_cast<int>(*pos + kWebSocketHandshakeBodyLen)) | |
| 51 return NULL; | |
| 52 return new WebSocketHixie76(server, connection, request, pos); | |
| 53 } | |
| 54 | |
| 55 void Accept(const HttpServerRequestInfo& request) override { | |
| 56 std::string key1 = request.GetHeaderValue("sec-websocket-key1"); | |
| 57 std::string key2 = request.GetHeaderValue("sec-websocket-key2"); | |
| 58 | |
| 59 uint32 fp1 = WebSocketKeyFingerprint(key1); | |
| 60 uint32 fp2 = WebSocketKeyFingerprint(key2); | |
| 61 | |
| 62 char data[16]; | |
| 63 memcpy(data, &fp1, 4); | |
| 64 memcpy(data + 4, &fp2, 4); | |
| 65 memcpy(data + 8, &key3_[0], 8); | |
| 66 | |
| 67 base::MD5Digest digest; | |
| 68 base::MD5Sum(data, 16, &digest); | |
| 69 | |
| 70 std::string origin = request.GetHeaderValue("origin"); | |
| 71 std::string host = request.GetHeaderValue("host"); | |
| 72 std::string location = "ws://" + host + request.path; | |
| 73 server_->SendRaw( | |
| 74 connection_->id(), | |
| 75 base::StringPrintf("HTTP/1.1 101 WebSocket Protocol Handshake\r\n" | |
| 76 "Upgrade: WebSocket\r\n" | |
| 77 "Connection: Upgrade\r\n" | |
| 78 "Sec-WebSocket-Origin: %s\r\n" | |
| 79 "Sec-WebSocket-Location: %s\r\n" | |
| 80 "\r\n", | |
| 81 origin.c_str(), | |
| 82 location.c_str())); | |
| 83 server_->SendRaw(connection_->id(), | |
| 84 std::string(reinterpret_cast<char*>(digest.a), 16)); | |
| 85 } | |
| 86 | |
| 87 ParseResult Read(std::string* message) override { | |
| 88 DCHECK(message); | |
| 89 HttpConnection::ReadIOBuffer* read_buf = connection_->read_buf(); | |
| 90 if (read_buf->StartOfBuffer()[0]) | |
| 91 return FRAME_ERROR; | |
| 92 | |
| 93 base::StringPiece data(read_buf->StartOfBuffer(), read_buf->GetSize()); | |
| 94 size_t pos = data.find('\377', 1); | |
| 95 if (pos == base::StringPiece::npos) | |
| 96 return FRAME_INCOMPLETE; | |
| 97 | |
| 98 message->assign(data.data() + 1, pos - 1); | |
| 99 read_buf->DidConsume(pos + 1); | |
| 100 | |
| 101 return FRAME_OK; | |
| 102 } | |
| 103 | |
| 104 void Send(const std::string& message) override { | |
| 105 char message_start = 0; | |
| 106 char message_end = -1; | |
| 107 server_->SendRaw(connection_->id(), std::string(1, message_start)); | |
| 108 server_->SendRaw(connection_->id(), message); | |
| 109 server_->SendRaw(connection_->id(), std::string(1, message_end)); | |
| 110 } | |
| 111 | |
| 112 private: | |
| 113 static const int kWebSocketHandshakeBodyLen; | |
| 114 | |
| 115 WebSocketHixie76(HttpServer* server, | |
| 116 HttpConnection* connection, | |
| 117 const HttpServerRequestInfo& request, | |
| 118 size_t* pos) | |
| 119 : WebSocket(server, connection) { | |
| 120 std::string key1 = request.GetHeaderValue("sec-websocket-key1"); | |
| 121 std::string key2 = request.GetHeaderValue("sec-websocket-key2"); | |
| 122 | |
| 123 if (key1.empty()) { | |
| 124 server->SendResponse( | |
| 125 connection->id(), | |
| 126 HttpServerResponseInfo::CreateFor500( | |
| 127 "Invalid request format. Sec-WebSocket-Key1 is empty or isn't " | |
| 128 "specified.")); | |
| 129 return; | |
| 130 } | |
| 131 | |
| 132 if (key2.empty()) { | |
| 133 server->SendResponse( | |
| 134 connection->id(), | |
| 135 HttpServerResponseInfo::CreateFor500( | |
| 136 "Invalid request format. Sec-WebSocket-Key2 is empty or isn't " | |
| 137 "specified.")); | |
| 138 return; | |
| 139 } | |
| 140 | |
| 141 key3_.assign(connection->read_buf()->StartOfBuffer() + *pos, | |
| 142 kWebSocketHandshakeBodyLen); | |
| 143 *pos += kWebSocketHandshakeBodyLen; | |
| 144 } | |
| 145 | |
| 146 std::string key3_; | |
| 147 | |
| 148 DISALLOW_COPY_AND_ASSIGN(WebSocketHixie76); | |
| 149 }; | |
| 150 | |
| 151 const int WebSocketHixie76::kWebSocketHandshakeBodyLen = 8; | |
| 152 | |
| 153 class WebSocketHybi17 : public WebSocket { | |
| 154 public: | |
| 155 static WebSocket* Create(HttpServer* server, | |
| 156 HttpConnection* connection, | |
| 157 const HttpServerRequestInfo& request, | |
| 158 size_t* pos) { | |
| 159 std::string version = request.GetHeaderValue("sec-websocket-version"); | |
| 160 if (version != "8" && version != "13") | |
| 161 return NULL; | |
| 162 | |
| 163 std::string key = request.GetHeaderValue("sec-websocket-key"); | |
| 164 if (key.empty()) { | |
| 165 server->SendResponse( | |
| 166 connection->id(), | |
| 167 HttpServerResponseInfo::CreateFor500( | |
| 168 "Invalid request format. Sec-WebSocket-Key is empty or isn't " | |
| 169 "specified.")); | |
| 170 return NULL; | |
| 171 } | |
| 172 return new WebSocketHybi17(server, connection, request, pos); | |
| 173 } | |
| 174 | |
| 175 void Accept(const HttpServerRequestInfo& request) override { | |
| 176 static const char* const kWebSocketGuid = | |
| 177 "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; | |
| 178 std::string key = request.GetHeaderValue("sec-websocket-key"); | |
| 179 std::string data = base::StringPrintf("%s%s", key.c_str(), kWebSocketGuid); | |
| 180 std::string encoded_hash; | |
| 181 base::Base64Encode(base::SHA1HashString(data), &encoded_hash); | |
| 182 | |
| 183 server_->SendRaw(connection_->id(), | |
| 184 base::StringPrintf( | |
| 185 "HTTP/1.1 101 WebSocket Protocol Handshake\r\n" | |
| 186 "Upgrade: WebSocket\r\n" | |
| 187 "Connection: Upgrade\r\n" | |
| 188 "Sec-WebSocket-Accept: %s\r\n" | |
| 189 "%s" | |
| 190 "\r\n", | |
| 191 encoded_hash.c_str(), response_extensions_.c_str())); | |
| 192 } | |
| 193 | |
| 194 ParseResult Read(std::string* message) override { | |
| 195 HttpConnection::ReadIOBuffer* read_buf = connection_->read_buf(); | |
| 196 base::StringPiece frame(read_buf->StartOfBuffer(), read_buf->GetSize()); | |
| 197 int bytes_consumed = 0; | |
| 198 ParseResult result = encoder_->DecodeFrame(frame, &bytes_consumed, message); | |
| 199 if (result == FRAME_OK) | |
| 200 read_buf->DidConsume(bytes_consumed); | |
| 201 if (result == FRAME_CLOSE) | |
| 202 closed_ = true; | |
| 203 return result; | |
| 204 } | |
| 205 | |
| 206 void Send(const std::string& message) override { | |
| 207 if (closed_) | |
| 208 return; | |
| 209 std::string encoded; | |
| 210 encoder_->EncodeFrame(message, 0, &encoded); | |
| 211 server_->SendRaw(connection_->id(), encoded); | |
| 212 } | |
| 213 | |
| 214 private: | |
| 215 WebSocketHybi17(HttpServer* server, | |
| 216 HttpConnection* connection, | |
| 217 const HttpServerRequestInfo& request, | |
| 218 size_t* pos) | |
| 219 : WebSocket(server, connection), | |
| 220 closed_(false) { | |
| 221 std::string request_extensions = | |
| 222 request.GetHeaderValue("sec-websocket-extensions"); | |
| 223 encoder_.reset(WebSocketEncoder::CreateServer(request_extensions, | |
| 224 &response_extensions_)); | |
| 225 if (!response_extensions_.empty()) { | |
| 226 response_extensions_ = | |
| 227 "Sec-WebSocket-Extensions: " + response_extensions_ + "\r\n"; | |
| 228 } | |
| 229 } | |
| 230 | |
| 231 scoped_ptr<WebSocketEncoder> encoder_; | |
| 232 std::string response_extensions_; | |
| 233 bool closed_; | |
| 234 | |
| 235 DISALLOW_COPY_AND_ASSIGN(WebSocketHybi17); | |
| 236 }; | |
| 237 | |
| 238 } // anonymous namespace | |
| 239 | |
| 240 WebSocket* WebSocket::CreateWebSocket(HttpServer* server, | |
| 241 HttpConnection* connection, | |
| 242 const HttpServerRequestInfo& request, | |
| 243 size_t* pos) { | |
| 244 WebSocket* socket = WebSocketHybi17::Create(server, connection, request, pos); | |
| 245 if (socket) | |
| 246 return socket; | |
| 247 | |
| 248 return WebSocketHixie76::Create(server, connection, request, pos); | |
| 249 } | |
| 250 | |
| 251 WebSocket::WebSocket(HttpServer* server, HttpConnection* connection) | |
| 252 : server_(server), | |
| 253 connection_(connection) { | |
| 254 } | |
| 255 | |
| 256 WebSocket::~WebSocket() { | |
| 257 } | |
| 258 | |
| 259 } // namespace net | |
| OLD | NEW |