forked from cory/tildefriends
Fix websocket unmasking issues. Autotest works with C httpd, now.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4699 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
parent
8ab8335baa
commit
7964524e0a
@ -1005,7 +1005,7 @@ loadSettings().then(function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
httpd_impl.registerSocketHandler("/app/socket", app.socket);
|
httpd_impl.registerSocketHandler("/app/socket", app.socket);
|
||||||
httpd_impl.start();
|
httpd_impl.start(tildefriends.http_port);
|
||||||
}).catch(function(error) {
|
}).catch(function(error) {
|
||||||
print('Failed to load settings.');
|
print('Failed to load settings.');
|
||||||
printError({print: print}, error);
|
printError({print: print}, error);
|
||||||
|
@ -525,7 +525,6 @@ let kBacklog = 8;
|
|||||||
let kHost = platform() == 'haiku' ? 'localhost' : '::';
|
let kHost = platform() == 'haiku' ? 'localhost' : '::';
|
||||||
|
|
||||||
function start() {
|
function start() {
|
||||||
print('ACTUAL START');
|
|
||||||
let socket = new Socket();
|
let socket = new Socket();
|
||||||
socket.bind(kHost, tildefriends.http_port).then(function(port) {
|
socket.bind(kHost, tildefriends.http_port).then(function(port) {
|
||||||
print("bound to", port);
|
print("bound to", port);
|
||||||
|
55
src/http.c
55
src/http.c
@ -8,6 +8,7 @@
|
|||||||
#include "uv.h"
|
#include "uv.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <stdalign.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@ -45,6 +46,7 @@ typedef struct _tf_http_connection_t
|
|||||||
void* user_data;
|
void* user_data;
|
||||||
|
|
||||||
bool is_websocket;
|
bool is_websocket;
|
||||||
|
int websocket_message_index;
|
||||||
void* body;
|
void* body;
|
||||||
size_t body_length;
|
size_t body_length;
|
||||||
size_t content_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)
|
if (connection->tcp.data)
|
||||||
{
|
{
|
||||||
tf_printf("CLOSE %p: %s\n", connection, reason);
|
|
||||||
uv_close((uv_handle_t*)&connection->tcp, _http_connection_on_close);
|
uv_close((uv_handle_t*)&connection->tcp, _http_connection_on_close);
|
||||||
}
|
}
|
||||||
else if (connection->ref_count == 0)
|
else if (connection->ref_count == 0)
|
||||||
@ -171,6 +172,25 @@ static void _http_reset_connection(tf_http_connection_t* connection)
|
|||||||
connection->parsed_length = 0;
|
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)
|
static void _http_add_body_bytes(tf_http_connection_t* connection, const void* data, size_t size)
|
||||||
{
|
{
|
||||||
if (connection->is_websocket)
|
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);
|
memcpy((char*)connection->body + connection->body_length, data, size);
|
||||||
connection->body_length += size;
|
connection->body_length += size;
|
||||||
|
|
||||||
uint8_t* p = connection->body;
|
|
||||||
while (connection->body_length >= 2)
|
while (connection->body_length >= 2)
|
||||||
{
|
{
|
||||||
|
uint8_t* p = connection->body;
|
||||||
uint8_t bits0 = p[0];
|
uint8_t bits0 = p[0];
|
||||||
uint8_t bits1 = p[1];
|
uint8_t bits1 = p[1];
|
||||||
if ((bits1 & (1 << 7)) == 0)
|
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");
|
_http_connection_destroy(connection, "websocket server received unmasked bytes");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint8_t opcode = bits0 & 0xf;
|
uint8_t op_code = bits0 & 0xf;
|
||||||
bool fin = (bits0 & (1 << 7)) != 0;
|
bool fin = (bits0 & (1 << 7)) != 0;
|
||||||
size_t length = bits1 & 0x7f;
|
size_t length = bits1 & 0x7f;
|
||||||
int mask_start = 2;
|
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)
|
if (connection->body_length >= mask_start + length + 4)
|
||||||
{
|
{
|
||||||
uint32_t mask =
|
uint32_t mask =
|
||||||
p[mask_start + 0] |
|
(uint32_t)p[mask_start + 0] |
|
||||||
p[mask_start + 1] << 8 |
|
(uint32_t)p[mask_start + 1] << 8 |
|
||||||
p[mask_start + 2] << 16 |
|
(uint32_t)p[mask_start + 2] << 16 |
|
||||||
p[mask_start + 3] << 24;
|
(uint32_t)p[mask_start + 3] << 24;
|
||||||
size_t i = 0;
|
_http_websocket_mask_in_place(p + mask_start + 4, mask, length);
|
||||||
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);
|
|
||||||
}
|
|
||||||
if (fin)
|
if (fin)
|
||||||
{
|
{
|
||||||
if (connection->request->on_message)
|
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
|
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);
|
memmove(connection->body, (char*)connection->body + total_length, connection->body_length - 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;
|
connection->buffer_length = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (read_size < 0)
|
||||||
{
|
{
|
||||||
_http_connection_destroy(connection, uv_strerror(read_size));
|
_http_connection_destroy(connection, uv_strerror(read_size));
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ typedef enum _tf_http_callback_phase_t
|
|||||||
k_http_callback_phase_request_done,
|
k_http_callback_phase_request_done,
|
||||||
} tf_http_callback_phase_t;
|
} 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
|
typedef struct _tf_http_request_t
|
||||||
{
|
{
|
||||||
|
@ -147,15 +147,15 @@ static JSValue _httpd_response_send(JSContext* context, JSValueConst this_val, i
|
|||||||
return JS_UNDEFINED;
|
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;
|
JSContext* context = request->context;
|
||||||
JSValue response_object = JS_MKPTR(JS_TAG_OBJECT, request->user_data);
|
JSValue response_object = JS_MKPTR(JS_TAG_OBJECT, request->user_data);
|
||||||
JSValue on_message = JS_GetPropertyStr(context, response_object, "onMessage");
|
JSValue on_message = JS_GetPropertyStr(context, response_object, "onMessage");
|
||||||
|
|
||||||
JSValue event = JS_NewObject(context);
|
JSValue event = JS_NewObject(context);
|
||||||
JS_SetPropertyStr(context, event, "opCode", JS_NewInt32(context, 0x1));
|
JS_SetPropertyStr(context, event, "opCode", JS_NewInt32(context, op_code));
|
||||||
JS_SetPropertyStr(context, event, "data", JS_NewStringLen(context, data, size)); //tf_util_new_uint8_array(context, data, size);
|
JS_SetPropertyStr(context, event, "data", JS_NewStringLen(context, data, size));
|
||||||
JSValue response = JS_Call(context, on_message, JS_UNDEFINED, 1, &event);
|
JSValue response = JS_Call(context, on_message, JS_UNDEFINED, 1, &event);
|
||||||
tf_util_report_error(context, response);
|
tf_util_report_error(context, response);
|
||||||
JS_FreeValue(context, event);
|
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)
|
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_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;
|
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, "handlers", JS_NewObject(context));
|
||||||
JS_SetPropertyStr(context, httpd, "all", JS_NewCFunction(context, _httpd_all, "all", 2));
|
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, "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_SetPropertyStr(context, global, "httpdc", httpd);
|
||||||
JS_FreeValue(context, global);
|
JS_FreeValue(context, global);
|
||||||
}
|
}
|
||||||
|
@ -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)
|
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)
|
static bool _add_following_entry(following_t*** list, int* count, following_t* add)
|
||||||
|
@ -7,6 +7,7 @@ from selenium.webdriver.support.ui import WebDriverWait
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
for path in ('out/selenium.sqlite', 'out/selenium.sqlite-shm', 'out/selenium.sqlite-wal'):
|
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)
|
os.unlink(path)
|
||||||
except:
|
except:
|
||||||
pass
|
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):
|
def exists_in_shadow_root(shadow_root, by, value):
|
||||||
return lambda driver: shadow_root.find_element(by, value)
|
return lambda driver: shadow_root.find_element(by, value)
|
||||||
|
Loading…
Reference in New Issue
Block a user