Skip to content

Commit 9be2219

Browse files
committed
Take content length into account on H/2 request bodies
When receiving H/2 data frames, make sure to take the advertised content length into account, and fail appropriately if the combined sum of the data frames does not match the content length.
1 parent 6e27d4d commit 9be2219

File tree

2 files changed

+40
-11
lines changed

2 files changed

+40
-11
lines changed

Diff for: bin/varnishd/http2/cache_http2.h

+2
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ struct h2_req {
131131
/* Where to wake this stream up */
132132
struct worker *wrk;
133133

134+
ssize_t reqbody_bytes;
135+
134136
VTAILQ_ENTRY(h2_req) tx_list;
135137
h2_error error;
136138

Diff for: bin/varnishd/http2/cache_http2_proto.c

+38-11
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ h2_end_headers(struct worker *wrk, struct h2_sess *h2,
546546
struct req *req, struct h2_req *r2)
547547
{
548548
h2_error h2e;
549-
const char *b;
549+
ssize_t cl;
550550

551551
ASSERT_RXTHR(h2);
552552
assert(r2->state == H2_S_OPEN);
@@ -572,14 +572,24 @@ h2_end_headers(struct worker *wrk, struct h2_sess *h2,
572572
// XXX: Have I mentioned H/2 Is hodge-podge ?
573573
http_CollectHdrSep(req->http, H_Cookie, "; "); // rfc7540,l,3114,3120
574574

575+
cl = http_GetContentLength(req->http);
576+
assert(cl >= -2);
577+
if (cl == -2) {
578+
VSLb(h2->vsl, SLT_Debug, "Non-parseable Content-Length");
579+
return (H2SE_PROTOCOL_ERROR);
580+
}
581+
575582
if (req->req_body_status == REQ_BODY_INIT) {
576-
if (!http_GetHdr(req->http, H_Content_Length, &b))
583+
if (cl == -1)
577584
req->req_body_status = REQ_BODY_WITHOUT_LEN;
578585
else
579586
req->req_body_status = REQ_BODY_WITH_LEN;
587+
req->htc->content_length = cl;
580588
} else {
589+
/* A HEADER frame contained END_STREAM */
581590
assert (req->req_body_status == REQ_BODY_NONE);
582-
if (http_GetContentLength(req->http) > 0)
591+
r2->state = H2_S_CLOS_REM;
592+
if (cl > 0)
583593
return (H2CE_PROTOCOL_ERROR); //rfc7540,l,1838,1840
584594
}
585595

@@ -736,6 +746,7 @@ h2_rx_data(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2)
736746
int w1 = 0, w2 = 0;
737747
char buf[4];
738748
unsigned wi;
749+
ssize_t cl;
739750

740751
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
741752
ASSERT_RXTHR(h2);
@@ -754,6 +765,23 @@ h2_rx_data(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2)
754765
Lck_Unlock(&h2->sess->mtx);
755766
return (h2->error ? h2->error : r2->error);
756767
}
768+
769+
r2->reqbody_bytes += h2->rxf_len;
770+
if (h2->rxf_flags & H2FF_DATA_END_STREAM)
771+
r2->state = H2_S_CLOS_REM;
772+
cl = r2->req->htc->content_length;
773+
if (cl >= 0 && (r2->reqbody_bytes > cl ||
774+
(r2->state >= H2_S_CLOS_REM && r2->reqbody_bytes != cl))) {
775+
VSLb(h2->vsl, SLT_Debug,
776+
"H2: stream %u: Received data and Content-Length"
777+
" mismatch", h2->rxf_stream);
778+
r2->error = H2SE_PROTOCOL_ERROR; // rfc7540,l,3150,3163
779+
if (r2->cond)
780+
AZ(pthread_cond_signal(r2->cond));
781+
Lck_Unlock(&h2->sess->mtx);
782+
return (H2SE_PROTOCOL_ERROR);
783+
}
784+
757785
AZ(h2->mailcall);
758786
h2->mailcall = r2;
759787
h2->req0->r_window -= h2->rxf_len;
@@ -772,6 +800,8 @@ h2_rx_data(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2)
772800
r2->r_window += wi;
773801
w2 = 1;
774802
}
803+
804+
775805
Lck_Unlock(&h2->sess->mtx);
776806

777807
if (w1 || w2) {
@@ -794,7 +824,7 @@ h2_vfp_body(struct vfp_ctx *vc, struct vfp_entry *vfe, void *ptr, ssize_t *lp)
794824
struct h2_req *r2;
795825
struct h2_sess *h2;
796826
unsigned l;
797-
enum vfp_status retval = VFP_OK;
827+
enum vfp_status retval;
798828

799829
CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
800830
CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
@@ -807,7 +837,6 @@ h2_vfp_body(struct vfp_ctx *vc, struct vfp_entry *vfe, void *ptr, ssize_t *lp)
807837
*lp = 0;
808838

809839
Lck_Lock(&h2->sess->mtx);
810-
assert (r2->state == H2_S_OPEN);
811840
r2->cond = &vc->wrk->cond;
812841
while (h2->mailcall != r2 && h2->error == 0 && r2->error == 0)
813842
AZ(Lck_CondWait(r2->cond, &h2->sess->mtx, 0));
@@ -830,12 +859,10 @@ h2_vfp_body(struct vfp_ctx *vc, struct vfp_entry *vfe, void *ptr, ssize_t *lp)
830859
Lck_Unlock(&h2->sess->mtx);
831860
return (VFP_OK);
832861
}
833-
if (h2->rxf_len == 0) {
834-
if (h2->rxf_flags & H2FF_DATA_END_STREAM) {
835-
retval = VFP_END;
836-
r2->state = H2_S_CLOS_REM;
837-
}
838-
}
862+
if (h2->rxf_len == 0 && r2->state >= H2_S_CLOS_REM)
863+
retval = VFP_END;
864+
else
865+
retval = VFP_OK;
839866
h2->mailcall = NULL;
840867
AZ(pthread_cond_signal(h2->cond));
841868
}

0 commit comments

Comments
 (0)