Commit 2b2a30c6 authored by Dridi Boukelmoune's avatar Dridi Boukelmoune

vcc: Add infrastructure for protected header fields

parent 00945a40
......@@ -2,22 +2,19 @@ varnishtest "Wrong calculation of last storage segment length"
server s1 {
rxreq
send "HTTP/1.1 200 OK\r\n"
send "Transfer-encoding: chunked\r\n"
send "\r\n"
txresp -hdr "Transfer-encoding: chunked"
# This is chunksize (128k) + 2 to force to chunks to be allocated
chunkedlen 131074
chunkedlen 0
} -start
varnish v1 -vcl+backend {
sub vcl_deliver {
unset resp.http.content-length;
}
} -start
varnish v1 -vcl+backend "" -start
client c1 {
txreq -proto HTTP/1.0
rxresp
# Chunked encoding streaming HTTP/1.0 client turns
# into EOF body delivery.
expect resp.http.connection == close
expect resp.bodylen == 131074
} -run
varnishtest "Regression test for duplicate content-length in pass"
server s1 {
rxreq
txresp \
-hdr "Date: Mon, 25 Oct 2010 06:34:06 GMT" \
-hdr "Content-length: 000010" \
-nolen -bodylen 10
} -start
varnish v1 -vcl+backend {
sub vcl_recv { return (pass); }
sub vcl_backend_response {
set beresp.do_stream = false;
unset beresp.http.content-length;
}
} -start
client c1 {
txreq
rxresp
expect resp.http.content-length == "10"
} -run
......@@ -14,13 +14,13 @@ varnish v1 -vcl+backend {
sub vcl_recv { return(pass);}
sub vcl_deliver {
set resp.http.CL = resp.http.content-length;
unset resp.http.content-length;
}
} -start
client c1 {
txreq
rxresp -no_obj
rxresphdrs
expect resp.status == 304
expect resp.http.cl == 100
expect_close
} -run
......@@ -20,6 +20,16 @@ varnish v1 -errvcl "Variable is read only" {
sub vcl_backend_response { set beresp.proto = "HTTP/1.2"; }
}
varnish v1 -errvcl "Variable is read only" {
backend proforma None;
sub vcl_recv { set req.http.content-length = "42"; }
}
varnish v1 -errvcl "Variable cannot be unset" {
backend proforma None;
sub vcl_recv { unset req.http.content-length; }
}
server s1 {
rxreq
txresp -hdr "Connection: close" -body "012345\n"
......
......@@ -35,6 +35,18 @@ and ``vcl_fini {}``.
.. include:: vcl_var.rst
.. _protected_headers:
Protected header fields
-----------------------
The ``content-length`` and ``transfer-encoding`` headers are read-only. They
must be preserved to ensure HTTP/1 framing remains consistent and maintain a
proper request and response synchronization with both clients and backends.
VMODs can still update these headers, when there is a reason to change the
framing, such as a transformation of a request or response body.
HTTP response status
--------------------
......
......@@ -353,6 +353,27 @@ req.http.*
headers present in IANA registries need to be quoted, so the
quoted syntax is discouraged but available for interoperability.
Some headers that cannot be tampered with for proper HTTP fetch
or delivery are read-only.
req.http.content-length
Type: HEADER
Readable from: client
The content-length header field is protected, see protected_headers_.
req.http.transfer-encoding
Type: HEADER
Readable from: client
The transfer-encoding header field is protected, see protected_headers_.
.. _req.is_hitmiss:
......@@ -715,6 +736,24 @@ bereq.http.*
See ``req.http.*`` for general notes.
bereq.http.content-length
Type: HEADER
Readable from: client
The content-length header field is protected, see protected_headers_.
bereq.http.transfer-encoding
Type: HEADER
Readable from: client
The transfer-encoding header field is protected, see protected_headers_.
.. _bereq.is_bgfetch:
bereq.is_bgfetch
......@@ -1119,6 +1158,24 @@ beresp.http.*
See ``req.http.*`` for general notes.
beresp.http.content-length
Type: HEADER
Readable from: client
The content-length header field is protected, see protected_headers_.
beresp.http.transfer-encoding
Type: HEADER
Readable from: client
The transfer-encoding header field is protected, see protected_headers_.
.. _beresp.keep:
beresp.keep
......@@ -1551,6 +1608,24 @@ resp.http.*
See ``req.http.*`` for general notes.
resp.http.content-length
Type: HEADER
Readable from: client
The content-length header field is protected, see protected_headers_.
resp.http.transfer-encoding
Type: HEADER
Readable from: client
The transfer-encoding header field is protected, see protected_headers_.
.. _resp.is_streaming:
resp.is_streaming
......
......@@ -174,20 +174,23 @@ class vardef(object):
fo.write(" SYM_VAR, %d, %d);\n" % (self.vlo, self.vhi))
fo.write("\tAN(sym);\n")
fo.write("\tsym->type = %s;\n" % self.typ)
fo.write("\tsym->eval = vcc_Eval_Var;\n")
if self.typ == "HEADER" and not var_is_wildcard(self.sym):
fo.write("\tsym->eval = vcc_Eval_ProtectedHeader;\n")
else:
fo.write("\tsym->eval = vcc_Eval_Var;\n")
if self.typ == "HEADER":
if var_is_wildcard(self.sym):
fo.write('\tsym->rname = "HDR_')
fo.write(self.nam.split(".")[0].upper())
fo.write('";\n')
elif self.rd:
elif self.rd and self.typ != "HEADER":
fo.write('\tsym->rname = "VRT_r_%s(ctx)";\n' % cnam)
varproto("VCL_" + self.typ + " VRT_r_%s(VRT_CTX)" % cnam)
fo.write("\tsym->r_methods =\n")
restrict(fo, self.rd)
fo.write(";\n")
if self.typ == "HEADER":
if var_is_wildcard(self.sym):
fo.write('\tsym->lname = "HDR_')
fo.write(self.nam.split(".")[0].upper())
fo.write('";\n')
......
......@@ -355,6 +355,7 @@ sym_act_f vcc_Act_Call;
sym_act_f vcc_Act_Obj;
void vcc_Expr_Init(struct vcc *tl);
sym_expr_t vcc_Eval_Var;
sym_expr_t vcc_Eval_ProtectedHeader;
sym_expr_t vcc_Eval_Handle;
sym_expr_t vcc_Eval_Sub;
sym_expr_t vcc_Eval_SymFunc;
......@@ -455,6 +456,7 @@ char *vcc_Dup_be(const char *b, const char *e);
int vcc_Has_vcl_prefix(const char *b);
/* vcc_var.c */
void vcc_Header_Fh(struct vcc *, struct symbol *);
sym_wildcard_t vcc_Var_Wildcard;
/* vcc_vmod.c */
......
......@@ -379,6 +379,19 @@ vcc_Eval_Var(struct vcc *tl, struct expr **e, struct token *t,
(*e)->fmt = STRINGS;
}
void v_matchproto_(sym_expr_t)
vcc_Eval_ProtectedHeader(struct vcc *tl, struct expr **e, struct token *t,
struct symbol *sym, vcc_type_t type)
{
AN(sym);
AZ(sym->lorev);
vcc_Header_Fh(tl, sym);
sym->eval = vcc_Eval_Var;
vcc_Eval_Var(tl, e, t, sym, type);
}
/*--------------------------------------------------------------------
*/
......
......@@ -438,6 +438,7 @@ VCC_MkSym(struct vcc *tl, const char *b, vcc_ns_t ns, vcc_kind_t kind,
{
struct symtab *st;
struct symbol *sym;
const struct symbol *parent;
AN(tl);
AN(b);
......@@ -450,6 +451,14 @@ VCC_MkSym(struct vcc *tl, const char *b, vcc_ns_t ns, vcc_kind_t kind,
st = vcc_symtab_str(tl->syms[ns->id], b, NULL, ID);
AN(st);
sym = vcc_sym_in_tab(tl, st, kind, vlo, vhi);
if (sym != NULL) {
assert(sym->kind == SYM_VAR);
parent = sym->eval_priv;
AN(parent);
AN(parent->wildcard);
assert(sym->type == parent->type);
return (sym);
}
AZ(sym);
sym = vcc_new_symbol(tl, st, kind, vlo, vhi);
AN(sym);
......
......@@ -40,7 +40,7 @@
/*--------------------------------------------------------------------*/
static void
void
vcc_Header_Fh(struct vcc *tl, struct symbol *sym)
{
const struct symbol *parent;
......@@ -123,5 +123,6 @@ vcc_Var_Wildcard(struct vcc *tl, struct symbol *parent, struct symbol *sym)
}
VSB_destroy(&vsb);
vcc_Header_Fh(tl, sym);
if (sym->lorev > 0)
vcc_Header_Fh(tl, sym);
}
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