Skip to content

Commit

Permalink
Change. Extension API uses string to deal with offer/response.
Browse files Browse the repository at this point in the history
  • Loading branch information
moteus committed Mar 19, 2016
1 parent 0ba4d32 commit 5297b87
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 52 deletions.
8 changes: 4 additions & 4 deletions src/lluv/websocket.lua
Original file line number Diff line number Diff line change
Expand Up @@ -444,16 +444,16 @@ function WSSocket:_client_handshake(key, req, cb)

if trace then trace("WS HS DONE>", "buffer size:", self._buffer:size()) end

local extensions = handshake.decode_header(headers['sec-websocket-extensions'])
local extensions = headers['sec-websocket-extensions']
if extensions and #extensions then
if not self._extensions then
-- we get extension response but we do not send offer
return protocol_error(self, 1010, "Unsupported extension", cb)
end

local ok, err = self._extensions:accept(extensions)
if err and not ok then
-- we get error while check accept options
if not ok then
-- we have to either accept all extensions or close connection
return protocol_error(self, 1010, "Unsupported extension", cb, false, err)
end
else self._extensions = nil end
Expand Down Expand Up @@ -523,7 +523,7 @@ function WSSocket:_server_handshake(cb)
local resp, err = self._extensions:response(extensions)
if resp and #resp > 0 then
tappend(response,
'Sec-WebSocket-Extensions: ' .. handshake.encode_header(resp)
'Sec-WebSocket-Extensions: ' .. resp
)
else self._extensions = nil end

Expand Down
15 changes: 13 additions & 2 deletions src/lluv/websocket/extensions.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
local ut = require "lluv.utils"
local handshake = require "lluv.websocket.handshake"

local encode_header, decode_header = handshake.encode_header, handshake.decode_header

local tappend = function(t, v) t[#t + 1] = v return t end

Expand Down Expand Up @@ -96,13 +99,18 @@ function Extensions:offer()

self._offered = extensions

return offer
return encode_header(offer)
end

-- Accept extension negotiation response
function Extensions:accept(params)
assert(self._offered, 'try accept without offer')

params = decode_header(params)
if not params then
return Error.new(Error.EINVAL, nil, 'invalid header value', params)
end

local active, offered = {}, self._offered
self._offered = nil

Expand Down Expand Up @@ -141,6 +149,9 @@ end

-- Generate extension negotiation response
function Extensions:response(offers)
offers = decode_header(offers)
if not offers then return end

local params_by_name = {}
for _, offer in ipairs(offers) do
local name, params = offer[1], offer[2]
Expand Down Expand Up @@ -182,7 +193,7 @@ function Extensions:response(offers)

if active[1] then
self._active = active
return response
return encode_header(response)
end
end

Expand Down
25 changes: 13 additions & 12 deletions src/lluv/websocket/handshake.lua
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,8 @@ local upgrade_request = function(req)
lines[2] = format('Host: %s:%d',req.host,req.port)
end

local extensions = encode_header(req.extensions)
if extensions and #extensions > 0 then
lines[#lines + 1] = 'Sec-WebSocket-Extensions: ' .. extensions
if req.extensions and #req.extensions > 0 then
lines[#lines + 1] = 'Sec-WebSocket-Extensions: ' .. req.extensions
end

lines[#lines + 1] = '\r\n'
Expand Down Expand Up @@ -99,7 +98,7 @@ local accept_upgrade = function(request, protocols)

local accept_key = sec_websocket_accept(headers['sec-websocket-key'])
local connection = headers['connection']
local extensions = decode_header(headers['sec-websocket-extensions'])
local extensions = headers['sec-websocket-extensions']

local lines = {
'HTTP/1.1 101 Switching Protocols',
Expand Down Expand Up @@ -235,14 +234,16 @@ decode_header = decode_header_lpeg or decode_header_native

local function encode_header_options(name, options)
local str = name
for k, v in pairs(options) do
if v == true then str = str .. '; ' .. k
elseif type(v) == 'table' then
for _, v in ipairs(v) do
if v == true then str = str .. '; ' .. k
else str = str .. '; ' .. k .. '=' .. enqute(tostring(v)) end
end
else str = str .. '; ' .. k .. '=' .. enqute(tostring(v)) end
if options then
for k, v in pairs(options) do
if v == true then str = str .. '; ' .. k
elseif type(v) == 'table' then
for _, v in ipairs(v) do
if v == true then str = str .. '; ' .. k
else str = str .. '; ' .. k .. '=' .. enqute(tostring(v)) end
end
else str = str .. '; ' .. k .. '=' .. enqute(tostring(v)) end
end
end
return str
end
Expand Down
76 changes: 42 additions & 34 deletions test/test_extensions.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ local decode_header_lpeg = handshake._decode_header_lpeg
local decode_header_native = handshake._decode_header_native
local decode_header = decode_header_lpeg or decode_header_native
local encode_header = handshake.encode_header
local H = encode_header

local D = function(s, ...)
if type(s) == 'string' then
return decode_header(s), ...
end
return t, ...
end

local function E(t)
t.name = t[1]
Expand Down Expand Up @@ -190,16 +198,16 @@ function teardown()
end

function test_accept()
local offer = assert_table(ext:offer())
local offer = assert_table(D(ext:offer()))
assert_equal(0, #offer)
local ok, err = assert_nil(ext:accept({{'permessage-deflate'}}))
local ok, err = assert_nil(ext:accept(H{{'permessage-deflate'}}))
end

function test_offer()
assert(ext:reg(E{'permessage-foo', true, false, false,
offer = function() return {value = true} end
}))
local offer = assert_table(ext:offer())
local offer = assert_table(D(ext:offer()))
assert_equal(1, #offer)
assert_equal('permessage-foo', offer[1][1])
local params = assert_table(offer[1][2])
Expand All @@ -219,12 +227,12 @@ function test_duplicate_rsv_bit()
offer = {bar_param=true};
}))

local offer = assert_table(ext:offer())
local offer = assert_table(D(ext:offer()))
assert_equal(2, #offer)
assert_equal('permessage-foo', offer[1][1])
assert_equal('permessage-bar', offer[2][1])

assert(ext:accept({{'permessage-bar'}}))
assert(ext:accept(H{{'permessage-bar'}}))

assert('permessage-bar', ext:accepted('permessage-bar'))
assert_nil(ext:accepted('permessage-foo'))
Expand Down Expand Up @@ -253,12 +261,12 @@ function test_encode_decode()
end;
}))

local offer = assert_table(ext:offer())
local offer = assert_table(D(ext:offer()))
assert_equal(2, #offer)
assert_equal('permessage-foo', offer[1][1])
assert_equal('permessage-bar', offer[2][1])

assert(ext:accept({{'permessage-bar'}, {'permessage-foo'}}))
assert(ext:accept(H{{'permessage-bar'}, {'permessage-foo'}}))

assert_equal('permessage-bar', ext:accepted('permessage-bar'))
assert_equal('permessage-foo', ext:accepted('permessage-foo'))
Expand Down Expand Up @@ -300,12 +308,12 @@ function test_duplicate_rsv_bit_accept()
offer = {bar_param=true};
}))

