+local basexx = require('basexx')
local ffi = require('ffi')
local condition = require('cqueues.condition')
-- Trace execution of DNS queries
local function serve_doh(h, stream)
+ local input
local method = h:get(':method')
- if method ~= 'POST' then
- return 405, 'only HTTP post is supported'
+ if method == 'POST' then
+ input = stream:get_body_chars(65536, 10) -- FIXME: timeout
+ elseif method == 'GET' then
+ local input_b64 = string.match(h:get(':path'), '^/doh%?dns=([a-zA-Z0-9_-]+)$')
+ if not input_b64 then
+ return 400, 'base64url query not found'
+ end
+ if #input_b64 > 87380 then -- base64url encode 65535
+ return 414, 'query parameter in URI too long'
+ end
+ input = basexx.from_url64(input_b64)
+ if not input then
+ return 400, 'invalid base64url'
+ end
+ else
+ return 405, 'only HTTP POST and GET are supported'
end
+
+ if #input < 12 then
+ return 400, 'input too short'
+ elseif #input > 65535 then
+ return 413, 'input too long'
+ end
+
local content_type = h:get('content-type') or 'application/dns-message'
if content_type ~= 'application/dns-message' then
return 415, 'only Content-Type: application/dns-message is supported'
-- return 406, 'only Accept: application/dns-message is supported'
-- end
- local input = stream:get_body_chars(65536, 10) -- FIXME: timeout
- if #input < 12 then
- return 400, 'bad request: input too short'
- elseif #input > 65535 then
- return 413, 'bad request: input too long'
- end
-- Output buffer
local output = ''
local cond = condition.new()
local waiting, done = false, false
local finish_cb = function (answer, req)
- print(tostring(answer))
+ print(tostring(answer)) -- FIXME
print('TTL: ', get_http_ttl(answer))
+local basexx = require('basexx')
local ffi = require('ffi')
function parse_pkt(input)
end
local function check_err(req, exp_status, desc)
- local headers = req:go(5) -- randomly chosen timeout
+ local headers, errmsg, errno = req:go(5) -- TODO: randomly chosen timeout
+ if errno then
+ nok(errmsg, desc .. ': ' .. errmsg)
+ return
+ end
local got_status = headers:get(':status')
same(got_status, exp_status, desc)
- print(got_status) -- TODO
end
-- test whether http interface responds and binds
check_err(req, '413', 'too long POST finishes with 413')
end
+ local function test_get_long_input()
+ local req = assert(req_templ:clone())
+ req.headers:upsert(':method', 'GET')
+ req.headers:upsert(':path', '/doh?dns=' .. basexx.to_url64(string.rep('s', 65536)))
+ check_err(req, '414', 'too long GET finishes with 414')
+ end
+
local function test_post_unparseable_input()
local req = assert(req_templ:clone())
req.headers:upsert(':method', 'POST')
-- test_doh_post,
test_post_short_input,
test_post_long_input,
+ test_get_long_input,
test_post_unparseable_input,
test_post_unsupp_type
}