Skip to content

Commit 0da7cad

Browse files
committed
lpeg_patterns/http/alpn: Verify that protocol_id meets unique encoding criteria
1 parent 5d0949a commit 0da7cad

File tree

3 files changed

+50
-1
lines changed

3 files changed

+50
-1
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
UNRELEASED
22

33
- http: split into multiple modules
4+
- http.alpn: verify that protocol_id meets unique encoding criteria
45

56

67
0.5 - 2018-07-15

lpeg_patterns/http/alpn.lua

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,33 @@
11
-- RFC 7639
2+
3+
local lpeg = require "lpeg"
24
local http_core = require "lpeg_patterns.http.core"
5+
local util = require "lpeg_patterns.util"
6+
7+
local Cmt = lpeg.Cmt
8+
local Cs = lpeg.Cs
9+
local P = lpeg.P
10+
local R = lpeg.R
11+
12+
--[[ protocol-id is a percent-encoded ALPN protocol name
13+
- Octets in the ALPN protocol MUST NOT be percent-encoded if they
14+
are valid token characters except "%".
15+
- When using percent-encoding, uppercase hex digits MUST be used.
16+
]]
17+
18+
local valid_chars = http_core.tchar - P"%"
19+
local upper_hex = R("09", "AF")
20+
local percent_char = P"%" * (upper_hex * upper_hex / util.read_hex) / string.char
21+
local percent_encoded = Cmt(percent_char, function(_, _, c)
22+
-- check that decoded character would not have been allowed unescaped
23+
if not valid_chars:match(c) then
24+
return true, c
25+
end
26+
end)
27+
local percent_replace = Cs((valid_chars + percent_encoded)^0)
28+
29+
local protocol_id = percent_replace
330

4-
local protocol_id = http_core.token
531
local ALPN = http_core.comma_sep_trim(protocol_id, 1)
632

733
return {

spec/http_alpn_spec.lua

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
describe("lpeg_patterns.http.alpn", function()
2+
local http_alpn = require "lpeg_patterns.http.alpn"
3+
local lpeg = require "lpeg"
4+
local EOF = lpeg.P(-1)
5+
local protocol_id = http_alpn.protocol_id * EOF
6+
it("unescapes an ALPN protocol id correctly", function()
7+
assert.same("foo", protocol_id:match("foo"))
8+
-- percent encoded chars
9+
assert.same(" ", protocol_id:match("%20")) -- space
10+
assert.same("%", protocol_id:match("%25")) -- %
11+
end)
12+
it("must not decode to character that didn't need to be escaped", function()
13+
assert.same(nil, protocol_id:match("%41")) -- a
14+
assert.same(nil, protocol_id:match("%26")) -- &
15+
end)
16+
it("must be 2 digit hex", function()
17+
assert.same(nil, protocol_id:match("%2"))
18+
end)
19+
it("must be uppercase hex", function()
20+
assert.same(nil, protocol_id:match("%1a"))
21+
end)
22+
end)

0 commit comments

Comments
 (0)