aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/websocket/frames.lua30
-rw-r--r--spec/net_websocket_frames_spec.lua18
-rw-r--r--util-src/GNUmakefile2
-rw-r--r--util-src/makefile2
-rw-r--r--util-src/strbitop.c91
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;
+}