Merge 0.11->trunk
authorMatthew Wild <mwild1@gmail.com>
Thu, 15 Oct 2020 14:25:09 +0100
changeset 11170 51e5149ed0ad
parent 11165 f51ed2652602 (current diff)
parent 11169 eae8046d51fc (diff)
child 11174 4bda303d54ed
Merge 0.11->trunk
net/websocket/frames.lua
spec/net_websocket_frames_spec.lua
util-src/GNUmakefile
util-src/makefile
--- a/net/websocket/frames.lua	Thu Oct 15 13:43:03 2020 +0100
+++ b/net/websocket/frames.lua	Thu Oct 15 14:25:09 2020 +0100
@@ -12,12 +12,11 @@
 local bit = require "util.bitcompat";
 local band = bit.band;
 local bor = bit.bor;
-local bxor = bit.bxor;
 local lshift = bit.lshift;
 local rshift = bit.rshift;
-local unpack = table.unpack or unpack; -- luacheck: ignore 113
+local sbit = require "util.strbitop";
+local sxor = sbit.sxor;
 
-local t_concat = table.concat;
 local s_char= string.char;
 local s_pack = string.pack;
 local s_unpack = string.unpack;
@@ -106,7 +105,7 @@
 	end
 
 	if result.MASK then
-		result.key = { frame:byte(length_bytes+3, length_bytes+6) };
+		result.key = frame:sub(length_bytes+3, length_bytes+6);
 	end
 
 	return result, header_length;
@@ -115,19 +114,7 @@
 -- XORs the string `str` with the array of bytes `key`
 -- TODO: optimize
 local function apply_mask(str, key, from, to)
-	from = from or 1
-	if from < 0 then from = #str + from + 1 end -- negative indices
-	to = to or #str
-	if to < 0 then to = #str + to + 1 end -- negative indices
-	local key_len = #key
-	local counter = 0;
-	local data = {};
-	for i = from, to do
-		local key_index = counter%key_len + 1;
-		counter = counter + 1;
-		data[counter] = s_char(bxor(key[key_index], str:byte(i)));
-	end
-	return t_concat(data);
+	return sxor(str:sub(from or 1, to or -1), key);
 end
 
 local function parse_frame_body(frame, header, pos)
@@ -174,15 +161,12 @@
 
 	local key = ""
 	if desc.MASK then
-		local key_a = desc.key
-		if key_a then
-			key = s_char(unpack(key_a, 1, 4));
-		else
+		key = desc.key
+		if not key then
 			key = random_bytes(4);
-			key_a = {key:byte(1,4)};
 		end
 		b2 = bor(b2, 0x80);
-		data = apply_mask(data, key_a);
+		data = apply_mask(data, key);
 	end
 
 	return s_char(b1, b2) .. length_extra .. key .. data
--- a/spec/net_websocket_frames_spec.lua	Thu Oct 15 13:43:03 2020 +0100
+++ b/spec/net_websocket_frames_spec.lua	Thu Oct 15 14:25:09 2020 +0100
@@ -32,16 +32,25 @@
 			["RSV2"] = false;
 			["RSV3"] = false;
 		};
-		masked_data = {
+		with_mask = {
 			["opcode"] = 0;
 			["length"] = 5;
 			["data"] = "hello";
+			["key"] = " \0 \0";
 			["FIN"] = true;
 			["MASK"] = true;
 			["RSV1"] = false;
 			["RSV2"] = false;
 			["RSV3"] = false;
-			["key"] = { 0x20, 0x20, 0x20, 0x20, };
+		};
+		empty_with_mask = {
+			["opcode"] = 0;
+			["key"] = " \0 \0";
+			["FIN"] = true;
+			["MASK"] = true;
+			["RSV1"] = false;
+			["RSV2"] = false;
+			["RSV3"] = false;
 		};
 		ping = {
 			["opcode"] = 0x9;
@@ -71,7 +80,8 @@
 			assert.equal("\0\0", build(test_frames.simple_empty));
 			assert.equal("\0\5hello", build(test_frames.simple_data));
 			assert.equal("\128\0", build(test_frames.simple_fin));
-			assert.equal("\128\133    HELLO", build(test_frames.masked_data));
+			assert.equal("\128\133 \0 \0HeLlO", build(test_frames.with_mask))
+			assert.equal("\128\128 \0 \0", build(test_frames.empty_with_mask))
 			assert.equal("\137\4ping", build(test_frames.ping));
 			assert.equal("\138\4pong", build(test_frames.pong));
 		end);
@@ -83,7 +93,7 @@
 			assert.same(test_frames.simple_empty, parse("\0\0"));
 			assert.same(test_frames.simple_data, parse("\0\5hello"));
 			assert.same(test_frames.simple_fin, parse("\128\0"));
-			assert.same(test_frames.masked_data, parse("\128\133    HELLO"));
+			assert.same(test_frames.with_mask, parse("\128\133 \0 \0HeLlO"));
 			assert.same(test_frames.ping, parse("\137\4ping"));
 			assert.same(test_frames.pong, parse("\138\4pong"));
 		end);
