Commit ccf64cb8 authored by Nils Goroll's avatar Nils Goroll

Last-Modified support and ETag integration in test

parent 34044a00
#include "config.h"
#include <string.h>
#include <stdlib.h>
#include <cache/cache.h>
#include <vcl.h>
......@@ -29,3 +32,102 @@ vmod_bodyhash(VRT_CTX, VCL_HEADER hdr)
if (Bodyhash_push(bo->vfc, hdr->what) == NULL)
VRT_fail(ctx, "bodyhash push failed");
}
/* ============================================================================
* Last-Modified for all of ESI
*/
/*
* so far this is not much more as the VRT_priv ID
*/
struct vmod_esiextra_lm {
unsigned magic;
#define VMOD_ESIEXTRA_LM_MAGIC 0x3188a965
const char *vcl_name;
};
VCL_VOID __match_proto__(td_esiextra_lm__init)
vmod_lm__init(VRT_CTX, struct vmod_esiextra_lm **lmobj,
const char *vcl_name)
{
struct vmod_esiextra_lm *o;
assert(sizeof(void *) >= sizeof(VCL_TIME));
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
AN(lmobj);
AZ(*lmobj);
ALLOC_OBJ(o, VMOD_ESIEXTRA_LM_MAGIC);
AN(o);
*lmobj = o;
o->vcl_name = vcl_name;
AN(*lmobj);
}
VCL_VOID __match_proto__(td_esiextra_lm__fini)
vmod_lm__fini(struct vmod_esiextra_lm **lmobj)
{
AN(lmobj);
if (*lmobj == NULL)
return;
FREE_OBJ(*lmobj);
*lmobj = NULL;
}
static VCL_TIME *
lm_time(VRT_CTX, const struct vmod_esiextra_lm *lmobj)
{
struct vmod_priv *priv;
VCL_TIME *t;
priv = VRT_priv_top(ctx, (void *)lmobj);
AN(priv);
t = (VCL_TIME *)(&priv->priv);
if (!isnormal(*t))
*t = 0.0;
return (t);
}
static inline int
lm_bad_task(VRT_CTX)
{
if ((ctx->method & VCL_MET_TASK_C) == 0) {
VRT_fail(ctx, "lm object only usable in client context");
return 1;
}
return 0;
}
VCL_BOOL __match_proto__(td_esiextra_lminspect)
vmod_lm_inspect(VRT_CTX, struct vmod_esiextra_lm *lmobj,
VCL_TIME t)
{
VCL_TIME *lm;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
if (lm_bad_task(ctx))
return (0);
lm = lm_time(ctx, lmobj);
if (t <= *lm)
return (0);
*lm = t;
return (1);
}
VCL_VOID __match_proto__(td_esiextra_lmupdate)
vmod_lm_update(VRT_CTX, struct vmod_esiextra_lm *lmobj,
VCL_TIME t)
{
(void)vmod_lm_inspect(ctx, lmobj, t);
}
VCL_TIME __match_proto__(td_esiextra_lmget)
vmod_lm_get(VRT_CTX, struct vmod_esiextra_lm *lmobj)
{
VCL_TIME *lm;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
if (lm_bad_task(ctx))
return (0);
lm = lm_time(ctx, lmobj);
return (*lm);
}
......@@ -12,6 +12,20 @@ $Function VOID bodyhash(HEADER)
Hash the received body.
$Object lm()
$Method BOOL .inspect(TIME)
Inspect time vs. saved time. If new time is after saved time, update
and return true. Otherwise return false.
$Method VOID .update(TIME)
same as inspect without a return value.
$Method TIME .get()
get the saved time.
SEE ALSO
========
......
......@@ -2,7 +2,9 @@ varnishtest "Test resp_top.* in an ESI context"
server s1 {
rxreq
txresp -body {
txresp \
-hdr "Last-Modified: Thu, 02 Nov 2017 18:38:02 GMT" \
-body {
<html>
Before include
<esi:include src="/a"/>
......@@ -13,37 +15,45 @@ server s1 {
rxreq
expect req.url == "/a1"
txresp -body {
txresp \
-hdr "Last-Modified: Fri, 03 Nov 2017 18:38:03 GMT" \
-body {
Included file
<esi:include src="/c"/>
}
rxreq
expect req.url == "/c2"
txresp
txresp \
-hdr "Last-Modified: Sat, 04 Nov 2017 18:38:04 GMT" \
-body { c}
rxreq
expect req.url == "/b1"
txresp
txresp \
-hdr "Last-Modified: Sun, 05 Nov 2017 18:38:05 GMT" \
-body { b}
rxreq
expect req.url == "/noinclude"
txresp \
-hdr "Last-Modified: Fri, 03 Nov 2017 18:38:04 GMT" \
-body {<html></html>}
} -start
varnish v1 -vcl+backend {} -start
varnish v1 -arg "-p feature=+esi_disable_xml_check" -vcl+backend {} -start
varnish v1 -vcl+backend {
import esiextra;
import std;
backend recursive {
.host = "${v1_addr}";
.port = "${v1_port}";
}
sub recv_test_runtime_access {
if (req.url == "/level0readrecv") {
set req.http.foo = resp_top.http.foo;
return (synth(200));
}
if (req.url == "/level0writerecv") {
set resp_top.http.foo = req.http.foo;
return (synth(200));
}
sub vcl_init {
new esilm = esiextra.lm();
}
sub vcl_recv {
if (req.restarts == 0) {
......@@ -55,13 +65,13 @@ varnish v1 -vcl+backend {
return (hash);
}
call recv_test_runtime_access;
if (req.http.X-Do-Recurse) {
set req.hash_ignore_busy = true;
set req.backend_hint = recursive;
set req.esi = false;
}
if (req.http.X-Recursive) {
set req.hash_ignore_busy = true;
}
if (req.http.TE == "trailers" || req.http.TEFAIL) {
# We vary on X-TE to differenciate pre-rendered ESI
# output with trailers
......@@ -85,14 +95,26 @@ varnish v1 -vcl+backend {
} else {
set resp_top.http.X-ESI = req.url;
}
# updating for level > 1 would just be a waste, only the
# last update wins anyway
if (req.esi_level == 1) {
if (esilm.inspect(std.time(resp.http.Last-Modified,
now - 10s))) {
set resp_top.http.Last-Modified = esilm.get();
}
} else {
esilm.update(std.time(resp.http.Last-Modified, now - 10s));
}
return (deliver);
}
sub vcl_deliver {
if (req.esi_level > 0) {
call deliver_esi;
}
esilm.update(std.time(resp.http.Last-Modified, now - 10s));
if (req.http.TE == "trailers") {
set resp.http.Trailer = "X-ESI";
set resp.http.Trailer = "X-ESI, Last-Modified";
set resp.http.X-ESI = req.url;
}
unset resp.http.Vary;
if (resp.http.hits) {
......@@ -110,12 +132,20 @@ varnish v1 -vcl+backend {
}
}
sub vcl_backend_response {
set beresp.do_esi = true;
set beresp.http.Vary = "X-TE";
if (bereq.http.X-Do-Recurse) {
# The recursively fetched Variant has all the headers
unset bereq.http.X-TE;
unset beresp.http.ETag;
esiextra.bodyhash(beresp.http.ETag);
if (beresp.http.Trailer) {
set beresp.http.Trailer = beresp.http.Trailer +
", ETag";
} else {
set beresp.http.Trailer = "ETag";
}
}
set beresp.do_esi = true;
set beresp.http.Vary = "X-TE";
}
}
......@@ -124,33 +154,24 @@ logexpect l1 -v v1 -g raw {
# expect * * VCL_Error {^resp_top.http.X-ESI not writable unless sending Trailers$}
} -start
client c1 {
txreq -url "/level0readrecv"
rxresp
expect resp.status == 503
expect resp.reason == "VCL failed"
} -run
client c1 {
txreq -url "/level0writerecv"
rxresp
expect resp.status == 503
expect resp.reason == "VCL failed"
} -run
client c1 {
txreq -hdr "TE: trailers"
rxresp
expect resp.status == 200
expect resp.bodylen == 81
expect resp.http.Trailer == "X-ESI"
expect resp.http.X-ESI == "/a1:/c2:/b1"
expect resp.bodylen == 85
expect resp.http.Trailer == "X-ESI, Last-Modified"
expect resp.http.X-ESI == "/:/a1:/c2:/b1"
expect resp.http.Last-Modified == "Sun, 05 Nov 2017 18:38:05 GMT"
expect resp.http.hits == "0"
txreq
rxresp
expect resp.status == 200
expect resp.bodylen == 81
expect resp.bodylen == 85
expect resp.http.Trailer == <undef>
expect resp.http.X-ESI == "/a1:/c2:/b1"
expect resp.http.X-ESI == "/:/a1:/c2:/b1"
expect resp.http.Last-Modified == "Sun, 05 Nov 2017 18:38:05 GMT"
expect resp.http.ETag == {"8fd5e543966b9d8c767b0eab658adcccddfe73a8f5bf3815dead2da979339024"}
expect resp.http.hits == "1,0"
# this fails at esi level 1 - body contains "503 VCL failed"
......@@ -165,11 +186,23 @@ client c1 {
txreq
rxresp
expect resp.status == 200
expect resp.bodylen == 81
expect resp.bodylen == 85
expect resp.http.Trailer == <undef>
expect resp.http.X-ESI == "/a1:/c2:/b1"
expect resp.http.X-ESI == "/:/a1:/c2:/b1"
expect resp.http.Last-Modified == "Sun, 05 Nov 2017 18:38:05 GMT"
expect resp.http.ETag == {"8fd5e543966b9d8c767b0eab658adcccddfe73a8f5bf3815dead2da979339024"}
expect resp.http.hits == "1,1"
} -run
# no esi include
txreq -url "/noinclude"
rxresp
expect resp.status == 200
expect resp.bodylen == 13
expect resp.http.Trailer == <undef>
expect resp.http.X-ESI == "/noinclude"
expect resp.http.Last-Modified == "Fri, 03 Nov 2017 18:38:04 GMT"
expect resp.http.ETag == {"b633a587c652d02386c4f16f8c6f6aab7352d97f16367c3c40576214372dd628"}
expect resp.http.hits == "0,0"
} -run
varnish v1 -expect esi_errors == 0
logexpect l1 -wait
......@@ -3,8 +3,19 @@ varnishtest "Generate an ETag as the hash of the received body"
server s1 {
rxreq
txresp -body "foo"
rxreq
txresp -nolen -hdr "Transfer-encoding: chunked"
chunked {f}
delay .2
chunked {o}
delay .2
chunked {o}
delay .2
chunkedlen 0
} -start
varnish v1 -vcl+backend {
import esiextra;
......@@ -18,3 +29,9 @@ client c1 -repeat 3 {
rxresp
expect resp.http.ETag == {"2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"}
} -run
client c1 -repeat 3 {
txreq -url "/chunked"
rxresp
expect resp.http.ETag == {"2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"}
} -run
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment