From: Lukáš Ježek Date: Mon, 9 Nov 2020 07:52:37 +0000 (+0100) Subject: doh2: send "cache-control: max-age" X-Git-Tag: v5.2.1~7^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=18a057b37e19c926b69d7856c3f81d20f0fa359c;p=thirdparty%2Fknot-resolver.git doh2: send "cache-control: max-age" --- diff --git a/daemon/http.c b/daemon/http.c index 372a83d2f..b8c150024 100644 --- a/daemon/http.c +++ b/daemon/http.c @@ -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); } /* diff --git a/lib/cache/util.h b/lib/cache/util.h index c3a0c44f3..0a2f329c8 100644 --- a/lib/cache/util.h +++ b/lib/cache/util.h @@ -1,4 +1,4 @@ /* SPDX-License-Identifier: GPL-3.0-or-later */ -#include +#include uint32_t packet_ttl(const knot_pkt_t *pkt, bool is_negative); diff --git a/lib/layer/iterate.h b/lib/layer/iterate.h index 3b24da0ec..e5ebe3838 100644 --- a/lib/layer/iterate.h +++ b/lib/layer/iterate.h @@ -17,6 +17,7 @@ enum { }; /** Classify response by type. */ +KR_EXPORT int kr_response_classify(const knot_pkt_t *pkt); /** Make next iterative query. */ diff --git a/tests/config/doh2.test.lua b/tests/config/doh2.test.lua index 0d6a3eb61..a97fc0692 100644 --- a/tests/config/doh2.test.lua +++ b/tests/config/doh2.test.lua @@ -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