Explorar o código

Add helper funktion for mask_data and enhance test for websocket clients

bel %!s(int64=9) %!d(string=hai) anos
pai
achega
641a742128
Modificáronse 5 ficheiros con 100 adicións e 48 borrados
  1. 30 21
      src/civetweb.c
  2. 0 1
      src/main.c
  3. 2 1
      test/CMakeLists.txt
  4. 36 0
      test/private.c
  5. 32 25
      test/public_server.c

+ 30 - 21
src/civetweb.c

@@ -8198,6 +8198,34 @@ mg_websocket_write(struct mg_connection *conn,
 	return mg_websocket_write_exec(conn, opcode, data, dataLen, 0);
 	return mg_websocket_write_exec(conn, opcode, data, dataLen, 0);
 }
 }
 
 
+
+static void
+mask_data(const char *in, size_t in_len, uint32_t masking_key, char *out)
+{
+	size_t i = 0;
+
+	i = 0;
+	if (((ptrdiff_t)in % 4) == 0) {
+		/* Convert in 32 bit words, if data is 4 byte aligned */
+		while (i < (in_len - 3)) {
+			*(uint32_t *)(void *)(out + i) =
+			    *(uint32_t *)(void *)(in + i) ^ masking_key;
+			i += 4;
+		}
+	}
+	if (i != in_len) {
+		/* convert 1-3 remaining bytes if ((dataLen % 4) != 0)*/
+		while (i < in_len) {
+			*(uint8_t *)(void *)(out + i) =
+			    *(uint8_t *)(void *)(in + i)
+			    ^ *(((uint8_t *)&masking_key) + (i % 4));
+			i++;
+		}
+	}
+	/* TODO (high): Deal with ((dataLen % 4) != 0) and misalignment */
+}
+
+
 int
 int
 mg_websocket_client_write(struct mg_connection *conn,
 mg_websocket_client_write(struct mg_connection *conn,
                           int opcode,
                           int opcode,
@@ -8205,7 +8233,6 @@ mg_websocket_client_write(struct mg_connection *conn,
                           size_t dataLen)
                           size_t dataLen)
 {
 {
 	int retval = -1;
 	int retval = -1;
-	size_t i = 0;
 	char *masked_data = (char *)mg_malloc(((dataLen + 7) / 4) * 4);
 	char *masked_data = (char *)mg_malloc(((dataLen + 7) / 4) * 4);
 	uint32_t masking_key;
 	uint32_t masking_key;
 	static uint64_t lfsr = 0;
 	static uint64_t lfsr = 0;
@@ -8237,26 +8264,8 @@ mg_websocket_client_write(struct mg_connection *conn,
 		return -1;
 		return -1;
 	}
 	}
 
 
-	i = 0;
-	if (((ptrdiff_t)data % 4) == 0) {
-		/* Convert in 32 bit words, if data is 4 byte aligned */
-		while (i < (dataLen - 3)) {
-			*(uint32_t *)(void *)(masked_data + i) =
-			    *(uint32_t *)(void *)(data + i) ^ masking_key;
-			i += 4;
-		}
-	}
-	if (i != dataLen) {
-		/* convert 1-3 remaining bytes if ((dataLen % 4) != 0)*/
-		i -= 4;
-		while (i < dataLen) {
-			*(uint8_t *)(void *)(masked_data + i) =
-			    *(uint8_t *)(void *)(data + i)
-			    ^ *(((uint8_t *)&masking_key) + (i % 4));
-			i++;
-		}
-	}
-	/* TODO (high): Deal with ((dataLen % 4) != 0) and misalignment */
+	mask_data(data, dataLen, masking_key, masked_data);
+
 	retval = mg_websocket_write_exec(
 	retval = mg_websocket_write_exec(
 	    conn, opcode, masked_data, dataLen, masking_key);
 	    conn, opcode, masked_data, dataLen, masking_key);
 	mg_free(masked_data);
 	mg_free(masked_data);

+ 0 - 1
src/main.c

@@ -974,7 +974,6 @@ start_civetweb(int argc, char *argv[])
 	/* Call Duktape, if -E option is specified */
 	/* Call Duktape, if -E option is specified */
 	if (argc > 1 && !strcmp(argv[1], "-E")) {
 	if (argc > 1 && !strcmp(argv[1], "-E")) {
 
 
-		fprintf(stdout, "asd\n");
 #ifdef USE_DUKTAPE
 #ifdef USE_DUKTAPE
 		if (argc != 3) {
 		if (argc != 3) {
 			show_usage_and_exit(argv[0]);
 			show_usage_and_exit(argv[0]);

+ 2 - 1
test/CMakeLists.txt

@@ -126,11 +126,12 @@ macro(civetweb_add_test suite test_case)
 endmacro(civetweb_add_test)
 endmacro(civetweb_add_test)
 
 
 
 
-# Private API tests
+# Tests of private functions
 civetweb_add_test(Private "HTTP Message")
 civetweb_add_test(Private "HTTP Message")
 civetweb_add_test(Private "URL Parsing")
 civetweb_add_test(Private "URL Parsing")
 civetweb_add_test(Private "Internal Parsing")
 civetweb_add_test(Private "Internal Parsing")
 civetweb_add_test(Private "Encode Decode")
 civetweb_add_test(Private "Encode Decode")
+civetweb_add_test(Private "Mask Data")
 
 
 # Public API function tests
 # Public API function tests
 civetweb_add_test(PublicFunc "Version")
 civetweb_add_test(PublicFunc "Version")

+ 36 - 0
test/private.c

@@ -456,6 +456,37 @@ START_TEST(test_encode_decode)
 }
 }
 END_TEST
 END_TEST
 
 
+
+START_TEST(test_mask_data)
+{
+	char in[1024];
+	char out[1024];
+	char zero[1024];
+	int i;
+
+	memset(in, 0, sizeof(in));
+	memset(out, 99, sizeof(out));
+
+	mask_data(in, sizeof(out), 0, out);
+	ck_assert(!memcmp(out, in, sizeof(out)));
+
+	for (i = 0; i < 1024; i++) {
+		in[i] = (char)((unsigned char)i);
+	}
+	mask_data(in, 107, 0, out);
+	ck_assert(!memcmp(out, in, 107));
+
+	mask_data(in, 256, 0x01010101, out);
+	for (i = 0; i < 256; i++) {
+		ch_assert_int_eq((int)out[i], (int)(((unsigned char)in[i]) ^ (char)1u));
+	}
+	for (i = 256; i < sizeof(out)) {
+		ch_assert_int_eq((int)out[i], (int)0);
+	}
+}
+END_TEST
+
+
 Suite *
 Suite *
 make_private_suite(void)
 make_private_suite(void)
 {
 {
@@ -465,6 +496,7 @@ make_private_suite(void)
 	TCase *const url_parsing = tcase_create("URL Parsing");
 	TCase *const url_parsing = tcase_create("URL Parsing");
 	TCase *const internal_parse = tcase_create("Internal Parsing");
 	TCase *const internal_parse = tcase_create("Internal Parsing");
 	TCase *const encode_decode = tcase_create("Encode Decode");
 	TCase *const encode_decode = tcase_create("Encode Decode");
+	TCase *const mask_data = tcase_create("Mask Data");
 
 
 	tcase_add_test(http_message, test_parse_http_message);
 	tcase_add_test(http_message, test_parse_http_message);
 	tcase_add_test(http_message, test_should_keep_alive);
 	tcase_add_test(http_message, test_should_keep_alive);
@@ -489,5 +521,9 @@ make_private_suite(void)
 	tcase_set_timeout(encode_decode, civetweb_min_test_timeout);
 	tcase_set_timeout(encode_decode, civetweb_min_test_timeout);
 	suite_add_tcase(suite, encode_decode);
 	suite_add_tcase(suite, encode_decode);
 
 
+	tcase_add_test(mask_data, test_mask_data);
+	tcase_set_timeout(mask_data, civetweb_min_test_timeout);
+	suite_add_tcase(suite, mask_data);
+
 	return suite;
 	return suite;
 }
 }

+ 32 - 25
test/public_server.c

@@ -100,6 +100,7 @@ wait_not_null(void *volatile *data)
 			return 1;
 			return 1;
 		}
 		}
 	}
 	}
