]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
doh2: added control stream to each test
authorLukáš Ježek <lukas.jezek@nic.cz>
Tue, 9 Feb 2021 10:58:23 +0000 (11:58 +0100)
committerLukáš Ježek <lukas.jezek@nic.cz>
Tue, 9 Mar 2021 09:31:51 +0000 (10:31 +0100)
tests/config/doh2.test.lua

index 6111f1148a3dfbcf814627473b83399d3b07f621..98bcbccff42ef4a4240f2bd2bed49b3cc624ddc1 100644 (file)
@@ -1,13 +1,25 @@
 -- SPDX-License-Identifier: GPL-3.0-or-later
 local basexx = require('basexx')
 local ffi = require('ffi')
+local monotime = require('cqueues').monotime
+
+-- check prerequisites
+local timeout = 8 -- randomly chosen timeout by tkrizek
+local bound, port
+local host = '127.0.0.1'
+for _  = 1,10 do
+       port = math.random(30000, 39999)
+       bound = pcall(net.listen, host, port, { kind = 'doh2'})
+       if bound then
+               break
+       end
+end
 
 local function gen_huge_answer(_, req)
        local answer = req:ensure_answer()
        ffi.C.kr_pkt_make_auth_header(answer)
 
        answer:rcode(kres.rcode.NOERROR)
