]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
Revert "Merge branch '618-doh2-respond-to-invalid-requests-with-proper-status-code...
authorTomas Krizek <tomas.krizek@nic.cz>
Tue, 30 Mar 2021 11:30:51 +0000 (13:30 +0200)
committerTomas Krizek <tomas.krizek@nic.cz>
Tue, 30 Mar 2021 11:30:51 +0000 (13:30 +0200)
This reverts commit 4079a1a962cc528b30d8b0b330c329bf83d85fe8, reversing
changes made to a900fdbf47c181487edf8c6c07a079708c2647e3.

NEWS
daemon/http.c
daemon/http.h
tests/config/doh2.test.lua

diff --git a/NEWS b/NEWS
index c8682aba55ccb68bbd5ae93cd9bf1d9dd06e394b..116225e06f48648587150e62c21bdf8e2f57f24b 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -3,7 +3,6 @@ Knot Resolver 5.3.1 (2021-03-dd)
 
 Improvements
 ------------
-- doh2: send HTTP error status codes (#618, !1102)
 - policy.STUB: try to avoid TCP (compared to 5.3.0; !1155)
 
 Bugfixes
index d31280fce97b3dc0ade09bf3c71a6c85b4c0a62d..f72465f65e1313e187cd763815077d0a416fa8ee 100644 (file)
@@ -45,24 +45,6 @@ struct http_data {
        uv_write_t *req;
 };
 
-static void http_stream_status_free(struct http_stream_status *stat)
-{
-       if (!stat)
-               return;
-
-       free(stat->err_msg);
-       stat->err_msg = NULL;
-       free(stat);
-}
-
-static int status_free(trie_val_t *stat, void *null)
-{
-       assert(stat);
-       http_stream_status_free(*stat);
-       return 0;
-}
-
-
 /*
  * Write HTTP/2 protocol data to underlying transport layer.
  */
@@ -149,167 +131,10 @@ static int send_data_callback(nghttp2_session *h2, nghttp2_frame *frame, const u
        return 0;
 }
 
-/*
- * Provide data from buffer to HTTP/2 library.
- *
- * To avoid copying the packet wire buffer, we use NGHTTP2_DATA_FLAG_NO_COPY
- * and take care of sending entire DATA frames ourselves with nghttp2_send_data_callback.
- *
- * See https://www.nghttp2.org/documentation/types.html#c.nghttp2_data_source_read_callback
- */
-static ssize_t read_callback(nghttp2_session *h2, int32_t stream_id, uint8_t *buf,
-                            size_t length, uint32_t *data_flags,
-                            nghttp2_data_source *source, void *user_data)
-{
-       struct http_data *data;
-       size_t avail;
-       size_t send;
-
-       if (!source->ptr) {
-               *data_flags |= NGHTTP2_DATA_FLAG_EOF;
-               return 0;
-       }
-
-       data = (struct http_data*)source->ptr;
-       avail = data->len - data->pos;
-       send = MIN(avail, length);
-
-       if (avail == send)
-               *data_flags |= NGHTTP2_DATA_FLAG_EOF;
-
-       *data_flags |= NGHTTP2_DATA_FLAG_NO_COPY;
-       return send;
-}
-
-/*
- * Send http error status code.
- */
-static int send_err_status(struct http_ctx *ctx, int32_t stream_id)
-{
-       int ret;
-       int status_len;
-       nghttp2_data_provider prov;
-       trie_val_t *stat_p = trie_get_try(ctx->stream_status, (char *)&stream_id, sizeof(stream_id));
-
-       if (!stat_p || !*stat_p)
-               return kr_error(EINVAL);
-       struct http_stream_status *stat = *stat_p;
-
-       prov.source.ptr = NULL;
-       prov.read_callback = read_callback;
-
-       char status_str[MAX_DECIMAL_LENGTH(stat->err_status)] = { 0 };
-       status_len = snprintf(status_str, MAX_DECIMAL_LENGTH(stat->err_status), "%u", stat->err_status);
-       nghttp2_nv hdrs_err[] = {
-               MAKE_NV(":status", 7, status_str, status_len),
-       };
-
-       if (stat->err_msg) {
-               struct http_data *data = malloc(sizeof(struct http_data));
-               if (!data)
-                       return kr_error(ENOMEM);
-
-               data->buf = (uint8_t *)stat->err_msg;
-               data->len = strlen(stat->err_msg);
-               data->pos = 0;
-               data->on_write = NULL;
-               data->req = NULL;
-               data->ttl = 0;
-               prov.source.ptr = data;
-
-               /* data will be freed in callback. */
-               ret = nghttp2_session_set_stream_user_data(ctx->h2, stream_id, (void*)data);
-               if (ret != 0)
-                       return kr_error(EIO);
-       }
-
-       ret = nghttp2_submit_response(ctx->h2, stream_id, hdrs_err, sizeof(hdrs_err)/sizeof(*hdrs_err), &prov);
-       if (ret != 0)
-               return kr_error(EIO);
-
-       if (queue_len(ctx->streams) != 0)
-               queue_pop(ctx->streams);
-
-       return 0;
-}
-
-/*
- * Set error status for particular stream_id and return stream status or NULL on fail.
- *
- * status_msg is optional and defines error message.
- */
-static struct http_stream_status * set_error_status(struct http_ctx *ctx, int32_t stream_id, int status, const char *const status_msg)
-{
-
-       trie_val_t *stat_p = trie_get_ins(ctx->stream_status, (char *)&stream_id, sizeof(stream_id));
-       struct http_stream_status *stat = *stat_p;
-       if (stat && stat->err_status != 200)
-               return stat;
-
-       // add new item to array
-       if (!stat) {
-               stat = malloc(sizeof(*stat));
-               if (!stat)
-                       return NULL;
-
-               *stat_p = stat;
-               stat->err_msg = NULL;
-       }
-       stat->stream_id = stream_id;
-       stat->err_status = status;
-
-       if (!status_msg) {
-               if (stat->err_msg) { // remove previous message
-                       free(stat->err_msg);
-                       stat->err_msg = NULL;
-               }
-
-               return stat;
-       }
-
-       stat->err_msg = realloc(stat->err_msg, sizeof(*stat->err_msg) * (strlen(status_msg) + 2));
-       if (!stat->err_msg) {
-               return stat;
-       }
-
-       memcpy(stat->err_msg, status_msg, strlen(status_msg));
-       stat->err_msg[strlen(status_msg)] = '\n';
-       stat->err_msg[strlen(status_msg)+1] = '\0';
-
-       return stat;
-}
-
-/*
- * Reinit temporaly data of current stream
- */
-static void http_status_reinit(struct http_ctx *ctx, int stream_id)
-{
-       ctx->current_method = HTTP_METHOD_NONE;
-       ctx->current_stream = NULL;
-       ctx->buf_pos = 0;
-       if (ctx->uri_path) {
-               free(ctx->uri_path);
-               ctx->uri_path = NULL;
-       }
-       if (ctx->content_type) {
-               free(ctx->content_type);
-               ctx->content_type = NULL;
-       }
-}
-
-static void http_status_reinit_error(struct http_ctx *ctx, int stream_id)
-{
-
-       if (ctx->current_method == HTTP_METHOD_POST)
-               queue_pop(ctx->streams);
-
-       http_status_reinit(ctx, stream_id);
-}
-
 /*
  * Check endpoint and uri path
  */
-static int check_uri(struct http_ctx *ctx, int32_t stream_id, const char* uri_path)
+static int check_uri(const char* uri_path)
 {
        static const char key[] = "dns=";
        static const char *delim = "&";
@@ -318,7 +143,6 @@ static int check_uri(struct http_ctx *ctx, int32_t stream_id, const char* uri_pa
        char *end_prev;
        ssize_t endpoint_len;
        ssize_t ret;
-       struct http_stream_status *stat;
 
        if (!uri_path)
                return kr_error(EINVAL);
@@ -346,10 +170,8 @@ static int check_uri(struct http_ctx *ctx, int32_t stream_id, const char* uri_pa
                        break;
        }
 
-       if (ret) { /* no endpoint found */
-               stat = set_error_status(ctx, stream_id, 400, "missing endpoint");
-               return stat ? kr_error(EINVAL) : kr_error(ENOMEM);
-       }
+       if (ret) /* no endpoint found */
+               return -1;
        if (endpoint_len == strlen(path) - 1) /* done for POST method */
                return 0;
 
@@ -360,51 +182,38 @@ static int check_uri(struct http_ctx *ctx, int32_t stream_id, const char* uri_pa
                        if (!strncmp(beg, key, 4)) { /* dns variable in path found */
                                break;
                        }
-                       end_prev = beg + strlen(beg) - 1;
+                       end_prev = beg + strlen(beg);
                        beg = strtok(NULL, delim);
-                       if (beg && beg-1 != end_prev+1) { /* detect && */
-                               stat = set_error_status(ctx, stream_id, 400, "invalid uri path");
-                               return stat ? kr_error(EINVAL) : kr_error(ENOMEM);
+                       if (beg-1 != end_prev) { /* detect && */
+                               return -1;
                        }
                }
 
                if (!beg) { /* no dns variable in path */
-                       stat = set_error_status(ctx, stream_id, 400, "'dns' key in path not found");
-                       return stat ? kr_error(EINVAL) : kr_error(ENOMEM);
-               }
-       } else {
-               if (!beg) { /* no dns variable in path */
-                       stat = set_error_status(ctx, stream_id, 400, "'dns' key in path not found");
-                       return stat ? kr_error(EINVAL) : kr_error(ENOMEM);
+                       return -1;
                }
        }
 
        return 0;
 }
 
-
 /*
  * Process a query from URI path if there's base64url encoded dns variable.
  */
-static int process_uri_path(struct http_ctx *ctx, int32_t stream_id)
+static int process_uri_path(struct http_ctx *ctx, const char* path, int32_t stream_id)
 {
+       if (!ctx || !path)
+               return kr_error(EINVAL);
+
        static const char key[] = "dns=";
-       char *beg, *end;
+       char *beg = strstr(path, key);
+       char *end;
        size_t remaining;
        ssize_t ret;
        uint8_t *dest;
-       struct http_stream_status *stat;
 
-       if (!ctx || !ctx->uri_path) {
-               stat = set_error_status(ctx, stream_id, 400, "invalid uri path");
-               return stat ? 0 : kr_error(ENOMEM);
-       }
-
-       beg = strstr(ctx->uri_path, key);
-       if (!beg) {  /* No dns variable in ctx->uri_path. */
-               stat = set_error_status(ctx, stream_id, 400, "'dns' key in path not found");
-               return stat ? 0 : kr_error(ENOMEM);
-       }
+       if (!beg)  /* No dns variable in path. */
+               return 0;
 
        beg += sizeof(key) - 1;
        end = strchr(beg, '&');
@@ -418,13 +227,9 @@ static int process_uri_path(struct http_ctx *ctx, int32_t stream_id)
        ret = kr_base64url_decode((uint8_t*)beg, end - beg, dest, remaining);
        if (ret < 0) {
                ctx->buf_pos = 0;
-               kr_log_verbose("[http] base64url decode failed %s\n", strerror(ret));
-               if (ret == KNOT_ERANGE) {
-                       stat = set_error_status(ctx, stream_id, 414, NULL);// ? ;
-               } else {
-                       stat = set_error_status(ctx, stream_id, 400, NULL);
-               }
-               return stat ? 0 : kr_error(ENOMEM);
+               kr_log_verbose("[http] base64url decode failed %s\n",
+                              strerror(ret));
+               return ret;
        }
 
        ctx->buf_pos += ret;
@@ -432,6 +237,12 @@ static int process_uri_path(struct http_ctx *ctx, int32_t stream_id)
        return 0;
 }
 
+static void refuse_stream(nghttp2_session *h2, int32_t stream_id)
+{
+       nghttp2_submit_rst_stream(
+               h2, NGHTTP2_FLAG_NONE, stream_id, NGHTTP2_REFUSED_STREAM);
+}
+
 /*
  * Save stream id from first header's frame.
  *
@@ -450,13 +261,12 @@ static int begin_headers_callback(nghttp2_session *h2, const nghttp2_frame *fram
                return 0;
        }
 
-       if (ctx->current_stream != NULL) {
+       if (ctx->incomplete_stream != -1) {
                kr_log_verbose(
-                       "[http] stream %d incomplete\n", ctx->current_stream->stream_id);
-               if (!set_error_status(ctx, stream_id, 501, "incomplete stream"))
-                       return NGHTTP2_ERR_CALLBACK_FAILURE;
+                       "[http] stream %d incomplete, refusing\n", ctx->incomplete_stream);
+               refuse_stream(h2, stream_id);
        } else {
-               ctx->current_stream = set_error_status(ctx, stream_id, 200, NULL);
+               ctx->incomplete_stream = stream_id;
        }
        return 0;
 }
@@ -477,26 +287,24 @@ static int header_callback(nghttp2_session *h2, const nghttp2_frame *frame,
        if (frame->hd.type != NGHTTP2_HEADERS)
                return 0;
 
-       if (ctx->current_stream->stream_id != stream_id) {
+       if (ctx->incomplete_stream != stream_id) {
                kr_log_verbose(
-                       "[http] stream %d incomplete\n", ctx->current_stream->stream_id);
-               if (!set_error_status(ctx, stream_id, 501, "incomplete stream"))
-                       return NGHTTP2_ERR_CALLBACK_FAILURE;
+                       "[http] stream %d incomplete, refusing\n", ctx->incomplete_stream);
+               refuse_stream(h2, stream_id);
                return 0;
        }
 
        if (!strcasecmp(":path", (const char *)name)) {
-               int rc = check_uri(ctx, stream_id, (const char *)value);
-               if (rc < 0) {
-                       if (rc == kr_error(ENOMEM))
-                               return NGHTTP2_ERR_CALLBACK_FAILURE;
-               } else {
-                       ctx->uri_path = malloc(sizeof(*ctx->uri_path) * (valuelen + 1));
-                       if (!ctx->uri_path)
-                               return NGHTTP2_ERR_CALLBACK_FAILURE;
-                       memcpy(ctx->uri_path, value, valuelen);
-                       ctx->uri_path[valuelen] = '\0';
+               if (check_uri((const char *)value) < 0) {
+                       refuse_stream(h2, stream_id);
+                       return 0;
                }
+
+               ctx->uri_path = malloc(sizeof(*ctx->uri_path) * (valuelen + 1));
+               if (!ctx->uri_path)
+                       return kr_error(ENOMEM);
+               memcpy(ctx->uri_path, value, valuelen);
+               ctx->uri_path[valuelen] = '\0';
        }
 
        if (!strcasecmp(":method", (const char *)name)) {
@@ -509,14 +317,6 @@ static int header_callback(nghttp2_session *h2, const nghttp2_frame *frame,
                }
        }
 
-       if (!strcasecmp("content-type", (const char *)name)) {
-               ctx->content_type = malloc(sizeof(*ctx->content_type) * valuelen+1);
-               if (!ctx->content_type)
-                       return NGHTTP2_ERR_CALLBACK_FAILURE;
-               memcpy(ctx->content_type, value, valuelen);
-               ctx->content_type[valuelen] = '\0';
-       }
-
        return 0;
 }
 
@@ -534,15 +334,14 @@ static int data_chunk_recv_callback(nghttp2_session *h2, uint8_t flags, int32_t
        struct http_ctx *ctx = (struct http_ctx *)user_data;
        ssize_t remaining;
        ssize_t required;
-       assert(ctx->current_stream);
-       bool is_first = queue_len(ctx->streams) == 0 || queue_tail(ctx->streams) != ctx->current_stream->stream_id;
+       bool is_first = queue_len(ctx->streams) == 0 || queue_tail(ctx->streams) != ctx->incomplete_stream;
 
-       if (ctx->current_stream->stream_id != stream_id) {
+       if (ctx->incomplete_stream != stream_id) {
                kr_log_verbose(
-                       "[http] stream %d incomplete\n",
-                       ctx->current_stream->stream_id);
-               if (!set_error_status(ctx, stream_id, 501, "incomplete stream"))
-                       return NGHTTP2_ERR_CALLBACK_FAILURE;
+                       "[http] stream %d incomplete, refusing\n",
+                       ctx->incomplete_stream);
+               refuse_stream(h2, stream_id);
+               ctx->incomplete_stream = -1;
                return 0;
        }
 
@@ -554,11 +353,8 @@ static int data_chunk_recv_callback(nghttp2_session *h2, uint8_t flags, int32_t
 
        if (required > remaining) {
                kr_log_error("[http] insufficient space in buffer\n");
-               if (!set_error_status(ctx, stream_id, 413, NULL)) {
-                       http_status_reinit_error(ctx, stream_id);
-                       return NGHTTP2_ERR_CALLBACK_FAILURE;
-               }
-               return 0;
+               ctx->incomplete_stream = -1;
+               return NGHTTP2_ERR_CALLBACK_FAILURE;
        }
 
        if (is_first) {
@@ -586,76 +382,27 @@ static int on_frame_recv_callback(nghttp2_session *h2, const nghttp2_frame *fram
        int32_t stream_id = frame->hd.stream_id;
        assert(stream_id != -1);
 
-       if (stream_id == 0 || ctx == NULL)
-               return 0;
-
-       if (ctx->current_method == HTTP_METHOD_NONE) {
-               kr_log_verbose("[http] unsupported HTTP method\n");
-               if (!set_error_status(ctx, stream_id, 405, "only HTTP POST and GET are supported\n")) {
-                       http_status_reinit_error(ctx, stream_id);
-                       return NGHTTP2_ERR_CALLBACK_FAILURE;
+       if ((frame->hd.flags & NGHTTP2_FLAG_END_STREAM) && ctx->incomplete_stream == stream_id) {
+               if (ctx->current_method == HTTP_METHOD_GET) {
+                       if (process_uri_path(ctx, ctx->uri_path, stream_id) < 0) {
+                               refuse_stream(h2, stream_id);
+                       }
                }
-       }
+               ctx->incomplete_stream = -1;
+               ctx->current_method = HTTP_METHOD_NONE;
+               free(ctx->uri_path);
+               ctx->uri_path = NULL;
 
-       if (ctx->content_type && strcasecmp("application/dns-message", (const char *)ctx->content_type)) {
-               kr_log_verbose("[http] unsupported content-type %s\n", ctx->content_type);
-               if (!set_error_status(ctx, stream_id, 415, "only Content-Type: application/dns-message is supported\n")) {
-                       http_status_reinit_error(ctx, stream_id);
+               len = ctx->buf_pos - sizeof(uint16_t);
+               if (len <= 0 || len > KNOT_WIRE_MAX_PKTSIZE) {
+                       kr_log_verbose("[http] invalid dnsmsg size: %zd B\n", len);
                        return NGHTTP2_ERR_CALLBACK_FAILURE;
                }
-       }
 
-       if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
-               struct http_stream_status *stat = ctx->current_stream;
-               assert(stat);
-               if (stat->stream_id == stream_id) {
-                       if (stat->err_status == 200) {
-                               if (ctx->current_method == HTTP_METHOD_GET) {
-                                       if (process_uri_path(ctx, stream_id) < 0) {
-                                               http_status_reinit_error(ctx, stream_id);
-                                               return NGHTTP2_ERR_CALLBACK_FAILURE;
-                                       }
-                               }
-
-                               if (ctx->buf_pos) {
-                                       len = ctx->buf_pos - sizeof(uint16_t);
-                                       if (len <= 0 || len > KNOT_WIRE_MAX_PKTSIZE) {
-                                               kr_log_verbose("[http] invalid dnsmsg size: %zd B\n", len);
-                                               http_status_reinit_error(ctx, stream_id);
-                                               return NGHTTP2_ERR_CALLBACK_FAILURE;
-                                       }
-
-                                       if (len < 12) {
-                                               if (!set_error_status(ctx, stream_id, 400, "input too short\n")) {
-                                                       http_status_reinit_error(ctx, stream_id);
-                                                       return NGHTTP2_ERR_CALLBACK_FAILURE;
-                                               }
-                                       }
-
-                                       if (stat->err_status == 200) {
-                                               knot_wire_write_u16(ctx->buf, len);
-                                               ctx->submitted += ctx->buf_pos;
-                                               ctx->buf += ctx->buf_pos;
-                                       }
-                               }
-                       }
-
-                       if (stat->err_status != 200) {
-                               if (send_err_status(ctx, stream_id) < 0) {
-                                       http_status_reinit_error(ctx, stream_id);
-                                       return NGHTTP2_ERR_CALLBACK_FAILURE;
-                               }
-                       }
-
-                       http_status_reinit(ctx, stream_id);
-                       ctx->buf_pos = 0;
-               } else {
-                       /* send error for non-processed stream */
-                       if (send_err_status(ctx, stream_id) < 0) {
-                               http_status_reinit_error(ctx, stream_id);
-                               return NGHTTP2_ERR_CALLBACK_FAILURE;
-                       }
-               }
+               knot_wire_write_u16(ctx->buf, len);
+               ctx->submitted += ctx->buf_pos;
+               ctx->buf += ctx->buf_pos;
+               ctx->buf_pos = 0;
        }
 
        return 0;
