]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
doh2: send "cache-control: max-age"
authorLukáš Ježek <lukas.jezek@nic.cz>
Mon, 9 Nov 2020 07:52:37 +0000 (08:52 +0100)
committerLukáš Ježek <lukas.jezek@nic.cz>
Thu, 26 Nov 2020 08:23:04 +0000 (09:23 +0100)
daemon/http.c
lib/cache/util.h
lib/layer/iterate.h
tests/config/doh2.test.lua

index 372a83d2f1a4b2304de79cf1b735ec9a3486639f..b8c150024f1147459d2bb8e54e0b2ab0b044cc23 100644 (file)
@@ -16,6 +16,8 @@
 #include "daemon/http.h"
 #include "daemon/worker.h"
 #include "daemon/session.h"
+#include "lib/layer/iterate.h" /* kr_response_classify */
+#include "lib/cache/util.h"
 
 #include "contrib/base64url.h"
 
@@ -37,6 +39,7 @@ struct http_data {
        uint8_t *buf;
        size_t len;
        size_t pos;
+       uint32_t ttl;
        uv_write_cb on_write;
        uv_write_t *req;
 };
@@ -427,15 +430,26 @@ static ssize_t read_callback(nghttp2_session *h2, int32_t stream_id, uint8_t *bu
  *
  * Data isn't guaranteed to be sent immediately due to underlying HTTP/2 flow control.
  */
-static int http_send_response(nghttp2_session *h2, char *size, size_t size_len,
-                             int32_t stream_id, nghttp2_data_provider *prov)
+static int http_send_response(nghttp2_session *h2, int32_t stream_id,
+                             nghttp2_data_provider *prov)
 {
-       int ret;
        struct http_data *data = (struct http_data*)prov->source.ptr;
+       int ret;
+       const char *directive_max_age = "max-age=";
+       char size[MAX_DECIMAL_LENGTH(data->len)] = { 0 };
+       char max_age[MAX_DECIMAL_LENGTH(data->ttl)+sizeof(directive_max_age)] = { 0 };
+       int size_len;
+       int max_age_len;
+
+       size_len = snprintf(size, MAX_DECIMAL_LENGTH(data->len), "%zu", data->len);
+       max_age_len = snprintf(max_age, MAX_DECIMAL_LENGTH(data->ttl)+sizeof(directive_max_age),
+                               "%s%u", directive_max_age, data->ttl);
+
        nghttp2_nv hdrs[] = {
                MAKE_STATIC_NV(":status", "200"),
                MAKE_STATIC_NV("content-type", "application/dns-message"),
-               MAKE_NV("content-length", 14, size, size_len)
+               MAKE_NV("content-length", 14, size, size_len),
+               MAKE_NV("cache-control", 13, max_age, max_age_len),
        };
 
        ret = nghttp2_submit_response(h2, stream_id, hdrs, sizeof(hdrs)/sizeof(*hdrs), prov);
@@ -465,12 +479,9 @@ static int http_send_response(nghttp2_session *h2, char *size, size_t size_len,
 static int http_write_pkt(nghttp2_session *h2, knot_pkt_t *pkt, int32_t stream_id,
                          uv_write_t *req, uv_write_cb on_write)
 {
-       char size[MAX_DECIMAL_LENGTH(pkt->size)] = { 0 };
-       int size_len;
        struct http_data *data;
        nghttp2_data_provider prov;
-
-       size_len = snprintf(size, MAX_DECIMAL_LENGTH(pkt->size), "%zu", pkt->size);
+       const bool is_negative = kr_response_classify(pkt) & (PKT_NODATA|PKT_NXDOMAIN);
 
        data = malloc(sizeof(struct http_data));
        if (!data)
@@ -481,11 +492,12 @@ static int http_write_pkt(nghttp2_session *h2, knot_pkt_t *pkt, int32_t stream_i
        data->pos = 0;
        data->on_write = on_write;
        data->req = req;
+       data->ttl = packet_ttl(pkt, is_negative);
 
        prov.source.ptr = data;
        prov.read_callback = read_callback;
 
-       return http_send_response(h2, size, size_len, stream_id, &prov);
+       return http_send_response(h2, stream_id, &prov);
 }
 
 /*
index c3a0c44f32f0281896952076699e7f75e72a92da..0a2f329c8004b23b461f7337f948374538267ec6 100644 (file)
@@ -1,4 +1,4 @@
 /* SPDX-License-Identifier: GPL-3.0-or-later */
-#include <knot/lib/pkt.h>
+#include <libknot/packet/pkt.h>
 
 uint32_t packet_ttl(const knot_pkt_t *pkt, bool is_negative);
index 3b24da0ec7c0b1cc132b74557892a5aa44c6ff25..e5ebe3838a11e33b941f499901fd3c0f772d2ade 100644 (file)
@@ -17,6 +17,7 @@ enum {
 };
 
 /** Classify response by type. */
+KR_EXPORT
 int kr_response_classify(const knot_pkt_t *pkt);
 
 /** Make next iterative query. */
index 0d6a3eb61b1705bc149dcd796253e73849a5e21f..a97fc0692cae8156326061662f4072ee3b54c1b4 100644 (file)
@@ -34,6 +34,7 @@ local function gen_varying_ttls(_, req)
        -- shorter TTL than all other RRs
        answer:begin(kres.section.AUTHORITY)
        answer:put('\4test\0', 300, answer:qclass(), kres.type.SOA,
+               -- ns.test. nobody.invalid. 1 3600 1200 604800 10800
                '\2ns\4test\0\6nobody\7invalid\0\0\0\0\1\0\0\14\16\0\0\4\176\0\9\58\128\0\0\42\48')
        return kres.DONE
 end
@@ -115,7 +116,7 @@ else
                        return
                end
                -- uncacheable
-               -- same(headers:get('cache-control'), 'max-age=0', desc .. ': TTL 0')  TODO: implement
+               same(headers:get('cache-control'), 'max-age=0', desc .. ': TTL 0')
                same(pkt:rcode(), kres.rcode.SERVFAIL, desc .. ': rcode matches')
        end
 
@@ -130,7 +131,7 @@ else
                        return
                end
                -- HTTP TTL is minimum from all RRs in the answer
-               -- same(headers:get('cache-control'), 'max-age=300', desc .. ': TTL 900')  TODO: implement
+               same(headers:get('cache-control'), 'max-age=300', desc .. ': TTL 900')
                same(pkt:rcode(), kres.rcode.NOERROR, desc .. ': rcode matches')
                same(pkt:ancount(), 3, desc .. ': ANSWER is present')
                same(pkt:nscount(), 1, desc .. ': AUTHORITY is present')
@@ -147,7 +148,7 @@ else
                if not (headers and pkt) then
                        return
                end
-               -- same(headers:get('cache-control'), 'max-age=10800', desc .. ': TTL 10800')  TODO: implement
+               same(headers:get('cache-control'), 'max-age=10800', desc .. ': TTL 10800')
                same(pkt:rcode(), kres.rcode.NXDOMAIN, desc .. ': rcode matches')
                same(pkt:nscount(), 1, desc .. ': AUTHORITY is present')
        end
@@ -208,7 +209,7 @@ else
                        return
                end
                -- uncacheable
-               -- same(headers:get('cache-control'), 'max-age=0', desc .. ': TTL 0')  TODO: implement
+               same(headers:get('cache-control'), 'max-age=0', desc .. ': TTL 0')
                same(pkt:rcode(), kres.rcode.SERVFAIL, desc .. ': rcode matches')
        end
 
@@ -223,7 +224,7 @@ else
                        return
                end
                -- HTTP TTL is minimum from all RRs in the answer
-               -- same(headers:get('cache-control'), 'max-age=300', desc .. ': TTL 900')  TODO: implement
+               same(headers:get('cache-control'), 'max-age=300', desc .. ': TTL 900')
                same(pkt:rcode(), kres.rcode.NOERROR, desc .. ': rcode matches')
                same(pkt:ancount(), 3, desc .. ': ANSWER is present')
                same(pkt:nscount(), 1, desc .. ': AUTHORITY is present')
@@ -240,7 +241,7 @@ else
                if not (headers and pkt) then
                        return
                end
-               -- same(headers:get('cache-control'), 'max-age=10800', desc .. ': TTL 10800')  TODO: implement
+               same(headers:get('cache-control'), 'max-age=10800', desc .. ': TTL 10800')
                same(pkt:rcode(), kres.rcode.NXDOMAIN, desc .. ': rcode matches')
                same(pkt:nscount(), 1, desc .. ': AUTHORITY is present')
        end