local offer = assert_table(ext:offer())
local offer = assert_table(D(ext:offer()))
assert_equal(2, #offer)
assert_equal('permessage-foo', offer[1][1])
assert_equal('permessage-bar', offer[2][1])

local _, err = assert_nil(ext:accept({{'permessage-bar'}, {'permessage-foo'}}))
local _, err = assert_nil(ext:accept(H{{'permessage-bar'}, {'permessage-foo'}}))

assert_not_nil(err)
assert_match('%[WSEXT%]', tostring(err))
Expand All @@ -330,10 +338,10 @@ function test_accept_invalid_extension()
offer = {bar_param=true};
}))

assert_table(ext:offer())
assert_table(D(ext:offer()))
local response = {{'permessage-baz'}}

local _, err = assert_nil(ext:accept(response))
local _, err = assert_nil(ext:accept(H(response)))

assert_not_nil(err)
assert_match('%[WSEXT%]', tostring(err))
Expand All @@ -348,10 +356,10 @@ function test_accept_multi_ext_with_same_rsv()
offer = {bar_param=true};
}))

assert_table(ext:offer())
assert_table(D(ext:offer()))
local response = {{'permessage-bar'}, {'permessage-foo'}}

local _, err = assert_nil(ext:accept(response))
local _, err = assert_nil(ext:accept(H(response)))
assert(err)
end