@@ -666,11 +413,10 @@ static int on_frame_recv_callback(nghttp2_session *h2, const nghttp2_frame *fram
  */
 static void on_pkt_write(struct http_data *data, int status)
 {
-       if (!data)
+       if (!data || !data->req || !data->on_write)
                return;
 
-       if (data->req && data->on_write)
-               data->on_write(data->req, status);
+       data->on_write(data->req, status);
 
        free(data);
 }
@@ -684,19 +430,12 @@ static void on_pkt_write(struct http_data *data, int status)
 static int on_stream_close_callback(nghttp2_session *h2, int32_t stream_id,
                                    uint32_t error_code, void *user_data)
 {
-       struct http_ctx *ctx = (struct http_ctx *)user_data;
        struct http_data *data;
-       struct http_stream_status *stat;
-       int ret;
 
        data = nghttp2_session_get_stream_user_data(h2, stream_id);
        if (data)
                on_pkt_write(data, error_code == 0 ? 0 : kr_error(EIO));
 
-       ret = trie_del(ctx->stream_status, (char *)&stream_id, sizeof(stream_id), (trie_val_t *)&stat);
-       if (ret == 0)
-               http_stream_status_free(stat);
-
        return 0;
 }
 
@@ -733,13 +472,10 @@ struct http_ctx* http_new(struct session *session, http_send_callback send_cb)
        ctx->send_cb = send_cb;
        ctx->session = session;
        queue_init(ctx->streams);
-       ctx->current_stream = NULL;
+       ctx->incomplete_stream = -1;
        ctx->submitted = 0;
        ctx->current_method = HTTP_METHOD_NONE;
        ctx->uri_path = NULL;
-       ctx->content_type = NULL;
-       ctx->stream_status = trie_create(NULL);
-
 
        nghttp2_session_server_new(&ctx->h2, callbacks, ctx);
        nghttp2_submit_settings(ctx->h2, NGHTTP2_FLAG_NONE,
@@ -786,6 +522,33 @@ ssize_t http_process_input_data(struct session *session, const uint8_t *buf,
        return ctx->submitted;
 }
 
+/*
+ * Provide data from buffer to HTTP/2 library.
+ *
+ * To avoid copying the packet wire buffer, we use NGHTTP2_DATA_FLAG_NO_COPY
+ * and take care of sending entire DATA frames ourselves with nghttp2_send_data_callback.
+ *
+ * See https://www.nghttp2.org/documentation/types.html#c.nghttp2_data_source_read_callback
+ */
+static ssize_t read_callback(nghttp2_session *h2, int32_t stream_id, uint8_t *buf,
+                            size_t length, uint32_t *data_flags,
+                            nghttp2_data_source *source, void *user_data)
+{
+       struct http_data *data;
+       size_t avail;
+       size_t send;
+
+       data = (struct http_data*)source->ptr;
+       avail = data->len - data->pos;
+       send = MIN(avail, length);
+
+       if (avail == send)
+               *data_flags |= NGHTTP2_DATA_FLAG_EOF;
+
+       *data_flags |= NGHTTP2_DATA_FLAG_NO_COPY;
+       return send;
+}
+
 /*
  * Send dns response provided by the HTTTP/2 data provider.
  *
@@ -900,11 +663,7 @@ void http_free(struct http_ctx *ctx)
        if (!ctx)
                return;
 
-       trie_apply(ctx->stream_status, status_free, NULL);
-       trie_free(ctx->stream_status);
-
        queue_deinit(ctx->streams);
        nghttp2_session_del(ctx->h2);
-       free(ctx->content_type);
        free(ctx);
 }
index 2f9c84529cd1ad4810fd62058302341f1f0bab53..f0662779b8d171e3b60a7aec389790ec8b603111 100644 (file)
@@ -32,12 +32,6 @@ typedef enum {
        HTTP_METHOD_POST = 2,
 } http_method_t;
 
-struct http_stream_status {
-       int32_t stream_id;
-       int err_status;
-       char *err_msg;
-};
-
 struct http_ctx {
        struct nghttp2_session *h2;
        http_send_callback send_cb;
@@ -47,12 +41,9 @@ struct http_ctx {
        ssize_t submitted;
        http_method_t current_method;
        char *uri_path;
-       char *content_type;
        uint8_t *buf;  /* Part of the wire_buf that belongs to current HTTP/2 stream. */
        ssize_t buf_pos;
        ssize_t buf_size;
-       trie_t *stream_status;
-       struct http_stream_status *current_stream;
 };
 
 #if ENABLE_DOH2
index 98bcbccff42ef4a4240f2bd2bed49b3cc624ddc1..2c4779e90aeb406c57dce20d8c2b104093486c53 100644 (file)
@@ -1,25 +1,13 @@
 -- 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,
@@ -61,220 +49,41 @@ function parse_pkt(input, desc)
        return pkt
 end
 
-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'])
+local function check_ok(req, desc)
+       local headers, stream, errno = req:go(8)  -- randomly chosen timeout by tkrizek
        if errno then
                local errmsg = stream
                nok(errmsg, desc .. ': ' .. errmsg)
-               return nil, nil
+               return
        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)