-
        -- 64k answer
        answer:begin(kres.section.ANSWER)
        answer:put('\4test\0', 300, answer:qclass(), kres.type.URI,
@@ -49,41 +61,220 @@ function parse_pkt(input, desc)
        return pkt
 end
 
-local function check_ok(req, desc)
-       local headers, stream, errno = req:go(8)  -- randomly chosen timeout by tkrizek
+local function non_final_status(status)
+       return status:sub(1, 1) == "1" and status ~= "101"
+end
+
+local function request_set_body(req, body)
+       req['body'] = body
+end
+
+local function connection_connect(req)
+       local client = require('http.client')
+       local err, errno
+       req['deadline'] = req['timeout'] and (monotime()+req['timeout'])
+
+       connection, err, errno = client.connect({
+               host = host;
+               port = port;
+               tls = true;
+               ctx = req['ctx'];
+               version = 2;
+               h2_settings = { ENABLE_PUSH = false; };
+       }, req['deadline'] and req['deadline']-monotime())
+       if connection == nil then
+               print('Connection error ' .. err .. ': ' .. errno)
+               return false
+       end
+       -- Close the connection (and free resources) when done
+       connection:onidle(connection.close)
+       req['connection'] = connection
+
+       return req
+end
+
+local function connection_init(time)
+       local http_util = require('http.util')
+       local ssl_ctx = require('openssl.ssl.context')
+       local headers = require('http.headers').new()
+       local request = {}
+
+       headers:append(':method', 'GET')
+       headers:upsert(':authority', http_util.to_authority(host, port, 'https'))
+       headers:upsert(':path', '/dns-query')
+       headers:upsert(':scheme', 'https')
+       headers:upsert('user-agent', 'doh2.test.lua')
+       headers:upsert('content-type', 'application/dns-message')
+       request['headers'] = headers;
+
+       local ctx = ssl_ctx.new()
+       ctx:setVerify(ssl_ctx.VERIFY_NONE)
+       request['ctx'] = ctx;
+       request['timeout'] = time
+
+       request = connection_connect(request)
+
+       request['stream1'], err, errno = request['connection']:new_stream()
+       if request['stream1'] == nil then
+               return nil, err, errno
+       end
+       request['stream2'], err, errno = request['connection']:new_stream()
+       if request['stream2'] == nil then
+               return nil, err, errno
+       end
+
+       return request
+end
+
+local function set_headers_from_body(headers, body)
+       local length
+
+       if type(body) == "string" then
+               length = #body
+       end
+       if length then
+               headers:upsert("content-length", string.format("%d", #body))
+       end
+       if not length or length > 1024 then
+               headers:append("expect", "100-continue")
+       end
+
+       return headers
+end
+
+local function send_data(req, stream_name, method, body)
+       local pass, err, errno
+       local new_headers = set_headers_from_body(req['headers'], body)
+       local stream = req[stream_name]
+
+       new_headers:upsert(':method', method)
+       do -- Write outgoing headers
+               pass, err, errno = stream:write_headers(new_headers, body == nil, req['deadline'] and req['deadline']-monotime())
+               if not pass then
+                       stream:shutdown()
+                       return nil, err, errno
+               end
+       end
+
+       if body then
+               pass, err, errno = stream:write_body_from_string(body, req['deadline'] and req['deadline']-monotime())
+               if not pass then
+                       stream:shutdown()
+                       return nil, err, errno
+               end
+       end
+
+       return pass, err, errno
+end
+
+local function read_data(req, stream)
+       local headers
+       repeat
+               local err, errno
+               headers, err, errno = stream:get_headers(req['deadline'] and (req['deadline']-monotime()))
+               if headers == nil then
+                       stream:shutdown()
+                       if err == nil then
+                               return nil, ce.strerror(ce.EPIPE), ce.EPIPE
+                       end
+                       return nil, err, errno
+               end
+       until not non_final_status(headers:get(":status"))
+
+       return headers, stream
+end
+
+local function send_and_check_ok(req, method, desc)
+       local pass, headers, stream, stream_check
+
+       -- main request
+       pass = send_data(req, 'stream1', method, req['body'])
+       if not pass then
+               return nil, nil
+       end
+
+       headers, stream, errno = read_data(req, req['stream1'])
        if errno then
                local errmsg = stream
                nok(errmsg, desc .. ': ' .. errmsg)
-               return
+               return nil, nil
        end
        same(tonumber(headers:get(':status')), 200, desc .. ': status 200')
        same(headers:get('content-type'), 'application/dns-message', desc .. ': content-type')
+       local answ_headers = headers
+
+       -- test request - noerror.test. A
+       req['headers']:upsert('content-type', 'application/dns-message')
+       if method == 'GET' then
+               req.headers:upsert(':path', '/dns-query?dns=vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB')
+       end
+       pass = send_data(req, 'stream2', method, method == 'POST' and basexx.from_base64(
+               'vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB') or nil) -- noerror.test. A
+       if not pass then
+               return nil, nil
+       end
+
+       headers, stream_check, errno = read_data(req, req['stream2'])
+       if errno then
+               local errmsg = stream_check
+               nok(errmsg, desc .. ': ' .. errmsg)
+               return nil, nil
+       end
+       same(tonumber(headers:get(':status')), 200, desc .. ' (test second stream): status 200')
+       same(headers:get('content-type'), 'application/dns-message', desc .. ' (test second stream): content-type')
+
        local body = assert(stream:get_body_as_string())
        local pkt = parse_pkt(body, desc)
-       return headers, pkt
+       req['stream1']:shutdown()
+       req['stream2']:shutdown()
+
+       return answ_headers, pkt
 end
 
-local function check_err(req, exp_status, desc)
-       local headers, errmsg, errno = req:go(8)  -- randomly chosen timeout by tkrizek
+local function send_and_check_err(req, method, exp_status, desc)
+       local pass, headers, stream, stream_check
+
+       -- main request
+       pass = send_data(req, 'stream1', method, req['body'])
+       if not pass then
+               return
+       end
+
+       headers, stream, errno = read_data(req, req['stream1'])
        if errno then
+               local errmsg = stream
                nok(errmsg, desc .. ': ' .. errmsg)
                return
        end
-       local got_status = headers:get(':status')
-       same(got_status, exp_status, desc)
-end
+       local status = tonumber(headers:get(':status'))
+       same(status, exp_status, desc .. ': get ' .. status)
 
--- check prerequisites
-local bound, port
-local host = '127.0.0.1'
-for _  = 1,10 do
-       port = math.random(30000, 39999)
-       bound = pcall(net.listen, host, port, { kind = 'doh2'})
-       if bound then
-               break
+       -- test request
+       req['headers']:upsert('content-type', 'application/dns-message')
+       if method ~= 'GET' and method ~= 'POST' then
+               method = 'GET'
+       end
+       if method == 'GET' then
+               req.headers:upsert(':path', '/dns-query?dns=vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB')
+       end
+       pass  = send_data(req, 'stream2', method, method == 'POST' and basexx.from_base64(
+               'vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB') or nil) -- noerror.test. A
+       if not pass then
+               return
+       end
+       headers, stream_check, errno = read_data(req, req['stream2'])
+       if errno then
+               local errmsg = stream_check
+               nok(errmsg, desc .. ': ' .. errmsg)
+               return
        end
+       same(tonumber(headers:get(':status')), 200, desc .. ': second stream: status 200 (exp. 200)')
+       same(headers:get('content-type'), 'application/dns-message', desc .. ': second stream: content-type')
+       req['stream1']:shutdown()
+       req['stream2']:shutdown()
 end
 
+
 if not bound then
        -- skipping doh2 tests (failure to bind may be caused by missing support during build)
        os.exit(77)
@@ -92,26 +283,14 @@ else
        policy.add(policy.suffix(policy.DENY, policy.todnames({'nxdomain.test.'})))
        policy.add(policy.suffix(gen_varying_ttls, policy.todnames({'noerror.test.'})))
 
-       local req_templ, uri_templ
-       local function start_server()
-               local request = require('http.request')
-               local ssl_ctx = require('openssl.ssl.context')
-               uri_templ = string.format('https://%s:%d/dns-query', host, port)
-               req_templ = assert(request.new_from_uri(uri_templ))
-               req_templ.headers:upsert('content-type', 'application/dns-message')
-               req_templ.ctx = ssl_ctx.new()
-               req_templ.ctx:setVerify(ssl_ctx.VERIFY_NONE)
-       end
-
 
        -- test a valid DNS query using POST
        local function test_post_servfail()
                local desc = 'valid POST query which ends with SERVFAIL'
-               local req = req_templ:clone()
-               req.headers:upsert(':method', 'POST')
-               req:set_body(basexx.from_base64(  -- servfail.test. A
+               local req = connection_init(timeout)
+               request_set_body(req, basexx.from_base64(  -- servfail.test. A
                        'FZUBAAABAAAAAAAACHNlcnZmYWlsBHRlc3QAAAEAAQ=='))
-               local headers, pkt = check_ok(req, desc)
+               local headers, pkt = send_and_check_ok(req, 'POST', desc)
                if not (headers and pkt) then
                        return
                end
@@ -122,11 +301,10 @@ else
 
        local function test_post_noerror()
                local desc = 'valid POST query which ends with NOERROR'
-               local req = req_templ:clone()
-               req.headers:upsert(':method', 'POST')
-               req:set_body(basexx.from_base64(  -- noerror.test. A
+               local req = connection_init(timeout)
+               request_set_body(req, basexx.from_base64(  -- noerror.test. A
                        'vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB'))
-               local headers, pkt = check_ok(req, desc)
+               local headers, pkt = send_and_check_ok(req, 'POST', desc)
                if not (headers and pkt) then
                        return
                end
@@ -140,11 +318,10 @@ else
 
        local function test_post_nxdomain()
                local desc = 'valid POST query which ends with NXDOMAIN'
-               local req = req_templ:clone()
-               req.headers:upsert(':method', 'POST')
-               req:set_body(basexx.from_base64(  -- nxdomain.test. A
+               local req = connection_init(timeout)
+               request_set_body(req, basexx.from_base64(  -- nxdomain.test. A
                        'viABAAABAAAAAAAACG54ZG9tYWluBHRlc3QAAAEAAQ=='))
-               local headers, pkt = check_ok(req, desc)
+               local headers, pkt = send_and_check_ok(req, 'POST', desc)
                if not (headers and pkt) then
                        return
                end
@@ -157,11 +334,10 @@ else
        local function test_huge_answer()
                policy.add(policy.suffix(gen_huge_answer, policy.todnames({'huge.test'})))
                local desc = 'POST query for a huge answer'
-               local req = req_templ:clone()
-               req.headers:upsert(':method', 'POST')
-               req:set_body(basexx.from_base64(  -- huge.test. URI, no EDNS
+               local req = connection_init(timeout)
+               request_set_body(req, basexx.from_base64(  -- huge.test. URI, no EDNS
                        'HHwBAAABAAAAAAAABGh1Z2UEdGVzdAABAAAB'))
-               local _, pkt = check_ok(req, desc)
+               local _, pkt = send_and_check_ok(req, 'POST', desc)
                same(pkt:rcode(), kres.rcode.NOERROR, desc .. ': rcode NOERROR')
                same(pkt:tc(), false, desc .. ': no TC bit')
                same(pkt:ancount(), 2, desc .. ': ANSWER contains both RRs')
@@ -169,44 +345,37 @@ else
 
        -- test an invalid DNS query using POST
        local function test_post_short_input()
-               local req = assert(req_templ:clone())
-               req.headers:upsert(':method', 'POST')
-               req:set_body(string.rep('0', 11))  -- 11 bytes < DNS msg header
-               check_err(req, '400', 'too short POST finishes with 400')
-               test_post_noerror()
+               local req = connection_init(timeout)
+               request_set_body(req, string.rep('0', 11))  -- 11 bytes < DNS msg header
+               send_and_check_err(req, 'POST', 400, 'too short POST finishes with 400')
        end
 
        local function test_post_unsupp_type()
-               local req = assert(req_templ:clone())
-               req.headers:upsert(':method', 'POST')
-               req.headers:upsert('content-type', 'application/dns+json')
-               req:set_body(string.rep('\0', 12))  -- valid message
-               check_err(req, '415', 'unsupported request content type finishes with 415')
-               test_post_noerror()
+               local req = connection_init(timeout)
+               req['headers']:upsert('content-type', 'application/dns+json')
+               request_set_body(req, string.rep('\0', 12))  -- valid message
+               send_and_check_err(req, 'POST', 415, 'unsupported request content type finishes with 415')
        end
 
        local function test_get_right_endpoints()
                local desc = 'GET query with "doh" endpoint'
-               local req = req_templ:clone()
-               req.headers:upsert(':method', 'GET')
-               req.headers:upsert(':path', '/doh?dns=vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB')
-               check_ok(req, desc)
+               local req = connection_init(timeout)
+               req['headers']:upsert(':path', '/doh?dns=vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB')
+               send_and_check_ok(req, 'GET', desc)
 
                desc = 'GET query with "dns-query" endpoint'
-               req = req_templ:clone()
-               req.headers:upsert(':method', 'GET')
-               req.headers:upsert(':path', '/dns-query?dns=vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB')
-               check_ok(req, desc)
+               req = connection_init(timeout)
+               req['headers']:upsert(':path', '/dns-query?dns=vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB')
+               send_and_check_ok(req, 'GET', desc)
        end
 
        -- test a valid DNS query using GET
        local function test_get_servfail()
                local desc = 'valid GET query which ends with SERVFAIL'
-               local req = req_templ:clone()
-               req.headers:upsert(':method', 'GET')
-               req.headers:upsert(':path', '/doh?dns='  -- servfail.test. A
+               local req = connection_init(timeout)
+               req['headers']:upsert(':path', '/doh?dns='  -- servfail.test. A
                        .. 'FZUBAAABAAAAAAAACHNlcnZmYWlsBHRlc3QAAAEAAQ')
-               local headers, pkt = check_ok(req, desc)
+               local headers, pkt = send_and_check_ok(req, 'GET', desc)
                if not (headers and pkt) then
                        return
                end
@@ -217,11 +386,10 @@ else
 
        local function test_get_noerror()
                local desc = 'valid GET query which ends with NOERROR'
-               local req = req_templ:clone()
-               req.headers:upsert(':method', 'GET')
-               req.headers:upsert(':path', '/doh?dns='  -- noerror.test. A
+               local req = connection_init(timeout)
+               req['headers']:upsert(':path', '/doh?dns='  -- noerror.test. A
                        .. 'vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB')
-               local headers, pkt = check_ok(req, desc)
+               local headers, pkt = send_and_check_ok(req, 'GET', desc)
                if not (headers and pkt) then
                        return
                end
@@ -235,11 +403,10 @@ else
 
        local function test_get_nxdomain()
                local desc = 'valid GET query which ends with NXDOMAIN'
-               local req = req_templ:clone()
-               req.headers:upsert(':method', 'GET')
-               req.headers:upsert(':path', '/doh?dns='  -- nxdomain.test. A
+               local req = connection_init(timeout)
+               req['headers']:upsert(':path', '/doh?dns='  -- nxdomain.test. A
                        .. 'viABAAABAAAAAAAACG54ZG9tYWluBHRlc3QAAAEAAQ')
-               local headers, pkt = check_ok(req, desc)
+               local headers, pkt = send_and_check_ok(req, 'GET', desc)
                if not (headers and pkt) then
                        return
                end
@@ -250,99 +417,79 @@ else
 
        local function test_get_other_params_before_dns()
                local desc = 'GET query with other parameters before dns is valid'
-               local req = req_templ:clone()
-               req.headers:upsert(':method', 'GET')
-               req.headers:upsert(':path',
-               '/doh?other=something&another=something&dns=vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB')
-               check_ok(req, desc)
+               local req = connection_init(timeout)
+               req['headers']:upsert(':path',
+                       '/doh?other=something&another=something&dns=vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB')
+               send_and_check_ok(req, 'GET', desc)
        end
 
        local function test_get_other_params_after_dns()
                local desc = 'GET query with other parameters after dns is valid'
-               local req = req_templ:clone()
-               req.headers:upsert(':method', 'GET')
-               req.headers:upsert(':path',
-               '/doh?dns=vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB&other=something&another=something')
-               check_ok(req, desc)
+               local req = connection_init(timeout)
+               req['headers']:upsert(':path',
+                       '/doh?dns=vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB&other=something&another=something')
+               send_and_check_ok(req, 'GET', desc)
        end
 
        local function test_get_other_params()
                local desc = 'GET query with other parameters than dns on both sides is valid'
-               local req = req_templ:clone()
-               req.headers:upsert(':method', 'GET')
+               local req = connection_init(timeout)
                req.headers:upsert(':path',
-               '/doh?other=something&dns=vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB&another=something')
-               check_ok(req, desc)
+                       '/doh?other=something&dns=vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB&another=something')
+               send_and_check_ok(req, 'GET', desc)
        end
 
        -- test an invalid DNS query using GET
        local function test_get_wrong_endpoints()
-               local req = req_templ:clone()
-               req.headers:upsert(':method', 'GET')
-               req.headers:upsert(':path', '/bad?dns=vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB')
-               check_err(req, '400', 'wrong "bad" endpoint finishes with 400')
-               test_get_other_params()
+               local req = connection_init(timeout)
+               req['headers']:upsert(':path', '/bad?dns=vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB')
+               send_and_check_err(req, 'GET', 400, 'wrong "bad" endpoint finishes with 400')
 
-               req = req_templ:clone()
-               req.headers:upsert(':method', 'GET')
-               req.headers:upsert(':path', '/dns?dns=vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB')
-               check_err(req, '400', 'wrong "dns" endpoint finishes with 400')
-               test_get_other_params()
+               req = connection_init(timeout)
+               req['headers']:upsert(':path', '/dns?dns=vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB')
+               send_and_check_err(req, 'GET', 400, 'wrong "dns" endpoint finishes with 400')
        end
 
        local function test_get_no_dns_param()
-               local req = assert(req_templ:clone())
-               req.headers:upsert(':method', 'GET')
-               req.headers:upsert(':path', '/doh?notdns=' .. basexx.to_url64(string.rep('\0', 1024)))
-               check_err(req, '400', 'GET without dns parameter finishes with 400')
-               test_get_other_params()
+               local req = connection_init(timeout)
+               req['headers']:upsert(':path', '/doh?notdns=' .. basexx.to_url64(string.rep('\0', 1024)))
+               send_and_check_err(req, 'GET', 400, 'GET without dns parameter finishes with 400')
        end
 
        local function test_get_unparseable()
-               local req = assert(req_templ:clone())
-               req.headers:upsert(':method', 'GET')
-               req.headers:upsert(':path', '/doh??dns=' .. basexx.to_url64(string.rep('\0', 1024)))
-               check_err(req, '400', 'unparseable GET finishes with 400')
-               test_get_other_params()
+               local req = connection_init(timeout)
+               req['headers']:upsert(':path', '/doh??dns=' .. basexx.to_url64(string.rep('\0', 1024)))
+               send_and_check_err(req, 'GET', 400, 'unparseable GET finishes with 400')
        end
 
        local function test_get_invalid_b64()
-               local req = assert(req_templ:clone())
-               req.headers:upsert(':method', 'GET')
-               req.headers:upsert(':path', '/doh?dns=thisisnotb64')
-               check_err(req, '400', 'GET with invalid base64 finishes with 400')
-               test_get_other_params()
+               local req = connection_init(timeout)
+               req['headers']:upsert(':path', '/doh?dns=thisisnotb64')
+               send_and_check_err(req, 'GET', 400, 'GET with invalid base64 finishes with 400')
        end
 
        local function test_get_invalid_chars()
-               local req = assert(req_templ:clone())
-               req.headers:upsert(':method', 'GET')
-               req.headers:upsert(':path', '/doh?dns=' .. basexx.to_url64(string.rep('\0', 200)) .. '@#$%?!')
-               check_err(req, '400', 'GET with invalid characters in b64 finishes with 400')
-               test_get_other_params()
+               local req = connection_init(timeout)
+               req['headers']:upsert(':path', '/doh?dns=' .. basexx.to_url64(string.rep('\0', 200)) .. '@#$%?!')
+               send_and_check_err(req, 'GET', 400, 'GET with invalid characters in b64 finishes with 400')
        end
 
        local function test_get_two_ampersands()
-               local req = req_templ:clone()
-               req.headers:upsert(':method', 'GET')
-               req.headers:upsert(':path',
-               '/doh?other=something&&dns=vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB')
-               check_err(req, '400', 'GET with two ampersands finishes with 400')
-               test_get_other_params()
-
-               req = req_templ:clone()
-               req.headers:upsert(':method', 'GET')
-               req.headers:upsert(':path',
-               '/doh?other=something&&nodns=vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB')
-               check_err(req, '400', 'GET with two ampersands finishes with 400')
-               test_get_other_params()
+               local req = connection_init(timeout)
+               req['headers']:upsert(':path',
+                       '/doh?other=something&&dns=vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB')
+               send_and_check_err(req, 'GET', 400, 'GET with two ampersands finishes with 400')
+
+               req = connection_init(timeout)
+               req['headers']:upsert(':path',
+                       '/doh?other=something&&nodns=vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB')
+               send_and_check_err(req, 'GET', 400, 'GET with two ampersands finishes with 400')
        end
 
        local function test_unsupp_method()
-               local req = assert(req_templ:clone())
-               req.headers:upsert(':method', 'PUT')
-               check_err(req, '405', 'unsupported method finishes with 405')
-               test_get_other_params()
+               local req = connection_init(timeout)
+               req['headers']:upsert(':method', 'PUT')
+               send_and_check_err(req, 'PUT', 405, 'unsupported method finishes with 405')
        end
 
        local function test_dstaddr()
@@ -356,11 +503,10 @@ else
                end
                policy.add(policy.suffix(check_dstaddr, policy.todnames({'dstaddr.test'})))
                local desc = 'valid POST query has server address available in request'
-               local req = req_templ:clone()
-               req.headers:upsert(':method', 'POST')
-               req:set_body(basexx.from_base64(  -- dstaddr.test. A
+               local req = connection_init(timeout)
+               request_set_body(req, basexx.from_base64(  -- dstaddr.test. A
                        'FnkBAAABAAAAAAAAB2RzdGFkZHIEdGVzdAAAAQAB'))
-               check_ok(req, desc)
+               send_and_check_ok(req, 'POST', desc)
                ok(triggered, 'dstaddr policy was triggered')
        end
 
@@ -373,11 +519,10 @@ else
                view:addr('::/0', policy_refuse)
 
                local desc = 'valid POST query has source address available in request'
-               local req = req_templ:clone()
-               req.headers:upsert(':method', 'POST')
-               req:set_body(basexx.from_base64(  -- srcaddr.test.knot-resolver.cz TXT
+               local req = connection_init(timeout)
+               request_set_body(req, basexx.from_base64(  -- srcaddr.test.knot-resolver.cz TXT
                        'QNQBAAABAAAAAAAAB3NyY2FkZHIEdGVzdA1rbm90LXJlc29sdmVyAmN6AAAQAAE'))
-               local _, pkt = check_ok(req, desc)
+               local _, pkt = send_and_check_ok(req, 'POST', desc)
                same(pkt:rcode(), kres.rcode.REFUSED, desc .. ': view module caught it')
 
                modules.unload('view')
@@ -385,7 +530,6 @@ else
 
        -- plan tests
        local tests = {
-               start_server,
                test_post_servfail,
                test_post_noerror,
                test_post_nxdomain,