Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/inspector_socket.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include <string.h>
#include <vector>

#define ACCEPT_KEY_LENGTH 28 // SHA1 has is 20 bytes, 28 in base64
#define ACCEPT_KEY_LENGTH base64_encoded_size(20)
#define BUFFER_GROWTH_CHUNK_SIZE 1024

#define DUMP_READS 0
Expand Down Expand Up @@ -326,7 +326,7 @@ static int parse_ws_frames(inspector_socket_t* inspector, size_t len) {
inspector->ws_state->alloc_cb(
reinterpret_cast<uv_handle_t*>(&inspector->client),
len, &buffer);
CHECK_GE(len, buffer.len);
CHECK_GE(buffer.len, len);
memcpy(buffer.base, &output[0], len);
invoke_read_callback(inspector, len, &buffer);
}
Expand Down
180 changes: 114 additions & 66 deletions test/cctest/test_inspector_socket.cc
Original file line number Diff line number Diff line change
Expand Up @@ -130,27 +130,6 @@ static void check_data_cb(uv_stream_t *stream, ssize_t nread,
}
}

static void inspector_check_data_cb(uv_stream_t *stream, ssize_t nread,
const uv_buf_t *buf) {
inspector_socket_t *inspector = (inspector_socket_t *)stream->data;
const char *expectation = (const char *)inspector->data;
if (nread <= 0) {
EXPECT_EQ(expectation, nullptr);
return;
} else {
const char* actual = (const char *)buf->base;
const size_t expected_len = strlen(expectation);
for (size_t i = 0; i < expected_len; i++) {
if (expectation[i] != actual[i]) {
fprintf(stderr, "At position %ld\n", i);
GTEST_ASSERT_EQ(expectation[i], actual[i]);
}
}
}
inspector->data = nullptr;
free(buf->base);
}

