Skip to content

Commit 82b0a62

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 34d1193 commit 82b0a62

File tree

2 files changed

+38
-10
lines changed

2 files changed

+38
-10
lines changed

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

+2
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ struct h2_req {
134134
/* Where to wake this stream up */
135135
struct worker *wrk;
136136

137+
ssize_t reqbody_bytes;
138+
137139
VTAILQ_ENTRY(h2_req) tx_list;
138140
h2_error error;
139141
};

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

+36-10
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,7 @@ h2_end_headers(struct worker *wrk, struct h2_sess *h2,
554554
struct req *req, struct h2_req *r2)
555555
{
556556
h2_error h2e;
557+
ssize_t cl;
557558

558559
ASSERT_RXTHR(h2);
559560
assert(r2->state == H2_S_OPEN);
@@ -574,16 +575,24 @@ h2_end_headers(struct worker *wrk, struct h2_sess *h2,
574575
// XXX: Have I mentioned H/2 Is hodge-podge ?
575576
http_CollectHdrSep(req->http, H_Cookie, "; "); // rfc7540,l,3114,3120
576577

578+
cl = http_GetContentLength(req->http);
579+
assert(cl >= -2);
580+
if (cl == -2) {
581+
VSLb(h2->vsl, SLT_Debug, "Non-parseable Content-Length");
582+
return (H2SE_PROTOCOL_ERROR);
583+
}
584+
577585
if (req->req_body_status == NULL) {
578-
if (!http_GetHdr(req->http, H_Content_Length, NULL))
586+
if (cl == -1)
579587
req->req_body_status = BS_EOF;
580588
else
581589
req->req_body_status = BS_LENGTH;
590+
req->htc->content_length = cl;
582591
} else {
583592
/* A HEADER frame contained END_STREAM */
584593
assert (req->req_body_status == BS_NONE);
585594
r2->state = H2_S_CLOS_REM;
586-
if (http_GetContentLength(req->http) > 0)
595+
if (cl > 0)
587596
return (H2CE_PROTOCOL_ERROR); //rfc7540,l,1838,1840
588597
}
589598

@@ -737,6 +746,7 @@ h2_rx_data(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2)
737746
int w1 = 0, w2 = 0;
738747
char buf[4];
739748
unsigned wi;
749+
ssize_t cl;
740750

741751
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
742752
ASSERT_RXTHR(h2);
@@ -755,6 +765,23 @@ h2_rx_data(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2)
755765
Lck_Unlock(&h2->sess->mtx);
756766
return (h2->error ? h2->error : r2->error);
757767
}
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+
758785
AZ(h2->mailcall);
759786
h2->mailcall = r2;
760787
h2->req0->r_window -= h2->rxf_len;
@@ -773,6 +800,8 @@ h2_rx_data(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2)
773800
r2->r_window += wi;
774801
w2 = 1;
775802
}
803+
804+
776805
Lck_Unlock(&h2->sess->mtx);
777806

778807
if (w1 || w2) {
@@ -795,7 +824,7 @@ h2_vfp_body(struct vfp_ctx *vc, struct vfp_entry *vfe, void *ptr, ssize_t *lp)
795824
struct h2_req *r2;
796825
struct h2_sess *h2;
797826
unsigned l;
798-
enum vfp_status retval = VFP_OK;
827+
enum vfp_status retval;
799828

800829
CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
801830
CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
@@ -808,7 +837,6 @@ h2_vfp_body(struct vfp_ctx *vc, struct vfp_entry *vfe, void *ptr, ssize_t *lp)
808837
*lp = 0;
809838

810839
Lck_Lock(&h2->sess->mtx);
811-
assert (r2->state == H2_S_OPEN);
812840
r2->cond = &vc->wrk->cond;
813841
while (h2->mailcall != r2 && h2->error == 0 && r2->error == 0)
814842
AZ(Lck_CondWait(r2->cond, &h2->sess->mtx, 0));
@@ -831,12 +859,10 @@ h2_vfp_body(struct vfp_ctx *vc, struct vfp_entry *vfe, void *ptr, ssize_t *lp)
831859
Lck_Unlock(&h2->sess->mtx);
832860
return (VFP_OK);
833861
}
834-
if (h2->rxf_len == 0) {
835-
if (h2->rxf_flags & H2FF_DATA_END_STREAM) {
836-
retval = VFP_END;
837-
r2->state = H2_S_CLOS_REM;
838-
}
839-
}
862+
if (h2->rxf_len == 0 && r2->state >= H2_S_CLOS_REM)
863+
retval = VFP_END;
864+
else
865+
retval = VFP_OK;
840866
h2->mailcall = NULL;
841867
AZ(pthread_cond_signal(h2->cond));
842868
}

0 commit comments

Comments
 (0)