#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"
uint8_t *buf;
size_t len;
size_t pos;
+ uint32_t ttl;
uv_write_cb on_write;
uv_write_t *req;
};
*
* 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);
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)
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);
}
/*
/* 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);
};
/** Classify response by type. */
+KR_EXPORT
int kr_response_classify(const knot_pkt_t *pkt);
/** Make next iterative query. */
-- 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
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
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')
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
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
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')
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