+	ck_abort_msg("wait_not_null failed");
 	return 0;
 	return 0;
 }
 }
 
 
@@ -547,9 +548,6 @@ request_test_handler(struct mg_connection *conn, void *cbdata)
 static const char *websocket_welcome_msg = "websocket welcome\n";
 static const char *websocket_welcome_msg = "websocket welcome\n";
 static const size_t websocket_welcome_msg_len =
 static const size_t websocket_welcome_msg_len =
     18 /* strlen(websocket_welcome_msg) */;
     18 /* strlen(websocket_welcome_msg) */;
-static const char *websocket_acknowledge_msg = "websocket msg ok\n";
-static const size_t websocket_acknowledge_msg_len =
-    17 /* strlen(websocket_acknowledge_msg) */;
 static const char *websocket_goodbye_msg = "websocket bye\n";
 static const char *websocket_goodbye_msg = "websocket bye\n";
 static const size_t websocket_goodbye_msg_len =
 static const size_t websocket_goodbye_msg_len =
     14 /* strlen(websocket_goodbye_msg) */;
     14 /* strlen(websocket_goodbye_msg) */;
@@ -594,22 +592,29 @@ websock_server_data(struct mg_connection *conn,
 	ck_assert_ptr_eq((void *)udata, (void *)7531);
 	ck_assert_ptr_eq((void *)udata, (void *)7531);
 	printf("Server: Got %u bytes from the client\n", (unsigned)data_len);
 	printf("Server: Got %u bytes from the client\n", (unsigned)data_len);
 
 
-	if (data_len < 3 || 0 != memcmp(data, "bye", 3)) {
-		/* Send websocket acknowledge message */
-		mg_lock_connection(conn);
-		mg_websocket_write(conn,
-		                   WEBSOCKET_OPCODE_TEXT,
-		                   websocket_acknowledge_msg,
-		                   websocket_acknowledge_msg_len);
-		mg_unlock_connection(conn);
-	} else {
-		/* Send websocket acknowledge message */
+	if (data_len == 3 && !memcmp(data, "bye", 3)) {
+		/* Send websocket goodbye message */
 		mg_lock_connection(conn);
 		mg_lock_connection(conn);
 		mg_websocket_write(conn,
 		mg_websocket_write(conn,
 		                   WEBSOCKET_OPCODE_TEXT,
 		                   WEBSOCKET_OPCODE_TEXT,
 		                   websocket_goodbye_msg,
 		                   websocket_goodbye_msg,
 		                   websocket_goodbye_msg_len);
 		                   websocket_goodbye_msg_len);
 		mg_unlock_connection(conn);
 		mg_unlock_connection(conn);
+	} else if (data_len == 5 && !memcmp(data, "data1", 5)) {
+		mg_lock_connection(conn);
+		mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, "ok1", 3);
+		mg_unlock_connection(conn);
+	} else if (data_len == 5 && !memcmp(data, "data2", 5)) {
+		mg_lock_connection(conn);
+		mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, "ok 2", 4);
+		mg_unlock_connection(conn);
+	} else if (data_len == 5 && !memcmp(data, "data3", 5)) {
+		mg_lock_connection(conn);
+		mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, "ok - 3", 6);
+		mg_unlock_connection(conn);
+	} else {
+		ck_abort_msg("Got unexpected message from websocket client");
+		return 0;
 	}
 	}
 
 
 	return 1; /* return 1 to keep the connetion open */
 	return 1; /* return 1 to keep the connetion open */