-       req['stream1']:shutdown()
-       req['stream2']:shutdown()
-
-       return answ_headers, pkt
+       return headers, pkt
 end
 
-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 status = tonumber(headers:get(':status'))
-       same(status, exp_status, desc .. ': get ' .. status)
+--local function check_err(req, exp_status, desc)
+--     local headers, errmsg, errno = req:go(8)  -- randomly chosen timeout by tkrizek
+--     if errno then
+--             nok(errmsg, desc .. ': ' .. errmsg)
+--             return
+--     end
+--     local got_status = headers:get(':status')
+--     same(got_status, exp_status, desc)
+--end
 
-       -- 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
+-- 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
        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)
@@ -283,14 +92,26 @@ 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 = connection_init(timeout)
-               request_set_body(req, basexx.from_base64(  -- servfail.test. A
+               local req = req_templ:clone()
+               req.headers:upsert(':method', 'POST')
+               req:set_body(basexx.from_base64(  -- servfail.test. A
                        'FZUBAAABAAAAAAAACHNlcnZmYWlsBHRlc3QAAAEAAQ=='))
-               local headers, pkt = send_and_check_ok(req, 'POST', desc)
+               local headers, pkt = check_ok(req, desc)
                if not (headers and pkt) then
                        return
                end
@@ -301,10 +122,11 @@ else
 
        local function test_post_noerror()
                local desc = 'valid POST query which ends with NOERROR'
-               local req = connection_init(timeout)
-               request_set_body(req, basexx.from_base64(  -- noerror.test. A
+               local req = req_templ:clone()
+               req.headers:upsert(':method', 'POST')
+               req:set_body(basexx.from_base64(  -- noerror.test. A
                        'vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB'))
-               local headers, pkt = send_and_check_ok(req, 'POST', desc)
+               local headers, pkt = check_ok(req, desc)
                if not (headers and pkt) then
                        return
                end
@@ -318,10 +140,11 @@ else
 
        local function test_post_nxdomain()
                local desc = 'valid POST query which ends with NXDOMAIN'
-               local req = connection_init(timeout)
-               request_set_body(req, basexx.from_base64(  -- nxdomain.test. A
+               local req = req_templ:clone()
+               req.headers:upsert(':method', 'POST')
+               req:set_body(basexx.from_base64(  -- nxdomain.test. A
                        'viABAAABAAAAAAAACG54ZG9tYWluBHRlc3QAAAEAAQ=='))
-               local headers, pkt = send_and_check_ok(req, 'POST', desc)
+               local headers, pkt = check_ok(req, desc)
                if not (headers and pkt) then
                        return
                end
@@ -334,48 +157,54 @@ 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 = connection_init(timeout)
-               request_set_body(req, basexx.from_base64(  -- huge.test. URI, no EDNS
+               local req = req_templ:clone()
+               req.headers:upsert(':method', 'POST')
+               req:set_body(basexx.from_base64(  -- huge.test. URI, no EDNS
                        'HHwBAAABAAAAAAAABGh1Z2UEdGVzdAABAAAB'))
-               local _, pkt = send_and_check_ok(req, 'POST', desc)
+               local _, pkt = check_ok(req, 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')
        end
 
        -- test an invalid DNS query using POST
-       local function test_post_short_input()
-               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 = 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 = 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 = connection_init(timeout)
-               req['headers']:upsert(':path', '/dns-query?dns=vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB')
-               send_and_check_ok(req, 'GET', desc)
-       end
+--     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')
+--     end
+--
+--     local function test_post_long_input()
+--             local req = assert(req_templ:clone())
+--             req.headers:upsert(':method', 'POST')
+--             req:set_body(string.rep('s', 1025))  -- > DNS msg over UDP
+--             check_err(req, '413', 'too long POST finishes with 413')
+--     end
+--
+--     local function test_post_unparseable_input()
+--             local req = assert(req_templ:clone())
+--             req.headers:upsert(':method', 'POST')
+--             req:set_body(string.rep('\0', 1024))  -- garbage
+--             check_err(req, '400', 'unparseable DNS message 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')
+--     end
 
        -- test a valid DNS query using GET
        local function test_get_servfail()
                local desc = 'valid GET query which ends with SERVFAIL'
-               local req = connection_init(timeout)
-               req['headers']:upsert(':path', '/doh?dns='  -- servfail.test. A
+               local req = req_templ:clone()
+               req.headers:upsert(':method', 'GET')
+               req.headers:upsert(':path', '/doh?dns='  -- servfail.test. A
                        .. 'FZUBAAABAAAAAAAACHNlcnZmYWlsBHRlc3QAAAEAAQ')
-               local headers, pkt = send_and_check_ok(req, 'GET', desc)
+               local headers, pkt = check_ok(req, desc)
                if not (headers and pkt) then
                        return
                end
@@ -386,10 +215,11 @@ else
 
        local function test_get_noerror()
                local desc = 'valid GET query which ends with NOERROR'
-               local req = connection_init(timeout)
-               req['headers']:upsert(':path', '/doh?dns='  -- noerror.test. A
+               local req = req_templ:clone()
+               req.headers:upsert(':method', 'GET')
+               req.headers:upsert(':path', '/doh?dns='  -- noerror.test. A
                        .. 'vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB')
-               local headers, pkt = send_and_check_ok(req, 'GET', desc)
+               local headers, pkt = check_ok(req, desc)
                if not (headers and pkt) then
                        return
                end
@@ -403,10 +233,11 @@ else
 
        local function test_get_nxdomain()
                local desc = 'valid GET query which ends with NXDOMAIN'
-               local req = connection_init(timeout)
-               req['headers']:upsert(':path', '/doh?dns='  -- nxdomain.test. A
+               local req = req_templ:clone()
+               req.headers:upsert(':method', 'GET')
+               req.headers:upsert(':path', '/doh?dns='  -- nxdomain.test. A
                        .. 'viABAAABAAAAAAAACG54ZG9tYWluBHRlc3QAAAEAAQ')
-               local headers, pkt = send_and_check_ok(req, 'GET', desc)
+               local headers, pkt = check_ok(req, desc)
                if not (headers and pkt) then
                        return
                end
@@ -417,80 +248,72 @@ else
 
        local function test_get_other_params_before_dns()
                local desc = 'GET query with other parameters before dns is valid'
-               local req = connection_init(timeout)
-               req['headers']:upsert(':path',
-                       '/doh?other=something&another=something&dns=vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB')
-               send_and_check_ok(req, 'GET', desc)
+               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)
        end
 
        local function test_get_other_params_after_dns()
                local desc = 'GET query with other parameters after dns is valid'
-               local req = connection_init(timeout)
-               req['headers']:upsert(':path',
-                       '/doh?dns=vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB&other=something&another=something')
-               send_and_check_ok(req, 'GET', desc)
+               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)
        end
 
        local function test_get_other_params()
                local desc = 'GET query with other parameters than dns on both sides is valid'
-               local req = connection_init(timeout)
+               local req = req_templ:clone()
+               req.headers:upsert(':method', 'GET')
                req.headers:upsert(':path',
-                       '/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 = connection_init(timeout)
-               req['headers']:upsert(':path', '/bad?dns=vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB')
-               send_and_check_err(req, 'GET', 400, 'wrong "bad" endpoint finishes with 400')
-
-               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 = 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 = 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 = 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 = 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 = 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 = connection_init(timeout)
-               req['headers']:upsert(':method', 'PUT')
-               send_and_check_err(req, 'PUT', 405, 'unsupported method finishes with 405')
-       end
+               '/doh?other=something&dns=vMEBAAABAAAAAAAAB25vZXJyb3IEdGVzdAAAAQAB&another=something')
+               check_ok(req, desc)
+       end
+
+--     -- test an invalid DNS query using GET
+--             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('\0', 1030)))
+--             check_err(req, '414', 'too long GET finishes with 414')
+--     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 paramter 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')
+--     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')
+--     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')
+--     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')
+--     end
 
        local function test_dstaddr()
                local triggered = false
@@ -503,10 +326,11 @@ 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 = connection_init(timeout)
-               request_set_body(req, basexx.from_base64(  -- dstaddr.test. A
+               local req = req_templ:clone()
+               req.headers:upsert(':method', 'POST')
+               req:set_body(basexx.from_base64(  -- dstaddr.test. A
                        'FnkBAAABAAAAAAAAB2RzdGFkZHIEdGVzdAAAAQAB'))
-               send_and_check_ok(req, 'POST', desc)
+               check_ok(req, desc)
                ok(triggered, 'dstaddr policy was triggered')
        end
 
@@ -519,37 +343,49 @@ else
                view:addr('::/0', policy_refuse)
 
                local desc = 'valid POST query has source address available in request'
-               local req = connection_init(timeout)
-               request_set_body(req, basexx.from_base64(  -- srcaddr.test.knot-resolver.cz TXT
+               local req = req_templ:clone()
+               req.headers:upsert(':method', 'POST')
+               req:set_body(basexx.from_base64(  -- srcaddr.test.knot-resolver.cz TXT
                        'QNQBAAABAAAAAAAAB3NyY2FkZHIEdGVzdA1rbm90LXJlc29sdmVyAmN6AAAQAAE'))
-               local _, pkt = send_and_check_ok(req, 'POST', desc)
+               local _, pkt = check_ok(req, desc)
                same(pkt:rcode(), kres.rcode.REFUSED, desc .. ': view module caught it')
 
                modules.unload('view')
        end
 
+--     not implemented
+--     local function test_post_unsupp_accept()
+--             local req = assert(req_templ:clone())
+--             req.headers:upsert(':method', 'POST')
+--             req.headers:upsert('accept', 'application/dns+json')
+--             req:set_body(string.rep('\0', 12))  -- valid message
+--             check_err(req, '406', 'unsupported Accept type finishes with 406')
+--     end
+
        -- plan tests
+       -- TODO: implement (some) of the error status codes
        local tests = {
+               start_server,
                test_post_servfail,
                test_post_noerror,
                test_post_nxdomain,
                test_huge_answer,
-               test_post_short_input,
-               test_post_unsupp_type,
-               test_get_right_endpoints,
+               --test_post_short_input,
+               --test_post_long_input,
+               --test_post_unparseable_input,
+               --test_post_unsupp_type,
                test_get_servfail,
                test_get_noerror,
                test_get_nxdomain,
                test_get_other_params_before_dns,
                test_get_other_params_after_dns,
                test_get_other_params,
-               test_get_wrong_endpoints,
-               test_get_no_dns_param,
-               test_get_unparseable,
-               test_get_invalid_b64,
-               test_get_invalid_chars,
-               test_get_two_ampersands,
-               test_unsupp_method,
+               --test_get_long_input,
+               --test_get_no_dns_param,
+               --test_get_unparseable,
+               --test_get_invalid_b64,
+               --test_get_invalid_chars,
+               --test_unsupp_method,
                test_dstaddr,
                test_srcaddr
        }