--- a/util-src/GNUmakefile	Thu Oct 15 13:43:03 2020 +0100
+++ b/util-src/GNUmakefile	Thu Oct 15 14:25:09 2020 +0100
@@ -7,7 +7,7 @@
 TARGET?=../util/
 
 ALL=encodings.so hashes.so net.so pposix.so signal.so table.so \
-    ringbuffer.so time.so poll.so compat.so
+    ringbuffer.so time.so poll.so compat.so strbitop.so
 
 ifdef RANDOM
 ALL+=crand.so
--- a/util-src/makefile	Thu Oct 15 13:43:03 2020 +0100
+++ b/util-src/makefile	Thu Oct 15 14:25:09 2020 +0100
@@ -6,7 +6,7 @@
 TARGET?=../util/
 
 ALL=encodings.so hashes.so net.so pposix.so signal.so table.so \
-    ringbuffer.so time.so poll.so compat.so
+    ringbuffer.so time.so poll.so compat.so strbitop.so
 
 .ifdef $(RANDOM)
 ALL+=crand.so
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util-src/strbitop.c	Thu Oct 15 14:25:09 2020 +0100
@@ -0,0 +1,91 @@
+/*
+ * This project is MIT licensed. Please see the
+ * COPYING file in the source package for more information.
+ *
+ * Copyright (C) 2016 Kim Alvefur
+ */
+
+#include <lua.h>
+#include <lauxlib.h>
+
+#if (LUA_VERSION_NUM == 501)
+#define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R)
+#endif
+
+/* TODO Deduplicate code somehow */
+
+int strop_and(lua_State* L) {
+	luaL_Buffer buf;
+	size_t a, b, i;
+	const char* str_a = luaL_checklstring(L, 1, &a);
+	const char* str_b = luaL_checklstring(L, 2, &b);
+
+	luaL_buffinit(L, &buf);
+
+	if(a == 0 || b == 0) {
+		lua_settop(L, 1);
+		return 1;
+	}
+
+	for(i = 0; i < a; i++) {
+		luaL_addchar(&buf, str_a[i] & str_b[i % b]);
+	}
+
+	luaL_pushresult(&buf);
+	return 1;
+}
+
+int strop_or(lua_State* L) {
+	luaL_Buffer buf;
+	size_t a, b, i;
+	const char* str_a = luaL_checklstring(L, 1, &a);
+	const char* str_b = luaL_checklstring(L, 2, &b);
+
+	luaL_buffinit(L, &buf);
+
+	if(a == 0 || b == 0) {
+		lua_settop(L, 1);
+		return 1;
+	}
+
+	for(i = 0; i < a; i++) {
+		luaL_addchar(&buf, str_a[i] | str_b[i % b]);
+	}
+
+	luaL_pushresult(&buf);
+	return 1;
+}
+
+int strop_xor(lua_State* L) {
+	luaL_Buffer buf;
+	size_t a, b, i;
+	const char* str_a = luaL_checklstring(L, 1, &a);
+	const char* str_b = luaL_checklstring(L, 2, &b);
+
+	luaL_buffinit(L, &buf);
+
+	if(a == 0 || b == 0) {
+		lua_settop(L, 1);
+		return 1;
+	}
+
+	for(i = 0; i < a; i++) {
+		luaL_addchar(&buf, str_a[i] ^ str_b[i % b]);
+	}
+
+	luaL_pushresult(&buf);
+	return 1;
+}
+
+LUA_API int luaopen_util_strbitop(lua_State *L) {
+	luaL_Reg exports[] = {
+		{ "sand", strop_and },
+		{ "sor",  strop_or },
+		{ "sxor", strop_xor },
+		{ NULL, NULL }
+	};
+
+	lua_newtable(L);
+	luaL_setfuncs(L, exports, 0);
+	return 1;
+}