diff options
-rw-r--r-- | net/websocket/frames.lua | 30 | ||||
-rw-r--r-- | spec/net_websocket_frames_spec.lua | 18 | ||||
-rw-r--r-- | util-src/GNUmakefile | 2 | ||||
-rw-r--r-- | util-src/makefile | 2 | ||||
-rw-r--r-- | util-src/strbitop.c | 91 |
5 files changed, 114 insertions, 29 deletions
diff --git a/net/websocket/frames.lua b/net/websocket/frames.lua index 922a2fce..03ce21a8 100644 --- a/net/websocket/frames.lua +++ b/net/websocket/frames.lua @@ -12,12 +12,11 @@ local random_bytes = require "util.random".bytes; 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 @@ local function parse_frame_header(frame) 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 @@ end -- 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 function build_frame(desc) 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 diff --git a/spec/net_websocket_frames_spec.lua b/spec/net_websocket_frames_spec.lua index 7eed73c9..7c7d8f05 100644 --- a/spec/net_websocket_frames_spec.lua +++ b/spec/net_websocket_frames_spec.lua @@ -32,16 +32,25 @@ describe("net.websocket.frames", function () ["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; + }; + empty_with_mask = { + ["opcode"] = 0; + ["key"] = " \0 \0"; ["FIN"] = true; ["MASK"] = true; ["RSV1"] = false; ["RSV2"] = false; ["RSV3"] = false; - ["key"] = { 0x20, 0x20, 0x20, 0x20, }; }; ping = { ["opcode"] = 0x9; @@ -71,7 +80,8 @@ describe("net.websocket.frames", function () 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 @@ describe("net.websocket.frames", function () 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); diff --git a/util-src/GNUmakefile b/util-src/GNUmakefile index e9e06355..0b96bf41 100644 --- a/util-src/GNUmakefile +++ b/util-src/GNUmakefile @@ -7,7 +7,7 @@ INSTALL_DATA=install -m644 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 diff --git a/util-src/makefile b/util-src/makefile index 2db415df..1560fca4 100644 --- a/util-src/makefile +++ b/util-src/makefile @@ -6,7 +6,7 @@ INSTALL_DATA=install -m644 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 diff --git a/util-src/strbitop.c b/util-src/strbitop.c new file mode 100644 index 00000000..a26288e5 --- /dev/null +++ b/util-src/strbitop.c @@ -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; +} |