Expand All @@ -360,12 +368,12 @@ it('should fail accept if first ext fail', function()
assert(ext:reg(E{'permessage-foo', true, accept = {nil, ERROR}}))
assert(ext:reg(E{'permessage-bar', false, true}))

local offer = assert_table(ext:offer())
local offer = assert_table(D(ext:offer()))
assert_equal(2, #offer)
assert_equal('permessage-foo', offer[1][1])
assert_equal('permessage-bar', offer[2][1])

local _, err = assert_nil(ext:accept({{'permessage-foo'}, {'permessage-bar'}}))
local _, err = assert_nil(ext:accept(H{{'permessage-foo'}, {'permessage-bar'}}))
assert_equal(ERROR, err)

assert_nil(ext:accepted())
Expand All @@ -378,12 +386,12 @@ it('should fail accept if second ext fail', function()
assert(ext:reg(E{'permessage-foo', true}))
assert(ext:reg(E{'permessage-bar', false, true, accept = {nil, ERROR}}))

local offer = assert_table(ext:offer())
local offer = assert_table(D(ext:offer()))
assert_equal(2, #offer)
assert_equal('permessage-foo', offer[1][1])
assert_equal('permessage-bar', offer[2][1])

local _, err = assert_nil(ext:accept({{'permessage-foo'}, {'permessage-bar'}}))
local _, err = assert_nil(ext:accept(H{{'permessage-foo'}, {'permessage-bar'}}))
assert_equal(ERROR, err)

assert_nil(ext:accepted())
Expand All @@ -396,12 +404,12 @@ it('should accept multiple ext', function()
assert(ext:reg(E{'permessage-foo', true}))
assert(ext:reg(E{'permessage-bar', false, true}))

local offer = assert_table(ext:offer())
local offer = assert_table(D(ext:offer()))
assert_equal(2, #offer)
assert_equal('permessage-foo', offer[1][1])
assert_equal('permessage-bar', offer[2][1])

assert(ext:accept({{'permessage-bar'}, {'permessage-foo'}}))
assert(ext:accept(H{{'permessage-bar'}, {'permessage-foo'}}))

local t = assert_table(ext:accepted())
assert_equal('permessage-bar', t[1])
Expand Down Expand Up @@ -445,22 +453,22 @@ function test_response()
{'permessage-foo',{param_foo=true}},
}

local response = assert_table(ext:response(offer))
local response = assert_table(D(ext:response(H(offer))))

assert_equal(1, #response)
local resp_foo = assert_table(response[1])
assert_equal('permessage-foo', resp_foo[1])
assert_table(resp_foo[2])
assert_false(resp_foo[2].param_foo)
assert_equal('false', resp_foo[2].param_foo)
end

it('should accept match', function()
assert(ext:reg(E{'permessage-foo', true}))

local offer = {{'permessage-bar'}, {'permessage-foo'}}
local resp = assert_table(ext:response(offer))
local resp = assert_table(D(ext:response(H(offer))))

local response = assert_table(ext:response(offer))
local response = assert_table(D(ext:response(H(offer))))

assert_equal(1, #response)
local resp_foo = assert_table(response[1])
Expand All @@ -475,9 +483,9 @@ it('should accept first ext with same rsv bit', function()
assert(ext:reg(E{'permessage-bar', true}))

local offer = {{'permessage-bar'}, {'permessage-foo'}}
local resp = assert_table(ext:response(offer))
local resp = assert_table(D(ext:response(H(offer))))

local response = assert_table(ext:response(offer))
local response = assert_table(D(ext:response(H(offer))))

assert_equal(1, #response)
local resp = assert_table(response[1])
Expand All @@ -491,10 +499,10 @@ it('should accept first option set', function()
called = true
assert_equal(2, #params)
local param = assert_table(params[1])
assert_equal(1, param.value)
assert_equal('1', param.value)

param = assert_table(params[2])
assert_equal(2, param.value)
assert_equal('2', param.value)

return param
end}))
Expand All @@ -503,14 +511,14 @@ it('should accept first option set', function()
{'permessage-foo', {value = 1}},
{'permessage-foo', {value = 2}},
}
local resp = assert_table(ext:response(offer))
local resp = assert_table(D(ext:response(H(offer))))

local response = assert_table(ext:response(offer))
local response = assert_table(D(ext:response(H(offer))))

assert_equal(1, #response)
local resp = assert_table(response[1])
assert_equal('permessage-foo', resp[1])
assert_equal(2, resp[2].value)
assert_equal('2', resp[2].value)

assert_true(called)
end)
Expand All @@ -520,7 +528,7 @@ it('should fail accept if first ext fail', function()
assert(ext:reg(E{'permessage-bar', false, true}))

local offer = {{'permessage-bar'}, {'permessage-foo'}}
local _, err = assert_nil(ext:response(offer))
local _, err = assert_nil(ext:response(H(offer)))

assert_equal('ERROR', err)
assert_nil(ext:accepted())
Expand All @@ -531,7 +539,7 @@ it('should fail accept if second ext fail', function()
assert(ext:reg(E{'permessage-bar', false, true, response = 'ERROR'}))

local offer = {{'permessage-bar'}, {'permessage-foo'}}
local _, err = assert_nil(ext:response(offer))
local _, err = assert_nil(ext:response(H(offer)))

assert_equal('ERROR', err)
assert_nil(ext:accepted())
Expand Down Expand Up @@ -593,9 +601,9 @@ function setup()

assert(ext:reg(bar:reset()))

local offer = assert_table(ext:offer())
local offer = assert_table(D(ext:offer()))

assert(ext:accept({{'permessage-bar'}, {'permessage-foo'}}))
assert(ext:accept(H{{'permessage-bar'}, {'permessage-foo'}}))
end

it('should validate frame', function()
Expand Down

0 comments on commit 5297b87

Please sign in to comment.