@@ -423,10 +423,10 @@ class TestFilter(object):
423
423
424
424
hdr_validation_combos = [
425
425
h2 .utilities .HeaderValidationFlags (
426
- is_client , is_trailer , is_response_header , is_push_promise
426
+ is_client , is_trailer , is_response_header , is_push_promise , is_rfc8441_enabled
427
427
)
428
- for is_client , is_trailer , is_response_header , is_push_promise in (
429
- itertools .product ([True , False ], repeat = 4 )
428
+ for is_client , is_trailer , is_response_header , is_push_promise , is_rfc8441_enabled in (
429
+ itertools .product ([True , False ], repeat = 5 )
430
430
)
431
431
]
432
432
@@ -494,6 +494,68 @@ class TestFilter(object):
494
494
(u':path' , u'' ),
495
495
),
496
496
)
497
+ invalid_connect_request_block_bytes = (
498
+ # First, missing :authority with :protocol header
499
+ (
500
+ (b':method' , b'CONNECT' ),
501
+ (b':protocol' , b'test_value' ),
502
+ (b'host' , b'example.com' ),
503
+ ),
504
+ # Next, missing :authority without :protocol header
505
+ (
506
+ (b':method' , b'CONNECT' ),
507
+ (b'host' , b'example.com' ),
508
+ )
509
+ )
510
+ invalid_connect_request_block_unicode = (
511
+ # First, missing :authority with :protocol header
512
+ (
513
+ (u':method' , u'CONNECT' ),
514
+ (u':protocol' , u'websocket' ),
515
+ (u'host' , u'example.com' ),
516
+ ),
517
+ # Next, missing :authority without :protocol header
518
+ (
519
+ (u':method' , u'CONNECT' ),
520
+ (u'host' , u'example.com' ),
521
+ ),
522
+ )
523
+ invalid_connect_req_rfc8441_bytes = (
524
+ # First, missing :path header
525
+ (
526
+ (b':authority' , b'example.com' ),
527
+ (b':method' , b'CONNECT' ),
528
+ (b':protocol' , b'test_value' ),
529
+ (b':scheme' , b'https' ),
530
+ (b'host' , b'example.com' ),
531
+ ),
532
+ # Next, missing :scheme header
533
+ (
534
+ (b':authority' , b'example.com' ),
535
+ (b':method' , b'CONNECT' ),
536
+ (b':protocol' , b'test_value' ),
537
+ (b':path' , b'/' ),
538
+ (b'host' , b'example.com' ),
539
+ )
540
+ )
541
+ invalid_connect_req_rfc8441_unicode = (
542
+ # First, missing :path header
543
+ (
544
+ (u':authority' , u'example.com' ),
545
+ (u':method' , u'CONNECT' ),
546
+ (u':protocol' , u'test_value' ),
547
+ (u':scheme' , u'https' ),
548
+ (u'host' , u'example.com' ),
549
+ ),
550
+ # Next, missing :scheme header
551
+ (
552
+ (u':authority' , u'example.com' ),
553
+ (u':method' , u'CONNECT' ),
554
+ (u':protocol' , u'test_value' ),
555
+ (u':path' , u'/' ),
556
+ (u'host' , u'example.com' ),
557
+ )
558
+ )
497
559
498
560
# All headers that are forbidden from either request or response blocks.
499
561
forbidden_request_headers_bytes = (b':status' ,)
@@ -504,6 +566,8 @@ class TestFilter(object):
504
566
forbidden_response_headers_unicode = (
505
567
u':path' , u':scheme' , u':authority' , u':method'
506
568
)
569
+ forbidden_connect_request_headers_bytes = (b':scheme' , b':path' )
570
+ forbidden_connect_request_headers_unicode = (u':scheme' , u':path' )
507
571
508
572
@pytest .mark .parametrize ('validation_function' , validation_functions )
509
573
@pytest .mark .parametrize ('hdr_validation_flags' , hdr_validation_combos )
@@ -688,6 +752,144 @@ def test_inbound_resp_header_extra_pseudo_headers(self,
688
752
with pytest .raises (h2 .exceptions .ProtocolError ):
689
753
list (h2 .utilities .validate_headers (headers , hdr_validation_flags ))
690
754
755
+ @pytest .mark .parametrize (
756
+ 'hdr_validation_flags' , hdr_validation_request_headers_no_trailer
757
+ )
758
+ @pytest .mark .parametrize (
759
+ 'header_block' , (
760
+ invalid_connect_request_block_bytes +
761
+ invalid_connect_request_block_unicode
762
+ )
763
+ )
764
+ def test_outbound_connect_req_missing_pseudo_headers (self ,
765
+ hdr_validation_flags ,
766
+ header_block ):
767
+ if not hdr_validation_flags .is_rfc8441_enabled :
768
+ with pytest .raises (h2 .exceptions .ProtocolError ) as protocol_error :
769
+ list (
770
+ h2 .utilities .validate_outbound_headers (
771
+ header_block , hdr_validation_flags
772
+ )
773
+ )
774
+ # Check if missing :path and :scheme headers doesn't throw ProtocolError exception
775
+ assert "missing mandatory :path header" not in str (protocol_error .value )
776
+ assert "missing mandatory :scheme header" not in str (protocol_error .value )
777
+
778
+ @pytest .mark .parametrize (
779
+ 'hdr_validation_flags' , hdr_validation_request_headers_no_trailer
780
+ )
781
+ @pytest .mark .parametrize (
782
+ 'header_block' , invalid_connect_request_block_bytes
783
+ )
784
+ def test_inbound_connect_req_missing_pseudo_headers (self ,
785
+ hdr_validation_flags ,
786
+ header_block ):
787
+ if not hdr_validation_flags .is_rfc8441_enabled :
788
+ with pytest .raises (h2 .exceptions .ProtocolError ) as protocol_error :
789
+ list (
790
+ h2 .utilities .validate_headers (
791
+ header_block , hdr_validation_flags
792
+ )
793
+ )
794
+ # Check if missing :path and :scheme headers doesn't throw ProtocolError exception
795
+ assert "missing mandatory :path header" not in str (protocol_error .value )
796
+ assert "missing mandatory :scheme header" not in str (protocol_error .value )
797
+
798
+ @pytest .mark .parametrize (
799
+ 'hdr_validation_flags' , hdr_validation_request_headers_no_trailer
800
+ )
801
+ @pytest .mark .parametrize (
802
+ 'invalid_header' ,
803
+ forbidden_connect_request_headers_bytes + forbidden_connect_request_headers_unicode
804
+ )
805
+ def test_outbound_connect_req_extra_pseudo_headers (self ,
806
+ hdr_validation_flags ,
807
+ invalid_header ):
808
+ """
809
+ Inbound request header blocks containing the forbidden request headers
810
+ fail validation.
811
+ """
812
+ headers = [
813
+ (b':authority' , b'google.com' ),
814
+ (b':method' , b'CONNECT' ),
815
+ (b':protocol' , b'websocket' ),
816
+ ]
817
+ if not hdr_validation_flags .is_rfc8441_enabled :
818
+ headers .append ((invalid_header , b'some value' ))
819
+ with pytest .raises (h2 .exceptions .ProtocolError ) as protocol_error :
820
+ list (h2 .utilities .validate_outbound_headers (headers , hdr_validation_flags ))
821
+ if isinstance (invalid_header , bytes ):
822
+ expected_exception_string = (b'Header block must not contain ' + invalid_header + b' header' )\
823
+ .decode ("utf-8" )
824
+ else :
825
+ expected_exception_string = 'Header block must not contain ' + invalid_header + ' header'
826
+ assert expected_exception_string == str (protocol_error .value )
827
+
828
+ @pytest .mark .parametrize (
829
+ 'hdr_validation_flags' , hdr_validation_request_headers_no_trailer
830
+ )
831
+ @pytest .mark .parametrize (
832
+ 'invalid_header' ,
833
+ forbidden_connect_request_headers_bytes
834
+ )
835
+ def test_inbound_connect_req_extra_pseudo_headers (self ,
836
+ hdr_validation_flags ,
837
+ invalid_header ):
838
+ """
839
+ Inbound request header blocks containing the forbidden request headers
840
+ fail validation.
841
+ """
842
+ headers = [
843
+ (b':authority' , b'google.com' ),
844
+ (b':method' , b'CONNECT' ),
845
+ (b':protocol' , b'some value' ),
846
+ ]
847
+ if not hdr_validation_flags .is_rfc8441_enabled :
848
+ headers .append ((invalid_header , b'some value' ))
849
+ with pytest .raises (h2 .exceptions .ProtocolError ) as protocol_error :
850
+ list (h2 .utilities .validate_headers (headers , hdr_validation_flags ))
851
+ assert (b'Header block must not contain ' + invalid_header + b' header' ).decode ("utf-8" ) \
852
+ == str (protocol_error .value )
853
+
854
+
855
+ @pytest .mark .parametrize (
856
+ 'hdr_validation_flags' , hdr_validation_request_headers_no_trailer
857
+ )
858
+ @pytest .mark .parametrize (
859
+ 'header_block' , (
860
+ invalid_connect_req_rfc8441_bytes +
861
+ invalid_connect_req_rfc8441_unicode
862
+ )
863
+ )
864
+ def test_outbound_connect_req_rfc8441_missing_pseudo_headers (self ,
865
+ hdr_validation_flags ,
866
+ header_block ):
867
+ if hdr_validation_flags .is_rfc8441_enabled :
868
+ with pytest .raises (h2 .exceptions .ProtocolError ):
869
+ list (
870
+ h2 .utilities .validate_outbound_headers (
871
+ header_block , hdr_validation_flags
872
+ )
873
+ )
874
+
875
+ @pytest .mark .parametrize (
876
+ 'hdr_validation_flags' , hdr_validation_request_headers_no_trailer
877
+ )
878
+ @pytest .mark .parametrize (
879
+ 'header_block' , invalid_connect_req_rfc8441_bytes
880
+ )
881
+ def test_inbound_connect_req_rfc8441_missing_pseudo_headers (self ,
882
+ hdr_validation_flags ,
883
+ header_block ):
884
+ if hdr_validation_flags .is_rfc8441_enabled :
885
+ print ("here" , header_block )
886
+ with pytest .raises (h2 .exceptions .ProtocolError ):
887
+ list (
888
+ h2 .utilities .validate_headers (
889
+ header_block , hdr_validation_flags
890
+ )
891
+ )
892
+
691
893
692
894
class TestOversizedHeaders (object ):
693
895
"""
0 commit comments