[master] 165f191 So one of those strange cornercases in HTTP/1
Poul-Henning Kamp
phk at FreeBSD.org
Fri Oct 30 15:26:19 CET 2015
commit 165f191d68c2637629b6dd4303293c328745acae
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date: Fri Oct 30 14:22:11 2015 +0000
So one of those strange cornercases in HTTP/1
If we send the backend a HTTP/1.0 request, and it doesn't have a
Content-Length, it cannot use Chunked and must fall back to EOF.
However, the protocol field in the response tells us what version
backend *could* have used, not what it *does* use.
So we can get a response with HTTP/1.1 and EOF, following HTTP/1.0
semantics - because we asked for it.
Most sensible backends avoid this, either by buffering and creation
of a C-L or, smartly, returning "HTTP/1.0", even though that
is strictly speaking against the apocrphal texts.
Anyway, now we cope...
Fixes: #1810
diff --git a/bin/varnishd/cache/cache.h b/bin/varnishd/cache/cache.h
index 93e5de4..e7700d0 100644
--- a/bin/varnishd/cache/cache.h
+++ b/bin/varnishd/cache/cache.h
@@ -805,7 +805,8 @@ enum sess_close http_DoConnection(struct http *hp);
htc_complete_f HTTP1_Complete;
uint16_t HTTP1_DissectRequest(struct http_conn *, struct http *);
-uint16_t HTTP1_DissectResponse(struct http_conn *, struct http *);
+uint16_t HTTP1_DissectResponse(struct http_conn *, struct http *resp,
+ const struct http *req);
unsigned HTTP1_Write(const struct worker *w, const struct http *hp, const int*);
#define HTTPH(a, b, c) extern char b[];
diff --git a/bin/varnishd/http1/cache_http1_fetch.c b/bin/varnishd/http1/cache_http1_fetch.c
index 1b6ceb4..a69fb92 100644
--- a/bin/varnishd/http1/cache_http1_fetch.c
+++ b/bin/varnishd/http1/cache_http1_fetch.c
@@ -193,7 +193,7 @@ V1F_FetchRespHdr(struct busyobj *bo)
hp = bo->beresp;
- i = HTTP1_DissectResponse(htc, hp);
+ i = HTTP1_DissectResponse(htc, hp, bo->bereq);
bo->acct.beresp_hdrbytes += htc->rxbuf_e - htc->rxbuf_b;
if (i) {
VSLb(bo->vsl, SLT_FetchError, "http format error");
diff --git a/bin/varnishd/http1/cache_http1_proto.c b/bin/varnishd/http1/cache_http1_proto.c
index 8d08278..deb191d 100644
--- a/bin/varnishd/http1/cache_http1_proto.c
+++ b/bin/varnishd/http1/cache_http1_proto.c
@@ -321,15 +321,15 @@ http1_body_status(const struct http *hp, struct http_conn *htc)
/*--------------------------------------------------------------------*/
-static void
-http1_proto_ver(struct http *hp)
+static int8_t
+http1_proto_ver(const struct http *hp)
{
if (!strcasecmp(hp->hd[HTTP_HDR_PROTO].b, "HTTP/1.0"))
- hp->protover = 10;
+ return (10);
else if (!strcasecmp(hp->hd[HTTP_HDR_PROTO].b, "HTTP/1.1"))
- hp->protover = 11;
+ return (11);
else
- hp->protover = 0;
+ return (0);
}
/*--------------------------------------------------------------------*/
@@ -347,7 +347,7 @@ HTTP1_DissectRequest(struct http_conn *htc, struct http *hp)
retval = http1_splitline(hp, htc, HTTP1_Req);
if (retval != 0)
return (retval);
- http1_proto_ver(hp);
+ hp->protover = http1_proto_ver(hp);
if (hp->protover == 0)
return (400);
@@ -391,22 +391,28 @@ HTTP1_DissectRequest(struct http_conn *htc, struct http *hp)
/*--------------------------------------------------------------------*/
uint16_t
-HTTP1_DissectResponse(struct http_conn *htc, struct http *hp)
+HTTP1_DissectResponse(struct http_conn *htc, struct http *hp,
+ const struct http *req)
{
uint16_t retval = 0;
const char *p;
+ int8_t rv;
CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
+ CHECK_OBJ_NOTNULL(req, HTTP_MAGIC);
if (http1_splitline(hp, htc, HTTP1_Resp))
retval = 503;
if (retval == 0) {
- http1_proto_ver(hp);
+ hp->protover = http1_proto_ver(hp);
if (hp->protover == 0)
retval = 503;
+ rv = http1_proto_ver(req);
+ if (hp->protover > rv)
+ hp->protover = rv;
}
if (retval == 0 && Tlen(hp->hd[HTTP_HDR_STATUS]) != 3)
diff --git a/bin/varnishtest/tests/r01810.vtc b/bin/varnishtest/tests/r01810.vtc
new file mode 100644
index 0000000..77e84db
--- /dev/null
+++ b/bin/varnishtest/tests/r01810.vtc
@@ -0,0 +1,21 @@
+varnishtest "POST HTTP/1.0 response"
+
+server s1 {
+ non-fatal
+ rxreq
+ txresp -proto HTTP/1.1 -nolen -hdr "Connection: close"
+ send "Hello World\n"
+ delay .4
+} -start
+
+varnish v1 -vcl+backend {
+ sub vcl_backend_fetch {
+ set bereq.proto = "HTTP/1.0";
+ }
+} -start
+
+client c1 {
+ txreq -req POST -hdr "Content-Length: 0"
+ rxresp
+ expect resp.bodylen == 12
+} -run
More information about the varnish-commit
mailing list