@@ -1105,7 +1110,10 @@ START_TEST(test_request_handlers)
 	ws_client1_data.data = NULL;
 	ws_client1_data.data = NULL;
 	ws_client1_data.len = 0;
 	ws_client1_data.len = 0;
 
 
-	mg_websocket_write(ws_client1_conn, WEBSOCKET_OPCODE_TEXT, "data1", 5);
+	mg_websocket_client_write(ws_client1_conn,
+	                          WEBSOCKET_OPCODE_TEXT,
+	                          "data1",
+	                          5);
 
 
 	wait_not_null(
 	wait_not_null(
 	    &(ws_client1_data
 	    &(ws_client1_data
@@ -1115,10 +1123,8 @@ START_TEST(test_request_handlers)
 	ck_assert(ws_client2_data.data == NULL);
 	ck_assert(ws_client2_data.data == NULL);
 	ck_assert_uint_eq(ws_client2_data.len, 0);
 	ck_assert_uint_eq(ws_client2_data.len, 0);
 	ck_assert(ws_client1_data.data != NULL);
 	ck_assert(ws_client1_data.data != NULL);
-	ck_assert_uint_eq(ws_client1_data.len, websocket_acknowledge_msg_len);
-	ck_assert(!memcmp(ws_client1_data.data,
-	                  websocket_acknowledge_msg,
-	                  websocket_acknowledge_msg_len));
+	ck_assert_uint_eq(ws_client1_data.len, 3);
+	ck_assert(!memcmp(ws_client1_data.data, "ok1", 3));
 	free(ws_client1_data.data);
 	free(ws_client1_data.data);
 	ws_client1_data.data = NULL;
 	ws_client1_data.data = NULL;
 	ws_client1_data.len = 0;
 	ws_client1_data.len = 0;
@@ -1166,7 +1172,10 @@ START_TEST(test_request_handlers)
 	ws_client2_data.data = NULL;
 	ws_client2_data.data = NULL;
 	ws_client2_data.len = 0;
 	ws_client2_data.len = 0;
 
 
-	mg_websocket_write(ws_client1_conn, WEBSOCKET_OPCODE_TEXT, "data2", 5);
+	mg_websocket_client_write(ws_client1_conn,
+	                          WEBSOCKET_OPCODE_TEXT,
+	                          "data2",
+	                          5);
 
 
 	wait_not_null(
 	wait_not_null(
 	    &(ws_client1_data
 	    &(ws_client1_data
@@ -1176,15 +1185,13 @@ START_TEST(test_request_handlers)
 	ck_assert(ws_client2_data.data == NULL);
 	ck_assert(ws_client2_data.data == NULL);
 	ck_assert(ws_client2_data.len == 0);
 	ck_assert(ws_client2_data.len == 0);
 	ck_assert(ws_client1_data.data != NULL);
 	ck_assert(ws_client1_data.data != NULL);
-	ck_assert(ws_client1_data.len == websocket_acknowledge_msg_len);
-	ck_assert(!memcmp(ws_client1_data.data,
-	                  websocket_acknowledge_msg,
-	                  websocket_acknowledge_msg_len));
+	ck_assert(ws_client1_data.len == 4);
+	ck_assert(!memcmp(ws_client1_data.data, "ok 2", 4));
 	free(ws_client1_data.data);
 	free(ws_client1_data.data);
 	ws_client1_data.data = NULL;
 	ws_client1_data.data = NULL;
 	ws_client1_data.len = 0;
 	ws_client1_data.len = 0;
 
 
-	mg_websocket_write(ws_client1_conn, WEBSOCKET_OPCODE_TEXT, "bye", 3);
+	mg_websocket_client_write(ws_client1_conn, WEBSOCKET_OPCODE_TEXT, "bye", 3);
 
 
 	wait_not_null(
 	wait_not_null(
 	    &(ws_client1_data.data)); /* Wait for the websocket goodbye message */
 	    &(ws_client1_data.data)); /* Wait for the websocket goodbye message */
@@ -1211,7 +1218,7 @@ START_TEST(test_request_handlers)
 	ck_assert(ws_client2_data.data == NULL);
 	ck_assert(ws_client2_data.data == NULL);
 	ck_assert(ws_client2_data.len == 0);
 	ck_assert(ws_client2_data.len == 0);
 
 
-	mg_websocket_write(ws_client2_conn, WEBSOCKET_OPCODE_TEXT, "bye", 3);
+	mg_websocket_client_write(ws_client2_conn, WEBSOCKET_OPCODE_TEXT, "bye", 3);
 
 
 	wait_not_null(
 	wait_not_null(
 	    &(ws_client2_data.data)); /* Wait for the websocket goodbye message */
 	    &(ws_client2_data.data)); /* Wait for the websocket goodbye message */