diff --git a/core/core.js b/core/core.js index 801f8b5c..0b736d18 100644 --- a/core/core.js +++ b/core/core.js @@ -1005,7 +1005,7 @@ loadSettings().then(function() { } }); httpd_impl.registerSocketHandler("/app/socket", app.socket); - httpd_impl.start(); + httpd_impl.start(tildefriends.http_port); }).catch(function(error) { print('Failed to load settings.'); printError({print: print}, error); diff --git a/core/httpd.js b/core/httpd.js index 6689a922..ab67ac0b 100644 --- a/core/httpd.js +++ b/core/httpd.js @@ -525,7 +525,6 @@ let kBacklog = 8; let kHost = platform() == 'haiku' ? 'localhost' : '::'; function start() { - print('ACTUAL START'); let socket = new Socket(); socket.bind(kHost, tildefriends.http_port).then(function(port) { print("bound to", port); diff --git a/src/http.c b/src/http.c index 72354a3f..43547789 100644 --- a/src/http.c +++ b/src/http.c @@ -8,6 +8,7 @@ #include "uv.h" #include +#include #include #include @@ -45,6 +46,7 @@ typedef struct _tf_http_connection_t void* user_data; bool is_websocket; + int websocket_message_index; void* body; size_t body_length; size_t content_length; @@ -134,7 +136,6 @@ static void _http_connection_destroy(tf_http_connection_t* connection, const cha { if (connection->tcp.data) { - tf_printf("CLOSE %p: %s\n", connection, reason); uv_close((uv_handle_t*)&connection->tcp, _http_connection_on_close); } else if (connection->ref_count == 0) @@ -171,6 +172,25 @@ static void _http_reset_connection(tf_http_connection_t* connection) connection->parsed_length = 0; } +static void _http_websocket_mask_in_place(uint8_t* p, uint32_t mask, size_t size) +{ + int i = 0; + for (; ((intptr_t)(p + i)) % alignof(uint32_t); i++) + { + p[i] ^= (mask & 0xff); + mask = ((mask >> 8) & 0xffffff) | ((mask & 0xff) << 24); + } + int aligned_start = i; + for (; i + 4 < (int)size; i += 4) + { + *(uint32_t*)(p + i) ^= mask; + } + for (; i < (int)size; i++) + { + p[i] ^= ((mask >> (8 * ((i - aligned_start) % 4))) & 0xff); + } +} + static void _http_add_body_bytes(tf_http_connection_t* connection, const void* data, size_t size) { if (connection->is_websocket) @@ -179,9 +199,9 @@ static void _http_add_body_bytes(tf_http_connection_t* connection, const void* d memcpy((char*)connection->body + connection->body_length, data, size); connection->body_length += size; - uint8_t* p = connection->body; while (connection->body_length >= 2) { + uint8_t* p = connection->body; uint8_t bits0 = p[0]; uint8_t bits1 = p[1]; if ((bits1 & (1 << 7)) == 0) @@ -190,7 +210,7 @@ static void _http_add_body_bytes(tf_http_connection_t* connection, const void* d _http_connection_destroy(connection, "websocket server received unmasked bytes"); return; } - uint8_t opcode = bits0 & 0xf; + uint8_t op_code = bits0 & 0xf; bool fin = (bits0 & (1 << 7)) != 0; size_t length = bits1 & 0x7f; int mask_start = 2; @@ -217,33 +237,24 @@ static void _http_add_body_bytes(tf_http_connection_t* connection, const void* d if (connection->body_length >= mask_start + length + 4) { uint32_t mask = - p[mask_start + 0] | - p[mask_start + 1] << 8 | - p[mask_start + 2] << 16 | - p[mask_start + 3] << 24; - size_t i = 0; - size_t start = mask_start + 4; - size_t end = mask_start + 4 + length; - for (i = start; i < end; i += 4) - { - *(uint32_t*)(p + i) ^= mask; - } - for (; i < end; i++) - { - p[i] ^= ((mask >> (8 * (i % 4))) & 0xff); - } + (uint32_t)p[mask_start + 0] | + (uint32_t)p[mask_start + 1] << 8 | + (uint32_t)p[mask_start + 2] << 16 | + (uint32_t)p[mask_start + 3] << 24; + _http_websocket_mask_in_place(p + mask_start + 4, mask, length); if (fin) { if (connection->request->on_message) { - connection->request->on_message(connection->request, p + mask_start + 4, length); + connection->request->on_message(connection->request, op_code, p + mask_start + 4, length); } else { - tf_printf("MESSAGE %d [%.*s]\n", opcode, (int)length, p + mask_start + 4); + tf_printf("MESSAGE %d [%.*s]\n", op_code, (int)length, p + mask_start + 4); } } - size_t total_length = end; + connection->websocket_message_index++; + size_t total_length = mask_start + 4 + length; memmove(connection->body, (char*)connection->body + total_length, connection->body_length - total_length); connection->body_length -= total_length; } @@ -382,7 +393,7 @@ static void _http_on_read(uv_stream_t* stream, ssize_t read_size, const uv_buf_t connection->buffer_length = 0; } } - else + else if (read_size < 0) { _http_connection_destroy(connection, uv_strerror(read_size)); } diff --git a/src/http.h b/src/http.h index fd5270ad..8b82ba72 100644 --- a/src/http.h +++ b/src/http.h @@ -13,7 +13,7 @@ typedef enum _tf_http_callback_phase_t k_http_callback_phase_request_done, } tf_http_callback_phase_t; -typedef void (tf_http_message_callback)(tf_http_request_t* request, const void* data, size_t size); +typedef void (tf_http_message_callback)(tf_http_request_t* request, int op_code, const void* data, size_t size); typedef struct _tf_http_request_t { diff --git a/src/httpd.js.c b/src/httpd.js.c index aea51bdc..24a19a8d 100644 --- a/src/httpd.js.c +++ b/src/httpd.js.c @@ -147,15 +147,15 @@ static JSValue _httpd_response_send(JSContext* context, JSValueConst this_val, i return JS_UNDEFINED; } -static void _httpd_message_callback(tf_http_request_t* request, const void* data, size_t size) +static void _httpd_message_callback(tf_http_request_t* request, int op_code, const void* data, size_t size) { JSContext* context = request->context; JSValue response_object = JS_MKPTR(JS_TAG_OBJECT, request->user_data); JSValue on_message = JS_GetPropertyStr(context, response_object, "onMessage"); JSValue event = JS_NewObject(context); - JS_SetPropertyStr(context, event, "opCode", JS_NewInt32(context, 0x1)); - JS_SetPropertyStr(context, event, "data", JS_NewStringLen(context, data, size)); //tf_util_new_uint8_array(context, data, size); + JS_SetPropertyStr(context, event, "opCode", JS_NewInt32(context, op_code)); + JS_SetPropertyStr(context, event, "data", JS_NewStringLen(context, data, size)); JSValue response = JS_Call(context, on_message, JS_UNDEFINED, 1, &event); tf_util_report_error(context, response); JS_FreeValue(context, event); @@ -270,7 +270,9 @@ static JSValue _httpd_register_socket_handler(JSContext* context, JSValueConst t static JSValue _httpd_start(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv) { tf_http_t* http = JS_GetOpaque(this_val, _httpd_class_id); - tf_http_listen(http, 12345); + int port = 0; + JS_ToInt32(context, &port, argv[0]); + tf_http_listen(http, port); return JS_UNDEFINED; } @@ -319,7 +321,7 @@ void tf_httpd_register(JSContext* context) JS_SetPropertyStr(context, httpd, "handlers", JS_NewObject(context)); JS_SetPropertyStr(context, httpd, "all", JS_NewCFunction(context, _httpd_all, "all", 2)); JS_SetPropertyStr(context, httpd, "registerSocketHandler", JS_NewCFunction(context, _httpd_register_socket_handler, "register_socket_handler", 2)); - JS_SetPropertyStr(context, httpd, "start", JS_NewCFunction(context, _httpd_start, "start", 0)); + JS_SetPropertyStr(context, httpd, "start", JS_NewCFunction(context, _httpd_start, "start", 1)); JS_SetPropertyStr(context, global, "httpdc", httpd); JS_FreeValue(context, global); } diff --git a/src/ssb.db.c b/src/ssb.db.c index 876e08a0..c51a9796 100644 --- a/src/ssb.db.c +++ b/src/ssb.db.c @@ -1313,7 +1313,7 @@ static int _following_compare(const void* a, const void* b) static bool _has_following_entry(const char* id, following_t** list, int count) { - return bsearch(id, list, count, sizeof(following_t*), _following_compare) != 0; + return count ? bsearch(id, list, count, sizeof(following_t*), _following_compare) != 0 : false; } static bool _add_following_entry(following_t*** list, int* count, following_t* add) diff --git a/tools/autotest.py b/tools/autotest.py index 016c55d5..59a27366 100755 --- a/tools/autotest.py +++ b/tools/autotest.py @@ -7,6 +7,7 @@ from selenium.webdriver.support.ui import WebDriverWait import os import subprocess +import sys import time for path in ('out/selenium.sqlite', 'out/selenium.sqlite-shm', 'out/selenium.sqlite-wal'): @@ -14,7 +15,7 @@ for path in ('out/selenium.sqlite', 'out/selenium.sqlite-shm', 'out/selenium.sql os.unlink(path) except: pass -tf = subprocess.Popen(['out/debug/tildefriends', 'run', '-d', 'out/selenium.sqlite', '-b', '0', '-p', '8888']) +tf = subprocess.Popen(['out/debug/tildefriends', 'run', '-d', 'out/selenium.sqlite', '-b', '0', '-p', '8888'] + sys.argv[1:]) def exists_in_shadow_root(shadow_root, by, value): return lambda driver: shadow_root.find_element(by, value)