1 |
|
#include "inspector_socket.h" |
2 |
|
#include "util.h" |
3 |
|
#include "util-inl.h" |
4 |
|
|
5 |
|
#define NODE_WANT_INTERNALS 1 |
6 |
|
#include "base64.h" |
7 |
|
|
8 |
|
#include "openssl/sha.h" // Sha-1 hash |
9 |
|
|
10 |
|
#include <string.h> |
11 |
|
#include <vector> |
12 |
|
|
13 |
|
#define ACCEPT_KEY_LENGTH base64_encoded_size(20) |
14 |
|
#define BUFFER_GROWTH_CHUNK_SIZE 1024 |
15 |
|
|
16 |
|
#define DUMP_READS 0 |
17 |
|
#define DUMP_WRITES 0 |
18 |
|
|
19 |
|
static const char CLOSE_FRAME[] = {'\x88', '\x00'}; |
20 |
|
|
21 |
|
struct http_parsing_state_s { |
22 |
|
http_parser parser; |
23 |
|
http_parser_settings parser_settings; |
24 |
|
handshake_cb callback; |
25 |
|
bool done; |
26 |
|
bool parsing_value; |
27 |
|
char* ws_key; |
28 |
|
char* path; |
29 |
|
char* current_header; |
30 |
|
}; |
31 |
|
|
32 |
|
struct ws_state_s { |
33 |
|
uv_alloc_cb alloc_cb; |
34 |
|
uv_read_cb read_cb; |
35 |
|
inspector_cb close_cb; |
36 |
|
bool close_sent; |
37 |
|
bool received_close; |
38 |
|
}; |
39 |
|
|
40 |
|
enum ws_decode_result { |
41 |
|
FRAME_OK, FRAME_INCOMPLETE, FRAME_CLOSE, FRAME_ERROR |
42 |
|
}; |
43 |
|
|
44 |
|
#if DUMP_READS || DUMP_WRITES |
45 |
|
static void dump_hex(const char* buf, size_t len) { |
46 |
|
const char* ptr = buf; |
47 |
|
const char* end = ptr + len; |
48 |
|
const char* cptr; |
49 |
|
char c; |
50 |
|
int i; |
51 |
|
|
52 |
|
while (ptr < end) { |
53 |
|
cptr = ptr; |
54 |
|
for (i = 0; i < 16 && ptr < end; i++) { |
55 |
|
printf("%2.2X ", *(ptr++)); |
56 |
|
} |
57 |
|
for (i = 72 - (i * 4); i > 0; i--) { |
58 |
|
printf(" "); |
59 |
|
} |
60 |
|
for (i = 0; i < 16 && cptr < end; i++) { |
61 |
|
c = *(cptr++); |
62 |
|
printf("%c", (c > 0x19) ? c : '.'); |
63 |
|
} |
64 |
|
printf("\n"); |
65 |
|
} |
66 |
|
printf("\n\n"); |
67 |
|
} |
68 |
|
#endif |
69 |
|
|
70 |
|
static void dispose_inspector(uv_handle_t* handle) { |
71 |
|
inspector_socket_t* inspector = |
72 |
|
reinterpret_cast<inspector_socket_t*>(handle->data); |
73 |
|
inspector_cb close = |
74 |
|
inspector->ws_mode ? inspector->ws_state->close_cb : nullptr; |
75 |
|
free(inspector->buffer); |
76 |
|
free(inspector->ws_state); |
77 |
|
inspector->ws_state = nullptr; |
78 |
|
inspector->buffer = nullptr; |
79 |
|
inspector->buffer_size = 0; |
80 |
|
inspector->data_len = 0; |
81 |
|
inspector->last_read_end = 0; |
82 |
|
if (close) { |
83 |
|
close(inspector, 0); |
84 |
|
} |
85 |
|
} |
86 |
|
|
87 |
|
static void close_connection(inspector_socket_t* inspector) { |
88 |
|
uv_handle_t* socket = reinterpret_cast<uv_handle_t*>(&inspector->client); |
89 |
|
if (!uv_is_closing(socket)) { |
90 |
|
uv_read_stop(reinterpret_cast<uv_stream_t*>(socket)); |
91 |
|
uv_close(socket, dispose_inspector); |
92 |
|
} |
93 |
|
} |
94 |
|
|
95 |
|
// Cleanup |
96 |
|
static void write_request_cleanup(uv_write_t* req, int status) { |
97 |
|
free((reinterpret_cast<uv_buf_t*>(req->data))->base); |
98 |
|
free(req->data); |
99 |
|
free(req); |
100 |
|
} |
101 |
|
|
102 |
|
static int write_to_client(inspector_socket_t* inspector, |
103 |
|
const char* msg, |
104 |
|
size_t len, |
105 |
|
uv_write_cb write_cb = write_request_cleanup) { |
106 |
|
#if DUMP_WRITES |
107 |
|
printf("%s (%ld bytes):\n", __FUNCTION__, len); |
108 |
|
dump_hex(msg, len); |
109 |
|
#endif |
110 |
|
|
111 |
|
// Freed in write_request_cleanup |
112 |
|
uv_buf_t* buf = reinterpret_cast<uv_buf_t*>(malloc(sizeof(uv_buf_t))); |
113 |
|
uv_write_t* req = reinterpret_cast<uv_write_t*>(malloc(sizeof(uv_write_t))); |
114 |
|
CHECK_NE(buf, nullptr); |
115 |
|
CHECK_NE(req, nullptr); |
116 |
|
memset(req, 0, sizeof(*req)); |
117 |
|
buf->base = reinterpret_cast<char*>(malloc(len)); |
118 |
|
|
119 |
|
CHECK_NE(buf->base, nullptr); |
120 |
|
|
121 |
|
memcpy(buf->base, msg, len); |
122 |
|
buf->len = len; |
123 |
|
req->data = buf; |
124 |
|
|
125 |
|
uv_stream_t* stream = reinterpret_cast<uv_stream_t*>(&inspector->client); |
126 |
|
return uv_write(req, stream, buf, 1, write_cb) < 0; |
127 |
|
} |
128 |
|
|
129 |
|
// Constants for hybi-10 frame format. |
130 |
|
|
131 |
|
typedef int OpCode; |
132 |
|
|
133 |
|
const OpCode kOpCodeContinuation = 0x0; |
134 |
|
const OpCode kOpCodeText = 0x1; |
135 |
|
const OpCode kOpCodeBinary = 0x2; |
136 |
|
const OpCode kOpCodeClose = 0x8; |
137 |
|
const OpCode kOpCodePing = 0x9; |
138 |
|
const OpCode kOpCodePong = 0xA; |
139 |
|
|
140 |
|
const unsigned char kFinalBit = 0x80; |
141 |
|
const unsigned char kReserved1Bit = 0x40; |
142 |
|
const unsigned char kReserved2Bit = 0x20; |
143 |
|
const unsigned char kReserved3Bit = 0x10; |
144 |
|
const unsigned char kOpCodeMask = 0xF; |
145 |
|
const unsigned char kMaskBit = 0x80; |
146 |
|
const unsigned char kPayloadLengthMask = 0x7F; |
147 |
|
|
148 |
|
const size_t kMaxSingleBytePayloadLength = 125; |
149 |
|
const size_t kTwoBytePayloadLengthField = 126; |
150 |
|
const size_t kEightBytePayloadLengthField = 127; |
151 |
|
const size_t kMaskingKeyWidthInBytes = 4; |
152 |
|
|
153 |
|
static std::vector<char> encode_frame_hybi17(const char* message, |
154 |
|
size_t data_length) { |
155 |
|
std::vector<char> frame; |
156 |
|
OpCode op_code = kOpCodeText; |
157 |
|
frame.push_back(kFinalBit | op_code); |
158 |
|
if (data_length <= kMaxSingleBytePayloadLength) { |
159 |
|
frame.push_back(static_cast<char>(data_length)); |
160 |
|
} else if (data_length <= 0xFFFF) { |
161 |
|
frame.push_back(kTwoBytePayloadLengthField); |
162 |
|
frame.push_back((data_length & 0xFF00) >> 8); |
163 |
|
frame.push_back(data_length & 0xFF); |
164 |
|
} else { |
165 |
|
frame.push_back(kEightBytePayloadLengthField); |
166 |
|
char extended_payload_length[8]; |
167 |
|
size_t remaining = data_length; |
168 |
|
// Fill the length into extended_payload_length in the network byte order. |
169 |
|
for (int i = 0; i < 8; ++i) { |
170 |
|
extended_payload_length[7 - i] = remaining & 0xFF; |
171 |
|
remaining >>= 8; |
172 |
|
} |
173 |
|
frame.insert(frame.end(), extended_payload_length, |
174 |
|
extended_payload_length + 8); |
175 |
|
ASSERT_EQ(0, remaining); |
176 |
|
} |
177 |
|
frame.insert(frame.end(), message, message + data_length); |
178 |
|
return frame; |
179 |
|
} |
180 |
|
|
181 |
|
static ws_decode_result decode_frame_hybi17(const char* buffer_begin, |
182 |
|
size_t data_length, |
183 |
|
bool client_frame, |
184 |
|
int* bytes_consumed, |
185 |
|
std::vector<char>* output, |
186 |
|
bool* compressed) { |
187 |
|
*bytes_consumed = 0; |
188 |
|
if (data_length < 2) |
189 |
|
return FRAME_INCOMPLETE; |
190 |
|
|
191 |
|
const char* p = buffer_begin; |
192 |
|
const char* buffer_end = p + data_length; |
193 |
|
|
194 |
|
unsigned char first_byte = *p++; |
195 |
|
unsigned char second_byte = *p++; |
196 |
|
|
197 |
|
bool final = (first_byte & kFinalBit) != 0; |
198 |
|
bool reserved1 = (first_byte & kReserved1Bit) != 0; |
199 |
|
bool reserved2 = (first_byte & kReserved2Bit) != 0; |
200 |
|
bool reserved3 = (first_byte & kReserved3Bit) != 0; |
201 |
|
int op_code = first_byte & kOpCodeMask; |
202 |
|
bool masked = (second_byte & kMaskBit) != 0; |
203 |
|
*compressed = reserved1; |
204 |
|
if (!final || reserved2 || reserved3) |
205 |
|
return FRAME_ERROR; // Only compression extension is supported. |
206 |
|
|
207 |
|
bool closed = false; |
208 |
|
switch (op_code) { |
209 |
|
case kOpCodeClose: |
210 |
|
closed = true; |
211 |
|
break; |
212 |
|
case kOpCodeText: |
213 |
|
break; |
214 |
|
case kOpCodeBinary: // We don't support binary frames yet. |
215 |
|
case kOpCodeContinuation: // We don't support binary frames yet. |
216 |
|
case kOpCodePing: // We don't support binary frames yet. |
217 |
|
case kOpCodePong: // We don't support binary frames yet. |
218 |
|
default: |
219 |
|
return FRAME_ERROR; |
220 |
|
} |
221 |
|
|
222 |
|
// In Hybi-17 spec client MUST mask its frame. |
223 |
|
if (client_frame && !masked) { |
224 |
|
return FRAME_ERROR; |
225 |
|
} |
226 |
|
|
227 |
|
uint64_t payload_length64 = second_byte & kPayloadLengthMask; |
228 |
|
if (payload_length64 > kMaxSingleBytePayloadLength) { |
229 |
|
int extended_payload_length_size; |
230 |
|
if (payload_length64 == kTwoBytePayloadLengthField) { |
231 |
|
extended_payload_length_size = 2; |
232 |
|
} else if (payload_length64 == kEightBytePayloadLengthField) { |
233 |
|
extended_payload_length_size = 8; |
234 |
|
} else { |
235 |
|
return FRAME_ERROR; |
236 |
|
} |
237 |
|
if (buffer_end - p < extended_payload_length_size) |
238 |
|
return FRAME_INCOMPLETE; |
239 |
|
payload_length64 = 0; |
240 |
|
for (int i = 0; i < extended_payload_length_size; ++i) { |
241 |
|
payload_length64 <<= 8; |
242 |
|
payload_length64 |= static_cast<unsigned char>(*p++); |
243 |
|
} |
244 |
|
} |
245 |
|
|
246 |
|
static const uint64_t max_payload_length = 0x7FFFFFFFFFFFFFFFull; |
247 |
|
static const size_t max_length = SIZE_MAX; |
248 |
|
if (payload_length64 > max_payload_length || |
249 |
|
payload_length64 > max_length - kMaskingKeyWidthInBytes) { |
250 |
|
// WebSocket frame length too large. |
251 |
|
return FRAME_ERROR; |
252 |
|
} |
253 |
|
size_t payload_length = static_cast<size_t>(payload_length64); |
254 |
|
|
255 |
|
if (data_length - kMaskingKeyWidthInBytes < payload_length) |
256 |
|
return FRAME_INCOMPLETE; |
257 |
|
|
258 |
|
const char* masking_key = p; |
259 |
|
const char* payload = p + kMaskingKeyWidthInBytes; |
260 |
|
for (size_t i = 0; i < payload_length; ++i) // Unmask the payload. |
261 |
|
output->insert(output->end(), |
262 |
|
payload[i] ^ masking_key[i % kMaskingKeyWidthInBytes]); |
263 |
|
|
264 |
|
size_t pos = p + kMaskingKeyWidthInBytes + payload_length - buffer_begin; |
265 |
|
*bytes_consumed = pos; |
266 |
|
return closed ? FRAME_CLOSE : FRAME_OK; |
267 |
|
} |
268 |
|
|
269 |
|
static void invoke_read_callback(inspector_socket_t* inspector, |
270 |
|
int status, const uv_buf_t* buf) { |
271 |
|
if (inspector->ws_state->read_cb) { |
272 |
|
inspector->ws_state->read_cb( |
273 |
|
reinterpret_cast<uv_stream_t*>(&inspector->client), status, buf); |
274 |
|
} |
275 |
|
} |
276 |
|
|
277 |
|
static void shutdown_complete(inspector_socket_t* inspector) { |
278 |
|
close_connection(inspector); |
279 |
|
} |
280 |
|
|
281 |
|
static void on_close_frame_written(uv_write_t* write, int status) { |
282 |
|
inspector_socket_t* inspector = |
283 |
|
reinterpret_cast<inspector_socket_t*>(write->handle->data); |
284 |
|
write_request_cleanup(write, status); |
285 |
|
inspector->ws_state->close_sent = true; |
286 |
|
if (inspector->ws_state->received_close) { |
287 |
|
shutdown_complete(inspector); |
288 |
|
} |
289 |
|
} |
290 |
|
|
291 |
|
static void close_frame_received(inspector_socket_t* inspector) { |
292 |
|
inspector->ws_state->received_close = true; |
293 |
|
if (!inspector->ws_state->close_sent) { |
294 |
|
invoke_read_callback(inspector, 0, 0); |
295 |
|
write_to_client(inspector, CLOSE_FRAME, sizeof(CLOSE_FRAME), |
296 |
|
on_close_frame_written); |
297 |
|
} else { |
298 |
|
shutdown_complete(inspector); |
299 |
|
} |
300 |
|
} |
301 |
|
|
302 |
|
static int parse_ws_frames(inspector_socket_t* inspector, size_t len) { |
303 |
|
int bytes_consumed = 0; |
304 |
|
std::vector<char> output; |
305 |
|
bool compressed = false; |
306 |
|
|
307 |
|
ws_decode_result r = decode_frame_hybi17(inspector->buffer, |
308 |
|
len, true /* client_frame */, |
309 |
|
&bytes_consumed, &output, |
310 |
|
&compressed); |
311 |
|
// Compressed frame means client is ignoring the headers and misbehaves |
312 |
|
if (compressed || r == FRAME_ERROR) { |
313 |
|
invoke_read_callback(inspector, UV_EPROTO, nullptr); |
314 |
|
close_connection(inspector); |
315 |
|
bytes_consumed = 0; |
316 |
|
} else if (r == FRAME_CLOSE) { |
317 |
|
close_frame_received(inspector); |
318 |
|
bytes_consumed = 0; |
319 |
|
} else if (r == FRAME_OK && inspector->ws_state->alloc_cb |
320 |
|
&& inspector->ws_state->read_cb) { |
321 |
|
uv_buf_t buffer; |
322 |
|
size_t len = output.size(); |
323 |
|
inspector->ws_state->alloc_cb( |
324 |
|
reinterpret_cast<uv_handle_t*>(&inspector->client), |
325 |
|
len, &buffer); |
326 |
|
CHECK_GE(buffer.len, len); |
327 |
|
memcpy(buffer.base, &output[0], len); |
328 |
|
invoke_read_callback(inspector, len, &buffer); |
329 |
|
} |
330 |
|
return bytes_consumed; |
331 |
|
} |
332 |
|
|
333 |
|
static void prepare_buffer(uv_handle_t* stream, size_t len, uv_buf_t* buf) { |
334 |
|
inspector_socket_t* inspector = |
335 |
|
reinterpret_cast<inspector_socket_t*>(stream->data); |
336 |
|
|
337 |
|
if (len > (inspector->buffer_size - inspector->data_len)) { |
338 |
|
int new_size = (inspector->data_len + len + BUFFER_GROWTH_CHUNK_SIZE - 1) / |
339 |
|
BUFFER_GROWTH_CHUNK_SIZE * |
340 |
|
BUFFER_GROWTH_CHUNK_SIZE; |
341 |
|
inspector->buffer_size = new_size; |
342 |
|
inspector->buffer = reinterpret_cast<char*>(realloc(inspector->buffer, |
343 |
|
inspector->buffer_size)); |
344 |
|
ASSERT_NE(inspector->buffer, nullptr); |
345 |
|
} |
346 |
|
buf->base = inspector->buffer + inspector->data_len; |
347 |
|
buf->len = len; |
348 |
|
inspector->data_len += len; |
349 |
|
} |
350 |
|
|
351 |
|
static void websockets_data_cb(uv_stream_t* stream, ssize_t nread, |
352 |
|
const uv_buf_t* buf) { |
353 |
|
inspector_socket_t* inspector = |
354 |
|
reinterpret_cast<inspector_socket_t*>(stream->data); |
355 |
|
if (nread < 0 || nread == UV_EOF) { |
356 |
|
inspector->connection_eof = true; |
357 |
|
if (!inspector->shutting_down && inspector->ws_state->read_cb) { |
358 |
|
inspector->ws_state->read_cb(stream, nread, nullptr); |
359 |
|
} |
360 |
|
} else { |
361 |
|
#if DUMP_READS |
362 |
|
printf("%s read %ld bytes\n", __FUNCTION__, nread); |
363 |
|
if (nread > 0) { |
364 |
|
dump_hex(buf->base, nread); |
365 |
|
} |
366 |
|
#endif |
367 |
|
// 1. Move read bytes to continue the buffer |
368 |
|
// Should be same as this is supposedly last buffer |
369 |
|
ASSERT_EQ(buf->base + buf->len, inspector->buffer + inspector->data_len); |
370 |
|
|
371 |
|
// Should be noop... |
372 |
|
memmove(inspector->buffer + inspector->last_read_end, buf->base, nread); |
373 |
|
inspector->last_read_end += nread; |
374 |
|
|
375 |
|
// 2. Parse. |
376 |
|
int processed = 0; |
377 |
|
do { |
378 |
|
processed = parse_ws_frames(inspector, inspector->last_read_end); |
379 |
|
// 3. Fix the buffer size & length |
380 |
|
if (processed > 0) { |
381 |
|
memmove(inspector->buffer, inspector->buffer + processed, |
382 |
|
inspector->last_read_end - processed); |
383 |
|
inspector->last_read_end -= processed; |
384 |
|
inspector->data_len = inspector->last_read_end; |
385 |
|
} |
386 |
|
} while (processed > 0 && inspector->data_len > 0); |
387 |
|
} |
388 |
|
} |
389 |
|
|
390 |
|
int inspector_read_start(inspector_socket_t* inspector, |
391 |
|
uv_alloc_cb alloc_cb, uv_read_cb read_cb) { |
392 |
|
ASSERT(inspector->ws_mode); |
393 |
|
ASSERT(!inspector->shutting_down || read_cb == nullptr); |
394 |
|
inspector->ws_state->close_sent = false; |
395 |
|
inspector->ws_state->alloc_cb = alloc_cb; |
396 |
|
inspector->ws_state->read_cb = read_cb; |
397 |
|
int err = |
398 |
|
uv_read_start(reinterpret_cast<uv_stream_t*>(&inspector->client), |
399 |
|
prepare_buffer, |
400 |
|
websockets_data_cb); |
401 |
|
if (err < 0) { |
402 |
|
close_connection(inspector); |
403 |
|
} |
404 |
|
return err; |
405 |
|
} |
406 |
|
|
407 |
|
void inspector_read_stop(inspector_socket_t* inspector) { |
408 |
|
uv_read_stop(reinterpret_cast<uv_stream_t*>(&inspector->client)); |
409 |
|
inspector->ws_state->alloc_cb = nullptr; |
410 |
|
inspector->ws_state->read_cb = nullptr; |
411 |
|
} |
412 |
|
|
413 |
|
static void generate_accept_string(const char* client_key, char* buffer) { |
414 |
|
// Magic string from websockets spec. |
415 |
|
const char ws_magic[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; |
416 |
|
size_t key_len = strlen(client_key); |
417 |
|
size_t magic_len = sizeof(ws_magic) - 1; |
418 |
|
|
419 |
|
char* buf = reinterpret_cast<char*>(malloc(key_len + magic_len)); |
420 |
|
CHECK_NE(buf, nullptr); |
421 |
|
memcpy(buf, client_key, key_len); |
422 |
|
memcpy(buf + key_len, ws_magic, magic_len); |
423 |
|
char hash[20]; |
424 |
|
SHA1((unsigned char*) buf, key_len + magic_len, (unsigned char*) hash); |
425 |
|
free(buf); |
426 |
|
node::base64_encode(hash, 20, buffer, ACCEPT_KEY_LENGTH); |
427 |
|
buffer[ACCEPT_KEY_LENGTH] = '\0'; |
428 |
|
} |
429 |
|
|
430 |
|
static void append(char** value, const char* string, size_t length) { |
431 |
|
const size_t INCREMENT = 500; // There should never be more then 1 chunk... |
432 |
|
|
433 |
|
int current_len = *value ? strlen(*value) : 0; |
434 |
|
int new_len = current_len + length; |
435 |
|
int adjusted = (new_len / INCREMENT + 1) * INCREMENT; |
436 |
|
*value = reinterpret_cast<char*>(realloc(*value, adjusted)); |
437 |
|
memcpy(*value + current_len, string, length); |
438 |
|
(*value)[new_len] = '\0'; |
439 |
|
} |
440 |
|
|
441 |
|
static int header_value_cb(http_parser* parser, const char* at, size_t length) { |
442 |
|
char SEC_WEBSOCKET_KEY_HEADER[] = "Sec-WebSocket-Key"; |
443 |
|
struct http_parsing_state_s* state = (struct http_parsing_state_s*) |
444 |
|
(reinterpret_cast<inspector_socket_t*>(parser->data))->http_parsing_state; |
445 |
|
state->parsing_value = true; |
446 |
|
if (state->current_header && |
447 |
|
node::StringEqualNoCaseN(state->current_header, |
448 |
|
SEC_WEBSOCKET_KEY_HEADER, |
449 |
|
sizeof(SEC_WEBSOCKET_KEY_HEADER))) { |
450 |
|
append(&state->ws_key, at, length); |
451 |
|
} |
452 |
|
return 0; |
453 |
|
} |
454 |
|
|
455 |
|
static int header_field_cb(http_parser* parser, const char* at, size_t length) { |
456 |
|
struct http_parsing_state_s* state = (struct http_parsing_state_s*) |
457 |
|
(reinterpret_cast<inspector_socket_t*>(parser->data))->http_parsing_state; |
458 |
|
if (state->parsing_value) { |
459 |
|
state->parsing_value = false; |
460 |
|
if (state->current_header) |
461 |
|
state->current_header[0] = '\0'; |
462 |
|
} |
463 |
|
append(&state->current_header, at, length); |
464 |
|
return 0; |
465 |
|
} |
466 |
|
|
467 |
|
static int path_cb(http_parser* parser, const char* at, size_t length) { |
468 |
|
struct http_parsing_state_s* state = (struct http_parsing_state_s*) |
469 |
|
(reinterpret_cast<inspector_socket_t*>(parser->data))->http_parsing_state; |
470 |
|
append(&state->path, at, length); |
471 |
|
return 0; |
472 |
|
} |
473 |
|
|
474 |
|
static void handshake_complete(inspector_socket_t* inspector) { |
475 |
|
uv_read_stop(reinterpret_cast<uv_stream_t*>(&inspector->client)); |
476 |
|
handshake_cb callback = inspector->http_parsing_state->callback; |
477 |
|
inspector->ws_state = (struct ws_state_s*) malloc(sizeof(struct ws_state_s)); |
478 |
|
ASSERT_NE(nullptr, inspector->ws_state); |
479 |
|
memset(inspector->ws_state, 0, sizeof(struct ws_state_s)); |
480 |
|
inspector->last_read_end = 0; |
481 |
|
inspector->ws_mode = true; |
482 |
|
callback(inspector, kInspectorHandshakeUpgraded, |
483 |
|
inspector->http_parsing_state->path); |
484 |
|
} |
485 |
|
|
486 |
|
static void cleanup_http_parsing_state(inspector_socket_t* inspector) { |
487 |
|
struct http_parsing_state_s* state = inspector->http_parsing_state; |
488 |
|
free(state->current_header); |
489 |
|
free(state->path); |
490 |
|
free(state->ws_key); |
491 |
|
free(state); |
492 |
|
inspector->http_parsing_state = nullptr; |
493 |
|
} |
494 |
|
|
495 |
|
static void report_handshake_failure_cb(uv_handle_t* handle) { |
496 |
|
dispose_inspector(handle); |
497 |
|
inspector_socket_t* inspector = |
498 |
|
static_cast<inspector_socket_t*>(handle->data); |
499 |
|
handshake_cb cb = inspector->http_parsing_state->callback; |
500 |
|
cleanup_http_parsing_state(inspector); |
501 |
|
cb(inspector, kInspectorHandshakeFailed, nullptr); |
502 |
|
} |
503 |
|
|
504 |
|
static void close_and_report_handshake_failure(inspector_socket_t* inspector) { |
505 |
|
uv_handle_t* socket = reinterpret_cast<uv_handle_t*>(&inspector->client); |
506 |
|
if (uv_is_closing(socket)) { |
507 |
|
report_handshake_failure_cb(socket); |
508 |
|
} else { |
509 |
|
uv_read_stop(reinterpret_cast<uv_stream_t*>(socket)); |
510 |
|
uv_close(socket, report_handshake_failure_cb); |
511 |
|
} |
512 |
|
} |
513 |
|
|
514 |
|
static void handshake_failed(inspector_socket_t* inspector) { |
515 |
|
const char HANDSHAKE_FAILED_RESPONSE[] = |
516 |
|
"HTTP/1.0 400 Bad Request\r\n" |
517 |
|
"Content-Type: text/html; charset=UTF-8\r\n\r\n" |
518 |
|
"WebSockets request was expected\r\n"; |
519 |
|
write_to_client(inspector, HANDSHAKE_FAILED_RESPONSE, |
520 |
|
sizeof(HANDSHAKE_FAILED_RESPONSE) - 1); |
521 |
|
close_and_report_handshake_failure(inspector); |
522 |
|
} |
523 |
|
|
524 |
|
// init_handshake references message_complete_cb |
525 |
|
static void init_handshake(inspector_socket_t* inspector); |
526 |
|
|
527 |
|
static int message_complete_cb(http_parser* parser) { |
528 |
|
inspector_socket_t* inspector = |
529 |
|
reinterpret_cast<inspector_socket_t*>(parser->data); |
530 |
|
struct http_parsing_state_s* state = |
531 |
|
(struct http_parsing_state_s*) inspector->http_parsing_state; |
532 |
|
if (parser->method != HTTP_GET) { |
533 |
|
handshake_failed(inspector); |
534 |
|
} else if (!parser->upgrade) { |
535 |
|
if (state->callback(inspector, kInspectorHandshakeHttpGet, state->path)) { |
536 |
|
init_handshake(inspector); |
537 |
|
} else { |
538 |
|
handshake_failed(inspector); |
539 |
|
} |
540 |
|
} else if (!state->ws_key) { |
541 |
|
handshake_failed(inspector); |
542 |
|
} else if (state->callback(inspector, kInspectorHandshakeUpgrading, |
543 |
|
state->path)) { |
544 |
|
char accept_string[ACCEPT_KEY_LENGTH + 1]; |
545 |
|
generate_accept_string(state->ws_key, accept_string); |
546 |
|
|
547 |
|
const char accept_ws_prefix[] = "HTTP/1.1 101 Switching Protocols\r\n" |
548 |
|
"Upgrade: websocket\r\n" |
549 |
|
"Connection: Upgrade\r\n" |
550 |
|
"Sec-WebSocket-Accept: "; |
551 |
|
const char accept_ws_suffix[] = "\r\n\r\n"; |
552 |
|
// Format has two chars (%s) that are replaced with actual key |
553 |
|
char accept_response[sizeof(accept_ws_prefix) - 1 + |
554 |
|
sizeof(accept_ws_suffix) - 1 + |
555 |
|
ACCEPT_KEY_LENGTH]; |
556 |
|
memcpy(accept_response, accept_ws_prefix, sizeof(accept_ws_prefix) - 1); |
557 |
|
memcpy(accept_response + sizeof(accept_ws_prefix) - 1, |
558 |
|
accept_string, ACCEPT_KEY_LENGTH); |
559 |
|
memcpy(accept_response + sizeof(accept_ws_prefix) - 1 + ACCEPT_KEY_LENGTH, |
560 |
|
accept_ws_suffix, sizeof(accept_ws_suffix) - 1); |
561 |
|
int len = sizeof(accept_response); |
562 |
|
if (write_to_client(inspector, accept_response, len) >= 0) { |
563 |
|
handshake_complete(inspector); |
564 |
|
inspector->http_parsing_state->done = true; |
565 |
|
} else { |
566 |
|
close_and_report_handshake_failure(inspector); |
567 |
|
} |
568 |
|
} else { |
569 |
|
handshake_failed(inspector); |
570 |
|
} |
571 |
|
return 0; |
572 |
|
} |
573 |
|
|
574 |
|
static void data_received_cb(uv_stream_s* client, ssize_t nread, |
575 |
|
const uv_buf_t* buf) { |
576 |
|
#if DUMP_READS |
577 |
|
if (nread >= 0) { |
578 |
|
printf("%s (%ld bytes)\n", __FUNCTION__, nread); |
579 |
|
dump_hex(buf->base, nread); |
580 |
|
} else { |
581 |
|
printf("[%s:%d] %s\n", __FUNCTION__, __LINE__, uv_err_name(nread)); |
582 |
|
} |
583 |
|
#endif |
584 |
|
inspector_socket_t* inspector = |
585 |
|
reinterpret_cast<inspector_socket_t*>((client->data)); |
586 |
|
if (nread < 0 || nread == UV_EOF) { |
587 |
|
close_and_report_handshake_failure(inspector); |
588 |
|
} else { |
589 |
|
http_parsing_state_s* state = inspector->http_parsing_state; |
590 |
|
http_parser* parser = &state->parser; |
591 |
|
http_parser_execute(parser, &state->parser_settings, inspector->buffer, |
592 |
|
nread); |
593 |
|
if (parser->http_errno != HPE_OK) { |
594 |
|
handshake_failed(inspector); |
595 |
|
} |
596 |
|
if (inspector->http_parsing_state->done) { |
597 |
|
cleanup_http_parsing_state(inspector); |
598 |
|
} |
599 |
|
inspector->data_len = 0; |
600 |
|
} |
601 |
|
} |
602 |
|
|
603 |
|
static void init_handshake(inspector_socket_t* inspector) { |
604 |
|
http_parsing_state_s* state = inspector->http_parsing_state; |
605 |
|
CHECK_NE(state, nullptr); |
606 |
|
if (state->current_header) { |
607 |
|
state->current_header[0] = '\0'; |
608 |
|
} |
609 |
|
if (state->ws_key) { |
610 |
|
state->ws_key[0] = '\0'; |
611 |
|
} |
612 |
|
if (state->path) { |
613 |
|
state->path[0] = '\0'; |
614 |
|
} |
615 |
|
state->done = false; |
616 |
|
http_parser_init(&state->parser, HTTP_REQUEST); |
617 |
|
state->parser.data = inspector; |
618 |
|
http_parser_settings* settings = &state->parser_settings; |
619 |
|
http_parser_settings_init(settings); |
620 |
|
settings->on_header_field = header_field_cb; |
621 |
|
settings->on_header_value = header_value_cb; |
622 |
|
settings->on_message_complete = message_complete_cb; |
623 |
|
settings->on_url = path_cb; |
624 |
|
} |
625 |
|
|
626 |
|
int inspector_accept(uv_stream_t* server, inspector_socket_t* inspector, |
627 |
|
handshake_cb callback) { |
628 |
|
ASSERT_NE(callback, nullptr); |
629 |
|
// The only field that users should care about. |
630 |
|
void* data = inspector->data; |
631 |
|
memset(inspector, 0, sizeof(*inspector)); |
632 |
|
inspector->data = data; |
633 |
|
|
634 |
|
inspector->http_parsing_state = (struct http_parsing_state_s*) |
635 |
|
malloc(sizeof(struct http_parsing_state_s)); |
636 |
|
ASSERT_NE(nullptr, inspector->http_parsing_state); |
637 |
|
memset(inspector->http_parsing_state, 0, sizeof(struct http_parsing_state_s)); |
638 |
|
uv_stream_t* client = reinterpret_cast<uv_stream_t*>(&inspector->client); |
639 |
|
CHECK_NE(client, nullptr); |
640 |
|
int err = uv_tcp_init(server->loop, &inspector->client); |
641 |
|
|
642 |
|
if (err == 0) { |
643 |
|
err = uv_accept(server, client); |
644 |
|
} |
645 |
|
if (err == 0) { |
646 |
|
client->data = inspector; |
647 |
|
init_handshake(inspector); |
648 |
|
inspector->http_parsing_state->callback = callback; |
649 |
|
err = uv_read_start(client, prepare_buffer, |
650 |
|
data_received_cb); |
651 |
|
} |
652 |
|
if (err != 0) { |
653 |
|
uv_close(reinterpret_cast<uv_handle_t*>(client), NULL); |
654 |
|
} |
655 |
|
return err; |
656 |
|
} |
657 |
|
|
658 |
|
void inspector_write(inspector_socket_t* inspector, const char* data, |
659 |
|
size_t len) { |
660 |
|
if (inspector->ws_mode) { |
661 |
|
std::vector<char> output = encode_frame_hybi17(data, len); |
662 |
|
write_to_client(inspector, &output[0], output.size()); |
663 |
|
} else { |
664 |
|
write_to_client(inspector, data, len); |
665 |
|
} |
666 |
|
} |
667 |
|
|
668 |
|
void inspector_close(inspector_socket_t* inspector, |
669 |
|
inspector_cb callback) { |
670 |
|
// libuv throws assertions when closing stream that's already closed - we |
671 |
|
// need to do the same. |
672 |
|
ASSERT(!uv_is_closing(reinterpret_cast<uv_handle_t*>(&inspector->client))); |
673 |
|
ASSERT(!inspector->shutting_down); |
674 |
|
inspector->shutting_down = true; |
675 |
|
inspector->ws_state->close_cb = callback; |
676 |
|
if (inspector->connection_eof) { |
677 |
|
close_connection(inspector); |
678 |
|
} else { |
679 |
|
inspector_read_stop(inspector); |
680 |
|
write_to_client(inspector, CLOSE_FRAME, sizeof(CLOSE_FRAME), |
681 |
|
on_close_frame_written); |
682 |
|
inspector_read_start(inspector, nullptr, nullptr); |
683 |
|
} |
684 |
|
} |
685 |
|
|
686 |
|
bool inspector_is_active(const struct inspector_socket_s* inspector) { |
687 |
|
const uv_handle_t* client = |
688 |
|
reinterpret_cast<const uv_handle_t*>(&inspector->client); |
689 |
|
return !inspector->shutting_down && !uv_is_closing(client); |
690 |
|
} |