@@ -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