Commit 2bcd564d authored by Per Buer's avatar Per Buer
parents 0d710a0e aa103397
...@@ -312,6 +312,9 @@ struct worker { ...@@ -312,6 +312,9 @@ struct worker {
unsigned do_close; unsigned do_close;
char *h_content_length; char *h_content_length;
/* Stream state */
ssize_t stream_next;
/* ESI stuff */ /* ESI stuff */
struct vep_state *vep; struct vep_state *vep;
int gzip_resp; int gzip_resp;
...@@ -858,6 +861,7 @@ void RES_BuildHttp(struct sess *sp); ...@@ -858,6 +861,7 @@ void RES_BuildHttp(struct sess *sp);
void RES_WriteObj(struct sess *sp); void RES_WriteObj(struct sess *sp);
void RES_StreamStart(struct sess *sp); void RES_StreamStart(struct sess *sp);
void RES_StreamEnd(struct sess *sp); void RES_StreamEnd(struct sess *sp);
void RES_StreamPoll(const struct sess *sp);
/* cache_vary.c */ /* cache_vary.c */
struct vsb *VRY_Create(const struct sess *sp, const struct http *hp); struct vsb *VRY_Create(const struct sess *sp, const struct http *hp);
......
...@@ -102,6 +102,8 @@ vfp_nop_bytes(struct sess *sp, struct http_conn *htc, ssize_t bytes) ...@@ -102,6 +102,8 @@ vfp_nop_bytes(struct sess *sp, struct http_conn *htc, ssize_t bytes)
st->len += w; st->len += w;
sp->obj->len += w; sp->obj->len += w;
bytes -= w; bytes -= w;
if (sp->wrk->do_stream)
RES_StreamPoll(sp);
} }
return (1); return (1);
} }
......
...@@ -477,6 +477,8 @@ vfp_gunzip_bytes(struct sess *sp, struct http_conn *htc, ssize_t bytes) ...@@ -477,6 +477,8 @@ vfp_gunzip_bytes(struct sess *sp, struct http_conn *htc, ssize_t bytes)
i = VGZ_Gunzip(vg, &dp, &dl); i = VGZ_Gunzip(vg, &dp, &dl);
assert(i == VGZ_OK || i == VGZ_END); assert(i == VGZ_OK || i == VGZ_END);
sp->obj->len += dl; sp->obj->len += dl;
if (sp->wrk->do_stream)
RES_StreamPoll(sp);
} }
if (i == Z_OK || i == Z_STREAM_END) if (i == Z_OK || i == Z_STREAM_END)
return (1); return (1);
...@@ -547,6 +549,8 @@ vfp_gzip_bytes(struct sess *sp, struct http_conn *htc, ssize_t bytes) ...@@ -547,6 +549,8 @@ vfp_gzip_bytes(struct sess *sp, struct http_conn *htc, ssize_t bytes)
i = VGZ_Gzip(vg, &dp, &dl, VGZ_NORMAL); i = VGZ_Gzip(vg, &dp, &dl, VGZ_NORMAL);
assert(i == Z_OK); assert(i == Z_OK);
sp->obj->len += dl; sp->obj->len += dl;
if (sp->wrk->do_stream)
RES_StreamPoll(sp);
} }
return (1); return (1);
} }
...@@ -623,6 +627,8 @@ vfp_testgzip_bytes(struct sess *sp, struct http_conn *htc, ssize_t bytes) ...@@ -623,6 +627,8 @@ vfp_testgzip_bytes(struct sess *sp, struct http_conn *htc, ssize_t bytes)
VGZ_Ibuf(vg, st->ptr + st->len, w); VGZ_Ibuf(vg, st->ptr + st->len, w);
st->len += w; st->len += w;
sp->obj->len += w; sp->obj->len += w;
if (sp->wrk->do_stream)
RES_StreamPoll(sp);
while (!VGZ_IbufEmpty(vg)) { while (!VGZ_IbufEmpty(vg)) {
VGZ_Obuf(vg, ibuf, sizeof ibuf); VGZ_Obuf(vg, ibuf, sizeof ibuf);
...@@ -634,9 +640,9 @@ vfp_testgzip_bytes(struct sess *sp, struct http_conn *htc, ssize_t bytes) ...@@ -634,9 +640,9 @@ vfp_testgzip_bytes(struct sess *sp, struct http_conn *htc, ssize_t bytes)
} }
} }
} }
if (i == Z_STREAM_END) if (i == VGZ_OK || i == VGZ_END)
return (1); return (1);
WSP(sp, SLT_FetchError, "Incomplete Gzip data (not STREAM_END)"); WSP(sp, SLT_FetchError, "Gunzip trouble (%d)", i);
return (-1); return (-1);
} }
......
...@@ -270,7 +270,7 @@ res_WriteGunzipObj(struct sess *sp) ...@@ -270,7 +270,7 @@ res_WriteGunzipObj(struct sess *sp)
} }
if (obufl) { if (obufl) {
(void)WRW_Write(sp->wrk, obuf, obufl); (void)WRW_Write(sp->wrk, obuf, obufl);
WRW_Flush(sp->wrk); (void)WRW_Flush(sp->wrk);
} }
VGZ_Destroy(&vg); VGZ_Destroy(&vg);
assert(u == sp->obj->len); assert(u == sp->obj->len);
...@@ -413,19 +413,42 @@ RES_StreamStart(struct sess *sp) ...@@ -413,19 +413,42 @@ RES_StreamStart(struct sess *sp)
if (sp->wrk->res_mode & RES_CHUNKED) if (sp->wrk->res_mode & RES_CHUNKED)
WRW_Chunked(sp->wrk); WRW_Chunked(sp->wrk);
sp->wrk->stream_next = 0;
}
void
RES_StreamPoll(const struct sess *sp)
{
struct storage *st;
ssize_t l, l2;
void *ptr;
if (sp->obj->len == sp->wrk->stream_next)
return;
assert(sp->obj->len > sp->wrk->stream_next);
l = 0;
VTAILQ_FOREACH(st, &sp->obj->store, list) {
if (st->len + l <= sp->wrk->stream_next) {
l += st->len;
continue;
}
l2 = st->len + l - sp->wrk->stream_next;
ptr = st->ptr + (sp->wrk->stream_next - l);
(void)WRW_Write(sp->wrk, ptr, l2);
l += st->len;
sp->wrk->stream_next += l2;
}
(void)WRW_Flush(sp->wrk);
} }
void void
RES_StreamEnd(struct sess *sp) RES_StreamEnd(struct sess *sp)
{ {
ssize_t low, high;
if (sp->wrk->res_mode & RES_GUNZIP) { if (sp->wrk->res_mode & RES_GUNZIP) {
INCOMPL();
res_WriteGunzipObj(sp); res_WriteGunzipObj(sp);
} else {
low = 0;
high = sp->obj->len - 1;
res_WriteDirObj(sp, low, high);
} }
if (sp->wrk->res_mode & RES_CHUNKED && if (sp->wrk->res_mode & RES_CHUNKED &&
!(sp->wrk->res_mode & RES_ESI_CHILD)) !(sp->wrk->res_mode & RES_ESI_CHILD))
......
...@@ -170,7 +170,7 @@ RFC2616_Ttl(const struct sess *sp) ...@@ -170,7 +170,7 @@ RFC2616_Ttl(const struct sess *sp)
} }
/* calculated TTL, Our time, Date, Expires, max-age, age */ /* calculated TTL, Our time, Date, Expires, max-age, age */
WSP(sp, SLT_TTL, "%u RFC %g %g %g %g %u %u", sp->xid, WSP(sp, SLT_TTL, "%u RFC %g %.0f %.0f %.0f %u %u", sp->xid,
ttl, sp->wrk->entered, h_date, h_expires, max_age, age); ttl, sp->wrk->entered, h_date, h_expires, max_age, age);
return (ttl); return (ttl);
......
...@@ -219,6 +219,7 @@ clean_logline(struct logline *lp) ...@@ -219,6 +219,7 @@ clean_logline(struct logline *lp)
freez(lp->df_m); freez(lp->df_m);
freez(lp->df_s); freez(lp->df_s);
freez(lp->df_u); freez(lp->df_u);
freez(lp->df_ttfb);
#undef freez #undef freez
memset(lp, 0, sizeof *lp); memset(lp, 0, sizeof *lp);
} }
...@@ -415,17 +416,23 @@ collect_client(struct logline *lp, enum vsl_tag tag, unsigned spec, ...@@ -415,17 +416,23 @@ collect_client(struct logline *lp, enum vsl_tag tag, unsigned spec,
case SLT_RxHeader: case SLT_RxHeader:
if (!lp->active) if (!lp->active)
break; break;
if (isprefix(ptr, "user-agent:", end, &next)) if (isprefix(ptr, "user-agent:", end, &next)) {
free(lp->df_User_agent);
lp->df_User_agent = trimline(next, end); lp->df_User_agent = trimline(next, end);
else if (isprefix(ptr, "referer:", end, &next)) } else if (isprefix(ptr, "referer:", end, &next)) {
free(lp->df_Referer);
lp->df_Referer = trimline(next, end); lp->df_Referer = trimline(next, end);
else if (isprefix(ptr, "authorization:", end, &next) && } else if (isprefix(ptr, "authorization:", end, &next) &&
isprefix(next, "basic", end, &next)) isprefix(next, "basic", end, &next)) {
free(lp->df_u);
lp->df_u = trimline(next, end); lp->df_u = trimline(next, end);
else if (isprefix(ptr, "x-forwarded-for:", end, &next)) } else if (isprefix(ptr, "x-forwarded-for:", end, &next)) {
free(lp->df_X_Forwarded_For);
lp->df_X_Forwarded_For = trimline(next, end); lp->df_X_Forwarded_For = trimline(next, end);
else if (isprefix(ptr, "host:", end, &next)) } else if (isprefix(ptr, "host:", end, &next)) {
free(lp->df_Host);
lp->df_Host = trimline(next, end); lp->df_Host = trimline(next, end);
}
break; break;
case SLT_VCL_call: case SLT_VCL_call:
...@@ -471,7 +478,7 @@ collect_client(struct logline *lp, enum vsl_tag tag, unsigned spec, ...@@ -471,7 +478,7 @@ collect_client(struct logline *lp, enum vsl_tag tag, unsigned spec,
char ttfb[64]; char ttfb[64];
if (!lp->active) if (!lp->active)
break; break;
if (sscanf(ptr, "%*u %*u.%*u %ld.%*u %*u.%*u %s", &l, ttfb) != 2) { if (lp->df_ttfb != NULL || sscanf(ptr, "%*u %*u.%*u %ld.%*u %*u.%*u %s", &l, ttfb) != 2) {
clean_logline(lp); clean_logline(lp);
break; break;
} }
......
...@@ -15,10 +15,14 @@ Naming scheme ...@@ -15,10 +15,14 @@ Naming scheme
[id]%05d.vtc [id]%05d.vtc
id ~ [a] --> varnishtester(1) tests id ~ [a] --> varnishtest(1) tests
id ~ [b] --> Basic functionality tests id ~ [b] --> Basic functionality tests
id ~ [c] --> Complex functionality tests id ~ [c] --> Complex functionality tests
id ~ [e] --> ESI tests id ~ [e] --> ESI tests
id ~ [g] --> GZIP tests
id ~ [m] --> VMOD tests
id ~ [p] --> Persistent tests
id ~ [r] --> Regression tests, same number as ticket id ~ [r] --> Regression tests, same number as ticket
id ~ [s] --> Slow tests, expiry, grace etc. id ~ [s] --> Slow tests, expiry, grace etc.
id ~ [t] --> sTreaming tests
id ~ [v] --> VCL tests: execute VRT functions id ~ [v] --> VCL tests: execute VRT functions
# $Id$
test "Ticket #873"
server s1 {
rxreq
txresp -nolen -hdr "Transfer-encoding: chunked"
chunked "<1>------------------------<1>\n"
sema r1 sync 2
chunked "<2>------------------------<2>\n"
sema r2 sync 2
chunked "<3>------------------------<3>\n"
sema r1 sync 2
chunked "<4>------------------------<4>\n"
sema r2 sync 2
chunkedlen 0
} -start
varnish v1 -vcl+backend {
sub vcl_fetch {
set beresp.do_stream = true;
}
} -start
varnish v1 -cliok "param.set diag_bitmap 1"
client c1 {
txreq -hdr "foo: /foo"
rxresp -no_obj
rxchunk
expect resp.chunklen == 31
sema r1 sync 2
rxchunk
expect resp.chunklen == 31
sema r2 sync 2
rxchunk
expect resp.chunklen == 31
sema r1 sync 2
rxchunk
expect resp.chunklen == 31
sema r2 sync 2
rxchunk
expect resp.chunklen == 0
expect resp.bodylen == 124
} -run
...@@ -69,6 +69,7 @@ struct http { ...@@ -69,6 +69,7 @@ struct http {
char *body; char *body;
unsigned bodyl; unsigned bodyl;
char bodylen[20]; char bodylen[20];
char chunklen[20];
char *req[MAX_HDR]; char *req[MAX_HDR];
char *resp[MAX_HDR]; char *resp[MAX_HDR];
...@@ -191,6 +192,8 @@ cmd_var_resolve(struct http *hp, char *spec) ...@@ -191,6 +192,8 @@ cmd_var_resolve(struct http *hp, char *spec)
return(hp->resp[1]); return(hp->resp[1]);
if (!strcmp(spec, "resp.msg")) if (!strcmp(spec, "resp.msg"))
return(hp->resp[2]); return(hp->resp[2]);
if (!strcmp(spec, "resp.chunklen"))
return(hp->chunklen);
if (!strcmp(spec, "resp.bodylen")) if (!strcmp(spec, "resp.bodylen"))
return(hp->bodylen); return(hp->bodylen);
if (!memcmp(spec, "req.http.", 9)) { if (!memcmp(spec, "req.http.", 9)) {
...@@ -371,6 +374,47 @@ http_rxchar(struct http *hp, int n) ...@@ -371,6 +374,47 @@ http_rxchar(struct http *hp, int n)
assert(i > 0); assert(i > 0);
} }
static int
http_rxchunk(struct http *hp)
{
char *q;
int l, i;
l = hp->prxbuf;
do
http_rxchar(hp, 1);
while (hp->rxbuf[hp->prxbuf - 1] != '\n');
vtc_dump(hp->vl, 4, "len", hp->rxbuf + l, -1);
i = strtoul(hp->rxbuf + l, &q, 16);
bprintf(hp->chunklen, "%d", i);
if ((q == hp->rxbuf + l) ||
(*q != '\0' && !vct_islws(*q))) {
vtc_log(hp->vl, 0, "chunked fail %02x @ %d",
*q, q - (hp->rxbuf + l));
}
assert(q != hp->rxbuf + l);
assert(*q == '\0' || vct_islws(*q));
hp->prxbuf = l;
if (i > 0) {
http_rxchar(hp, i);
vtc_dump(hp->vl, 4, "chunk",
hp->rxbuf + l, i);
}
l = hp->prxbuf;
http_rxchar(hp, 2);
if(!vct_iscrlf(hp->rxbuf[l]))
vtc_log(hp->vl, 0,
"Wrong chunk tail[0] = %02x",
hp->rxbuf[l] & 0xff);
if(!vct_iscrlf(hp->rxbuf[l + 1]))
vtc_log(hp->vl, 0,
"Wrong chunk tail[1] = %02x",
hp->rxbuf[l + 1] & 0xff);
hp->prxbuf = l;
hp->rxbuf[l] = '\0';
return (i);
}
/********************************************************************** /**********************************************************************
* Swallow a HTTP message body * Swallow a HTTP message body
*/ */
...@@ -378,15 +422,13 @@ http_rxchar(struct http *hp, int n) ...@@ -378,15 +422,13 @@ http_rxchar(struct http *hp, int n)
static void static void
http_swallow_body(struct http *hp, char * const *hh, int body) http_swallow_body(struct http *hp, char * const *hh, int body)
{ {
char *p, *q; char *p;
int i, l, ll; int i, l, ll;
ll = 0; ll = 0;
p = http_find_header(hh, "content-length"); p = http_find_header(hh, "content-length");
if (p != NULL) { if (p != NULL) {
l = strtoul(p, NULL, 0); l = strtoul(p, NULL, 0);
hp->body = hp->rxbuf + hp->prxbuf;
http_rxchar(hp, l); http_rxchar(hp, l);
vtc_dump(hp->vl, 4, "body", hp->body, l); vtc_dump(hp->vl, 4, "body", hp->body, l);
hp->bodyl = l; hp->bodyl = l;
...@@ -395,44 +437,10 @@ http_swallow_body(struct http *hp, char * const *hh, int body) ...@@ -395,44 +437,10 @@ http_swallow_body(struct http *hp, char * const *hh, int body)
} }
p = http_find_header(hh, "transfer-encoding"); p = http_find_header(hh, "transfer-encoding");
if (p != NULL && !strcmp(p, "chunked")) { if (p != NULL && !strcmp(p, "chunked")) {
hp->body = hp->rxbuf + hp->prxbuf; while (http_rxchunk(hp) != 0)
while (1) { continue;
l = hp->prxbuf;
do
http_rxchar(hp, 1);
while (hp->rxbuf[hp->prxbuf - 1] != '\n');
vtc_dump(hp->vl, 4, "len", hp->rxbuf + l, -1);
i = strtoul(hp->rxbuf + l, &q, 16);
if ((q == hp->rxbuf + l) ||
(*q != '\0' && !vct_islws(*q))) {
vtc_log(hp->vl, 0, "chunked fail %02x @ %d",
*q, q - (hp->rxbuf + l));
}
assert(q != hp->rxbuf + l);
assert(*q == '\0' || vct_islws(*q));
hp->prxbuf = l;
if (i > 0) {
ll += i;
http_rxchar(hp, i);
vtc_dump(hp->vl, 4, "chunk",
hp->rxbuf + l, i);
}
l = hp->prxbuf;
http_rxchar(hp, 2);
if(!vct_iscrlf(hp->rxbuf[l]))
vtc_log(hp->vl, 0,
"Wrong chunk tail[0] = %02x",
hp->rxbuf[l] & 0xff);
if(!vct_iscrlf(hp->rxbuf[l + 1]))
vtc_log(hp->vl, 0,
"Wrong chunk tail[1] = %02x",
hp->rxbuf[l + 1] & 0xff);
hp->prxbuf = l;
hp->rxbuf[l] = '\0';
if (i == 0)
break;
}
vtc_dump(hp->vl, 4, "body", hp->body, ll); vtc_dump(hp->vl, 4, "body", hp->body, ll);
ll = hp->rxbuf + hp->prxbuf - hp->body;
hp->bodyl = ll; hp->bodyl = ll;
sprintf(hp->bodylen, "%d", ll); sprintf(hp->bodylen, "%d", ll);
return; return;
...@@ -505,8 +513,9 @@ cmd_http_rxresp(CMD_ARGS) ...@@ -505,8 +513,9 @@ cmd_http_rxresp(CMD_ARGS)
"Unknown http rxresp spec: %s\n", *av); "Unknown http rxresp spec: %s\n", *av);
http_rxhdr(hp); http_rxhdr(hp);
http_splitheader(hp, 0); http_splitheader(hp, 0);
hp->body = hp->rxbuf + hp->prxbuf;
if (!has_obj) if (!has_obj)
; return;
else if (!strcmp(hp->resp[1], "200")) else if (!strcmp(hp->resp[1], "200"))
http_swallow_body(hp, hp->resp, 1); http_swallow_body(hp, hp->resp, 1);
else else
...@@ -787,6 +796,26 @@ cmd_http_rxbody(CMD_ARGS) ...@@ -787,6 +796,26 @@ cmd_http_rxbody(CMD_ARGS)
vtc_log(hp->vl, 4, "bodylen = %s", hp->bodylen); vtc_log(hp->vl, 4, "bodylen = %s", hp->bodylen);
} }
static void
cmd_http_rxchunk(CMD_ARGS)
{
struct http *hp;
int ll, i;
(void)cmd;
(void)vl;
CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
ONLY_CLIENT(hp, av);
i = http_rxchunk(hp);
if (i == 0) {
ll = hp->rxbuf + hp->prxbuf - hp->body;
hp->bodyl = ll;
sprintf(hp->bodylen, "%d", ll);
vtc_log(hp->vl, 4, "bodylen = %s", hp->bodylen);
}
}
/********************************************************************** /**********************************************************************
* Transmit a request * Transmit a request
*/ */
...@@ -1043,6 +1072,7 @@ static const struct cmds http_cmds[] = { ...@@ -1043,6 +1072,7 @@ static const struct cmds http_cmds[] = {
{ "rxreq", cmd_http_rxreq }, { "rxreq", cmd_http_rxreq },
{ "rxhdrs", cmd_http_rxhdrs }, { "rxhdrs", cmd_http_rxhdrs },
{ "rxchunk", cmd_http_rxchunk },
{ "rxbody", cmd_http_rxbody }, { "rxbody", cmd_http_rxbody },
{ "txresp", cmd_http_txresp }, { "txresp", cmd_http_txresp },
......
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