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