static read_expects prepare_expects(const char *data, size_t len) {
read_expects expectation;
expectation.expected = data;
Expand Down Expand Up @@ -186,10 +165,87 @@ static void expect_on_client(const char *data, size_t len) {
SPIN_WHILE(!expectation.read_expected);
}

struct expectations {
char* actual_data;
size_t actual_offset;
size_t actual_end;
int err_code;
};

static void grow_expects_buffer(uv_handle_t* stream, size_t size, uv_buf_t* b) {
expectations* expects =
(expectations*) ((inspector_socket_t*) stream->data)->data;
size_t end = expects->actual_end;
// Grow the buffer in chunks of 64k.
size_t new_length = (end + size + 65535) & ~((size_t) 0xFFFF);
expects->actual_data = (char*) realloc(expects->actual_data, new_length);
*b = uv_buf_init(expects->actual_data + end, new_length - end);
}

// static void dump_hex(const char* buf, size_t len) {
// const char* ptr = buf;
// const char* end = ptr + len;
// const char* cptr;
// char c;
// int i;

// while (ptr < end) {
// cptr = ptr;
// for (i = 0; i < 16 && ptr < end; i++) {
// printf("%2.2X ", *(ptr++));
// }
// for (i = 72 - (i * 4); i > 0; i--) {
// printf(" ");
// }
// for (i = 0; i < 16 && cptr < end; i++) {
// c = *(cptr++);
// printf("%c", (c > 0x19) ? c : '.');
// }
// printf("\n");
// }
// printf("\n\n");
// }

static void save_read_data(uv_stream_t* stream, ssize_t nread,
const uv_buf_t* buf) {
expectations* expects =
(expectations*) ((inspector_socket_t*) stream->data)->data;
expects->err_code = nread < 0 ? nread : 0;
if (nread > 0) {
expects->actual_end += nread;
}
}

static void setup_inspector_expecting() {
if (inspector.data) {
return;
}
expectations* expects = (expectations*) malloc(sizeof(*expects));
memset(expects, 0, sizeof(*expects));
inspector.data = expects;
inspector_read_start(&inspector, grow_expects_buffer, save_read_data);
}

static void expect_on_server(const char *data, size_t len) {
inspector.data = (void *)data;
inspector_read_start(&inspector, buffer_alloc_cb, inspector_check_data_cb);
SPIN_WHILE(inspector.data != nullptr)
setup_inspector_expecting();
expectations* expects = (expectations*) inspector.data;
for (size_t i = 0; i < len;) {
SPIN_WHILE(expects->actual_offset == expects->actual_end);
for (; i < len && expects->actual_offset < expects->actual_end; i++) {
char actual = expects->actual_data[expects->actual_offset++];
char expected = data[i];
if (expected != actual) {
fprintf(stderr, "Character %ld:\n", i);
GTEST_ASSERT_EQ(expected, actual);
}
}
}
expects->actual_end -= expects->actual_offset;
if (!expects->actual_end) {
memmove(expects->actual_data, expects->actual_data + expects->actual_offset,
expects->actual_end);
}
expects->actual_offset = 0;
}

static void inspector_record_error_code(uv_stream_t *stream, ssize_t nread,
Expand All @@ -200,12 +256,9 @@ static void inspector_record_error_code(uv_stream_t *stream, ssize_t nread,
}

static void expect_server_read_error() {
int error_code = 0;
inspector.data = &error_code;
inspector_read_start(&inspector, buffer_alloc_cb,
inspector_record_error_code);
SPIN_WHILE(error_code != UV_EPROTO);
GTEST_ASSERT_EQ(UV_EPROTO, error_code);
setup_inspector_expecting();
expectations* expects = (expectations*) inspector.data;
SPIN_WHILE(expects->err_code != UV_EPROTO);
}

static void expect_handshake() {
Expand Down Expand Up @@ -293,6 +346,14 @@ class InspectorSocketTest : public ::testing::Test {
uv_print_active_handles(&loop, stderr);
}
EXPECT_EQ(0, err);
expectations* expects = (expectations*) inspector.data;
if (expects != nullptr) {
GTEST_ASSERT_EQ(expects->actual_end, expects->actual_offset);
free(expects->actual_data);
expects->actual_data = nullptr;
free(expects);
inspector.data = nullptr;
}
}
};

Expand Down Expand Up @@ -324,18 +385,6 @@ TEST_F(InspectorSocketTest, ReadsAndWritesInspectorMessage) {
GTEST_ASSERT_EQ(0, uv_is_active((uv_handle_t *)&client_socket));
}

void expect_data(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) {
inspector_socket_t *inspector = (inspector_socket_t *)stream->data;
const char **next_line = (const char **)inspector->data;
char *actual_line = (char*) malloc(nread + 1);
memcpy(actual_line, buf->base, nread);
actual_line[nread] = '\0';
EXPECT_STREQ(*next_line, actual_line);
inspector->data = next_line + 1;
free(buf->base);
free(actual_line);
}

TEST_F(InspectorSocketTest, BufferEdgeCases) {

do_write((char *)HANDSHAKE_REQ, sizeof(HANDSHAKE_REQ) - 1);
Expand Down Expand Up @@ -383,21 +432,18 @@ TEST_F(InspectorSocketTest, BufferEdgeCases) {
'\x75', '\x84', '\x8F', '\x15', '\x6E', '\x83', '\x84', '\x12', '\x69',
'\xC8', '\x96'};

const char *EXPECT[] = {
const char EXPECT[] = {
"{\"id\":12,\"method\":\"Worker.setAutoconnectToWorkers\","
"\"params\":{\"value\":true}}",
"{\"id\":13,\"method\":\"Worker.enable\"}",
"{\"id\":14,\"method\":\"Profiler.enable\"}",
"\"params\":{\"value\":true}}"
"{\"id\":13,\"method\":\"Worker.enable\"}"
"{\"id\":14,\"method\":\"Profiler.enable\"}"
"{\"id\":15,\"method\":\"Profiler.setSamplingInterval\","
"\"params\":{\"interval\":100}}",
"{\"id\":16,\"method\":\"ServiceWorker.enable\"}",
"{\"id\":17,\"method\":\"Network.canEmulateNetworkConditions\"}",
nullptr};
"\"params\":{\"interval\":100}}"
"{\"id\":16,\"method\":\"ServiceWorker.enable\"}"
"{\"id\":17,\"method\":\"Network.canEmulateNetworkConditions\"}"};

do_write(MULTIPLE_REQUESTS, sizeof(MULTIPLE_REQUESTS));
inspector.data = EXPECT;
inspector_read_start(&inspector, buffer_alloc_cb, expect_data);
SPIN_WHILE(*((char **)inspector.data) != nullptr);
expect_on_server(EXPECT, sizeof(EXPECT) - 1);
inspector_read_stop(&inspector);
manual_inspector_socket_cleanup();
}
Expand All @@ -423,10 +469,10 @@ TEST_F(InspectorSocketTest, AcceptsRequestInSeveralWrites) {
}

TEST_F(InspectorSocketTest, ExtraTextBeforeRequest) {
last_event = kInspectorHandshakeUpgraded;
char UNCOOL_BRO[] = "Uncool, bro: Text before the first req\r\n";
do_write((char *)UNCOOL_BRO, sizeof(UNCOOL_BRO) - 1);

last_event = kInspectorHandshakeUpgraded;
ASSERT_FALSE(inspector_ready);
do_write((char *)HANDSHAKE_REQ, sizeof(HANDSHAKE_REQ) - 1);
SPIN_WHILE(last_event != kInspectorHandshakeFailed);
Expand Down Expand Up @@ -519,6 +565,7 @@ TEST_F(InspectorSocketTest, CloseDoesNotNotifyReadCallback) {
do_write(CLIENT_CLOSE_FRAME, sizeof(CLIENT_CLOSE_FRAME));
EXPECT_NE(UV_EOF, error_code);
SPIN_WHILE(!inspector_closed);
inspector.data = nullptr;
}

TEST_F(InspectorSocketTest, CloseWorksWithoutReadEnabled) {
Expand Down Expand Up @@ -720,6 +767,7 @@ TEST_F(InspectorSocketTest, CleanupSocketAfterEOF) {
bool flag = false;
inspector.data = &flag;
SPIN_WHILE(!flag);
inspector.data = nullptr;
}

TEST_F(InspectorSocketTest, EOFBeforeHandshake) {
Expand Down Expand Up @@ -779,22 +827,22 @@ TEST_F(InspectorSocketTest, Send1Mb) {
'\x42', '\x40', MASK[0], MASK[1], MASK[2], MASK[3]
};

char *outgoing = (char*) malloc(sizeof(FRAME_TO_SERVER_HEADER) + message_len);
const size_t outgoing_len = sizeof(FRAME_TO_SERVER_HEADER) + message_len;
char *outgoing = (char*) malloc(outgoing_len);
memcpy(outgoing, FRAME_TO_SERVER_HEADER, sizeof(FRAME_TO_SERVER_HEADER));
mask_message(message, outgoing + sizeof(FRAME_TO_SERVER_HEADER), MASK);

// do_write(FRAME_TO_SERVER, sizeof(FRAME_TO_SERVER));
// expect_on_server(LONG_MESSAGE, sizeof(LONG_MESSAGE));

// // 3. Close
// const char CLIENT_CLOSE_FRAME[] = {'\x88', '\x80', '\x2D',
// '\x0E', '\x1E', '\xFA'};
// const char SERVER_CLOSE_FRAME[] = {'\x88', '\x00'};
// do_write(CLIENT_CLOSE_FRAME, sizeof(CLIENT_CLOSE_FRAME));
// expect_on_client(SERVER_CLOSE_FRAME, sizeof(SERVER_CLOSE_FRAME));
// GTEST_ASSERT_EQ(0, uv_is_active((uv_handle_t *)&client_socket));
manual_inspector_socket_cleanup();
setup_inspector_expecting(); // Buffer on the client side.
do_write(outgoing, outgoing_len);
expect_on_server(message, message_len);

// 3. Close
const char CLIENT_CLOSE_FRAME[] = {'\x88', '\x80', '\x2D',
'\x0E', '\x1E', '\xFA'};
const char SERVER_CLOSE_FRAME[] = {'\x88', '\x00'};
do_write(CLIENT_CLOSE_FRAME, sizeof(CLIENT_CLOSE_FRAME));
expect_on_client(SERVER_CLOSE_FRAME, sizeof(SERVER_CLOSE_FRAME));
GTEST_ASSERT_EQ(0, uv_is_active((uv_handle_t *)&client_socket));
free(outgoing);
free(expected);
free(message);
Expand Down