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