Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1289)

Side by Side Diff: net/server/web_socket.cc

Issue 7482041: DevTools: no way to remote debug using ToT build. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: web_socket class was extracted. Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« net/server/web_socket.h ('K') | « net/server/web_socket.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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/web_socket.h"
6
7 #include "base/base64.h"
8 #include "base/rand_util.h"
9 #include "base/logging.h"
10 #include "base/md5.h"
11 #include "base/sha1.h"
12 #include "base/string_number_conversions.h"
13 #include "base/stringprintf.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 #include <limits>
23
24 namespace net {
25
26 WebSocket::WebSocket(Connection* connection)
27 : connection_(connection) {
28 }
29
30 static std::string GetHeaderValue(
31 const HttpServerRequestInfo& request,
32 const std::string& header_name) {
33 HttpServerRequestInfo::HeadersMap::iterator it =
34 request.headers.find(header_name);
35 if (it != request.headers.end())
36 return it->second;
37 return "";
38 }
39
40 class WebSocketHixie76 : public WebSocket {
41 public:
42 static WebSocket* create(Connection* connection,
43 const HttpServerRequestInfo& request,
44 size_t* pos);
45
46 virtual void Accept(const HttpServerRequestInfo& request);
47 virtual ParseResult Read(std::string* message);
48 virtual void Send(const std::string& message);
49
eroman 2011/08/02 18:46:41 Note that virtual dtor is missing here, so this wi
50 private:
51 WebSocketHixie76(Connection* connection,
52 const HttpServerRequestInfo& request,
53 size_t* pos);
54 static const int kWebSocketHandshakeBodyLen;
55 std::string key3_;
56 };
57
58 const int WebSocketHixie76::kWebSocketHandshakeBodyLen = 8;
59
60 WebSocket* WebSocketHixie76::create(Connection* connection,
61 const HttpServerRequestInfo& request,
62 size_t* pos) {
63 if (connection->RecvData().length() < *pos + kWebSocketHandshakeBodyLen)
64 return NULL;
65 return new WebSocketHixie76(connection, request, pos);
66 }
67
68 WebSocketHixie76::WebSocketHixie76(Connection* connection,
69 const HttpServerRequestInfo& request,
70 size_t* pos)
71 : WebSocket(connection) {
72 std::string key1 = GetHeaderValue(request, "Sec-WebSocket-Key1");
73 std::string key2 = GetHeaderValue(request, "Sec-WebSocket-Key2");
74
75 if (key1.empty()) {
76 connection->Send500("Invalid request format. "
77 "Sec-WebSocket-Key1 is empty or isn't specified.");
78 return;
79 }
80
81 if (key2.empty()) {
82 connection->Send500("Invalid request format. "
83 "Sec-WebSocket-Key2 is empty or isn't specified.");
84 return;
85 }
86
87 key3_ = connection->RecvData().substr(
88 *pos,
89 *pos + kWebSocketHandshakeBodyLen);
90 *pos += kWebSocketHandshakeBodyLen;
91 }
92
93 static uint32 WebSocketKeyFingerprint(const std::string& str) {
94 std::string result;
95 const char* pChar = str.c_str();
96 int length = str.length();
97 int spaces = 0;
98 for (int i = 0; i < length; ++i) {
99 if (pChar[i] >= '0' && pChar[i] <= '9')
100 result.append(&pChar[i], 1);
101 else if (pChar[i] == ' ')
102 spaces++;
103 }
104 if (spaces == 0)
105 return 0;
106 int64 number = 0;
107 if (!base::StringToInt64(result, &number))
108 return 0;
109 return htonl(static_cast<uint32>(number / spaces));
110 }
111
112 void WebSocketHixie76::Accept(const HttpServerRequestInfo& request) {
113 std::string key1 = GetHeaderValue(request, "Sec-WebSocket-Key1");
114 std::string key2 = GetHeaderValue(request, "Sec-WebSocket-Key2");
115
116 uint32 fp1 = WebSocketKeyFingerprint(key1);
117 uint32 fp2 = WebSocketKeyFingerprint(key2);
118
119 char data[16];
120 memcpy(data, &fp1, 4);
121 memcpy(data + 4, &fp2, 4);
122 memcpy(data + 8, &key3_[0], 8);
123
124 base::MD5Digest digest;
125 base::MD5Sum(data, 16, &digest);
126
127 std::string origin = GetHeaderValue(request, "Origin");
128 std::string host = GetHeaderValue(request, "Host");
129 std::string location = "ws://" + host + request.path;
130 connection_->Send(base::StringPrintf(
131 "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
132 "Upgrade: WebSocket\r\n"
133 "Connection: Upgrade\r\n"
134 "Sec-WebSocket-Origin: %s\r\n"
135 "Sec-WebSocket-Location: %s\r\n"
136 "\r\n",
137 origin.c_str(),
138 location.c_str()));
139 connection_->Send(reinterpret_cast<char*>(digest.a), 16);
140 }
141
142 WebSocket::ParseResult WebSocketHixie76::Read(std::string* message) {
143 DCHECK(message);
144 const std::string& data = connection_->RecvData();
145 if (data[0])
146 return FrameError;
147
148 size_t pos = data.find('\377', 1);
149 if (pos == std::string::npos)
150 return FrameIncomplete;
151
152 std::string buffer(data.begin() + 1, data.begin() + pos);
153 message->swap(buffer);
154 connection_->Shift(pos + 1);
155
156 return FrameOK;
157 }
158
159 void WebSocketHixie76::Send(const std::string& message) {
160 char message_start = 0;
161 char message_end = -1;
162 connection_->Send(&message_start, 1);
163 connection_->Send(message);
164 connection_->Send(&message_end, 1);
165 }
166
167 class WebSocketHybi10 : public WebSocket {
168 public:
169
eroman 2011/08/02 18:46:41 Remove space.
170 typedef int OpCode;
171
172 static WebSocket* create(Connection* connection,
eroman 2011/08/02 18:46:41 Create
173 const HttpServerRequestInfo& request,
174 size_t* pos);
175 virtual void Accept(const HttpServerRequestInfo& request);
176 virtual ParseResult Read(std::string* message);
177 virtual void Send(const std::string& message);
178
179 private:
180 WebSocketHybi10(Connection* connection,
181 const HttpServerRequestInfo& request,
182 size_t* pos);
183
184 OpCode op_code_;
185 bool final_;
186 bool reserved1_;
187 bool reserved2_;
188 bool reserved3_;
189 bool masked_;
190 const char* payload_;
191 size_t payload_length_;
192 const char* frame_end_;
193 };
194
195 namespace {
196
197 // Constants for hybi-10 frame format.
198 const WebSocketHybi10::OpCode kOpCodeContinuation = 0x0;
199 const WebSocketHybi10::OpCode kOpCodeText = 0x1;
200 const WebSocketHybi10::OpCode kOpCodeBinary = 0x2;
201 const WebSocketHybi10::OpCode kOpCodeClose = 0x8;
202 const WebSocketHybi10::OpCode kOpCodePing = 0x9;
203 const WebSocketHybi10::OpCode kOpCodePong = 0xA;
204
205 const unsigned char kFinalBit = 0x80;
206 const unsigned char kReserved1Bit = 0x40;
207 const unsigned char kReserved2Bit = 0x20;
208 const unsigned char kReserved3Bit = 0x10;
209 const unsigned char kOpCodeMask = 0xF;
210 const unsigned char kMaskBit = 0x80;
211 const unsigned char kPayloadLengthMask = 0x7F;
212
213 const size_t kMaxSingleBytePayloadLength = 125;
214 const size_t kTwoBytePayloadLengthField = 126;
215 const size_t kEightBytePayloadLengthField = 127;
216 const size_t kMaskingKeyWidthInBytes = 4;
217
218 }
eroman 2011/08/02 18:46:41 nit: Please mark this with: // anonymous (conve
219
220 WebSocket* WebSocketHybi10::create(Connection* connection,
221 const HttpServerRequestInfo& request,
222 size_t* pos) {
223 std::string key = GetHeaderValue(request, "Sec-WebSocket-Key");
224 if (key.empty()) {
225 connection->Send500("Invalid request format. "
226 "Sec-WebSocket-Key is empty or isn't specified.");
227 return NULL;
228 }
229 return new WebSocketHybi10(connection, request, pos);
230 }
231
232 WebSocketHybi10::WebSocketHybi10(Connection* connection,
233 const HttpServerRequestInfo& request,
234 size_t* pos)
235 : WebSocket(connection) {
236 }
237
238 void WebSocketHybi10::Accept(const HttpServerRequestInfo& request)
239 {
240 static const char* const web_socket_GUID =
241 "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
242 std::string key = GetHeaderValue(request, "Sec-WebSocket-Key");
243 std::string data = base::StringPrintf("%s%s", key.c_str(), web_socket_GUID);
244 std::string encoded_hash;
245 base::Base64Encode(base::SHA1HashString(data), &encoded_hash);
246
247 std::string response = base::StringPrintf(
248 "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
249 "Upgrade: WebSocket\r\n"
250 "Connection: Upgrade\r\n"
251 "Sec-WebSocket-Accept: %s\r\n"
252 "\r\n",
253 encoded_hash.c_str());
254 connection_->Send(response);
255 }
256
257 WebSocket::ParseResult WebSocketHybi10::Read(std::string* message) {
258 size_t data_length = connection_->RecvData().length();
259 if (data_length < 2)
260 return FrameIncomplete;
261
262 const char* p = connection_->RecvData().c_str();
263 const char* buffer_end = p + data_length;
264
265 unsigned char first_byte = *p++;
266 unsigned char second_byte = *p++;
267
268 final_ = first_byte & kFinalBit;
269 reserved1_ = first_byte & kReserved1Bit;
270 reserved2_ = first_byte & kReserved2Bit;
271 reserved3_ = first_byte & kReserved3Bit;
272 op_code_ = first_byte & kOpCodeMask;
273 masked_ = second_byte & kMaskBit;
274
275 CHECK(op_code_ == kOpCodeText);
eroman 2011/08/02 18:46:41 CHECK_EQ ?
276
277 uint64 payload_length64 = second_byte & kPayloadLengthMask;
278 if (payload_length64 > kMaxSingleBytePayloadLength) {
279 int extended_payload_length_size;
280 if (payload_length64 == kTwoBytePayloadLengthField)
281 extended_payload_length_size = 2;
282 else {
283 DCHECK(payload_length64 == kEightBytePayloadLengthField);
284 extended_payload_length_size = 8;
285 }
286 if (buffer_end - p < extended_payload_length_size)
287 return FrameIncomplete;
288 payload_length64 = 0;
289 for (int i = 0; i < extended_payload_length_size; ++i) {
290 payload_length64 <<= 8;
291 payload_length64 |= static_cast<unsigned char>(*p++);
292 }
293 }
294
295 static const uint64 max_payload_ength = 0x7FFFFFFFFFFFFFFFull;
eroman 2011/08/02 18:46:41 ength --> length
296 size_t masking_key_length = masked_ ? kMaskingKeyWidthInBytes : 0;
297 static size_t max_length = std::numeric_limits<size_t>::max();
298 if (payload_length64 > max_payload_ength ||
299 payload_length64 + masking_key_length > max_length) {
300 // WebSocket frame length too large.
301 return FrameError;
302 }
303 payload_length_ = static_cast<size_t>(payload_length64);
304
305 size_t total_length = masking_key_length + payload_length_;
306 if (static_cast<size_t>(buffer_end - p) < total_length)
307 return FrameIncomplete;
308
309 if (masked_) {
310 message->resize(payload_length_);
311 const char* masking_key = p;
312 char* payload = const_cast<char*>(p + kMaskingKeyWidthInBytes);
313 for (size_t i = 0; i < payload_length_; ++i) // Unmask the payload.
314 (*message)[i] = payload[i] ^ masking_key[i % kMaskingKeyWidthInBytes];
315 } else {
316 std::string buffer(p, p + payload_length_);
317 message->swap(buffer);
318 }
319
320 size_t pos = p + masking_key_length + payload_length_ -
321 connection_->RecvData().c_str();
eroman 2011/08/02 18:46:41 Huh? What is subtracting the c_str() about? That l
322 connection_->Shift(pos);
323 return FrameOK;
324 }
325
326 void WebSocketHybi10::Send(const std::string& message) {
327 std::vector<char> frame;
328 OpCode op_code = kOpCodeText;
329 size_t data_length = message.length();
330
331 frame.push_back(kFinalBit | op_code);
332 if (data_length <= kMaxSingleBytePayloadLength)
333 frame.push_back(kMaskBit | data_length);
334 else if (data_length <= 0xFFFF) {
335 frame.push_back(kMaskBit | kTwoBytePayloadLengthField);
336 frame.push_back((data_length & 0xFF00) >> 8);
337 frame.push_back(data_length & 0xFF);
338 } else {
339 frame.push_back(kMaskBit | kEightBytePayloadLengthField);
340 char extended_payload_length[8];
341 size_t remaining = data_length;
342 // Fill the length into extended_payload_length in the network byte order.
343 for (int i = 0; i < 8; ++i) {
344 extended_payload_length[7 - i] = remaining & 0xFF;
345 remaining >>= 8;
346 }
347 frame.insert(frame.end(),
348 extended_payload_length,
349 extended_payload_length + 8);
350 DCHECK(!remaining);
351 }
352
353 // Mask the frame.
354 size_t masking_key_start = frame.size();
355 // Add placeholder for masking key. Will be overwritten.
356 frame.resize(frame.size() + kMaskingKeyWidthInBytes);
357 size_t payload_start = frame.size();
358 const char* data = message.c_str();
359 frame.insert(frame.end(), data, data + data_length);
360
361 base::RandBytes(&frame[0] + masking_key_start,
362 kMaskingKeyWidthInBytes);
363 for (size_t i = 0; i < data_length; ++i) {
364 frame[payload_start + i] ^=
365 frame[masking_key_start + i % kMaskingKeyWidthInBytes];
366 }
367 connection_->Send(&frame[0], frame.size());
368 }
369
370 WebSocket* WebSocket::createWebSocket(Connection* connection,
371 const HttpServerRequestInfo& request,
372 size_t* pos) {
373 std::string version = GetHeaderValue(request, "Sec-WebSocket-Version");
374 if (version.length() && version == "8")
375 return WebSocketHybi10::create(connection, request, pos);
376 else
377 return WebSocketHixie76::create(connection, request, pos);
378 }
379
380 } // namespace net
OLDNEW
« net/server/web_socket.h ('K') | « net/server/web_socket.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698