comparison h2_headers.t @ 1823:1e1d0f3874b0

Tests: expect HTTP 400 on HTTP/2 header validation errors.
author Maxim Dounin <mdounin@mdounin.ru>
date Fri, 10 Mar 2023 07:30:28 +0300
parents 3052d6ea8ff3
children 236d038dc04a
comparison
equal deleted inserted replaced
1822:de6aeda5c274 1823:1e1d0f3874b0
21 ############################################################################### 21 ###############################################################################
22 22
23 select STDERR; $| = 1; 23 select STDERR; $| = 1;
24 select STDOUT; $| = 1; 24 select STDOUT; $| = 1;
25 25
26 my $t = Test::Nginx->new()->has(qw/http http_v2 proxy rewrite/)->plan(107) 26 my $t = Test::Nginx->new()->has(qw/http http_v2 proxy rewrite/)->plan(103)
27 ->write_file_expand('nginx.conf', <<'EOF'); 27 ->write_file_expand('nginx.conf', <<'EOF');
28 28
29 %%TEST_GLOBALS%% 29 %%TEST_GLOBALS%%
30 30
31 daemon off; 31 daemon off;
941 { name => ':method', value => 'GET', mode => 0 }, 941 { name => ':method', value => 'GET', mode => 0 },
942 { name => ':scheme', value => 'http', mode => 0 }, 942 { name => ':scheme', value => 'http', mode => 0 },
943 { name => ':path', value => '/proxy2/', mode => 1 }, 943 { name => ':path', value => '/proxy2/', mode => 1 },
944 { name => ':authority', value => 'localhost', mode => 1 }, 944 { name => ':authority', value => 'localhost', mode => 1 },
945 { name => 'x-foo', value => "x-bar\r\nreferer:see-this", mode => 2 }]}); 945 { name => 'x-foo', value => "x-bar\r\nreferer:see-this", mode => 2 }]});
946 $frames = $s->read(all => [{ type => 'RST_STREAM' }]); 946 $frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
947 947
948 # 10.3. Intermediary Encapsulation Attacks 948 # 10.3. Intermediary Encapsulation Attacks
949 # An intermediary therefore cannot translate an HTTP/2 request or response 949 # An intermediary therefore cannot translate an HTTP/2 request or response
950 # containing an invalid field name into an HTTP/1.1 message. 950 # containing an invalid field name into an HTTP/1.1 message.
951 951
952 ($frame) = grep { $_->{type} eq "HEADERS" } @$frames; 952 ($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
953 isnt($frame->{headers}->{'x-referer'}, 'see-this', 'newline in request header'); 953 isnt($frame->{headers}->{'x-referer'}, 'see-this', 'newline in request header');
954 954
955 # 8.1.2.6. Malformed Requests and Responses 955 TODO: {
956 # Malformed requests or responses that are detected MUST be treated 956 local $TODO = 'not yet' unless $t->has_version('1.23.4');
957 # as a stream error (Section 5.4.2) of type PROTOCOL_ERROR. 957
958 958 is($frame->{headers}->{':status'}, 400, 'newline in request header - bad request');
959 ($frame) = grep { $_->{type} eq "RST_STREAM" } @$frames; 959
960 is($frame->{sid}, $sid, 'newline in request header - RST_STREAM sid'); 960 }
961 is($frame->{length}, 4, 'newline in request header - RST_STREAM length');
962 is($frame->{flags}, 0, 'newline in request header - RST_STREAM flags');
963 is($frame->{code}, 1, 'newline in request header - RST_STREAM code');
964 961
965 # invalid header name as seen with underscore should not lead to ignoring rest 962 # invalid header name as seen with underscore should not lead to ignoring rest
966 963
967 $s = Test::Nginx::HTTP2->new(); 964 $s = Test::Nginx::HTTP2->new();
968 $sid = $s->new_stream({ headers => [ 965 $sid = $s->new_stream({ headers => [
975 $frames = $s->read(all => [{ type => 'HEADERS' }]); 972 $frames = $s->read(all => [{ type => 'HEADERS' }]);
976 973
977 ($frame) = grep { $_->{type} eq "HEADERS" } @$frames; 974 ($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
978 is($frame->{headers}->{'x-referer'}, 'see-this', 'after invalid header name'); 975 is($frame->{headers}->{'x-referer'}, 'see-this', 'after invalid header name');
979 976
980 # other invalid header name characters as seen with ':' result in RST_STREAM 977 # other invalid header name characters as seen with ':'
978
979 TODO: {
980 local $TODO = 'not yet' unless $t->has_version('1.23.4');
981 981
982 $s = Test::Nginx::HTTP2->new(); 982 $s = Test::Nginx::HTTP2->new();
983 $sid = $s->new_stream({ headers => [ 983 $sid = $s->new_stream({ headers => [
984 { name => ':method', value => 'GET', mode => 0 }, 984 { name => ':method', value => 'GET', mode => 0 },
985 { name => ':scheme', value => 'http', mode => 0 }, 985 { name => ':scheme', value => 'http', mode => 0 },
986 { name => ':path', value => '/', mode => 0 }, 986 { name => ':path', value => '/', mode => 0 },
987 { name => ':authority', value => 'localhost', mode => 1 }, 987 { name => ':authority', value => 'localhost', mode => 1 },
988 { name => 'x:foo', value => "x-bar", mode => 2 }, 988 { name => 'x:foo', value => "x-bar", mode => 2 },
989 { name => 'referer', value => "see-this", mode => 1 }]}); 989 { name => 'referer', value => "see-this", mode => 1 }]});
990 $frames = $s->read(all => [{ type => 'RST_STREAM' }]); 990 $frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
991 991
992 ($frame) = grep { $_->{type} eq "RST_STREAM" } @$frames; 992 ($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
993 is($frame->{sid}, $sid, 'colon in header name - RST_STREAM sid'); 993 is($frame->{headers}->{':status'}, 400, 'colon in header name');
994 is($frame->{code}, 1, 'colon in header name - RST_STREAM code');
995
996 TODO: {
997 local $TODO = 'not yet' unless $t->has_version('1.21.1');
998 994
999 $s = Test::Nginx::HTTP2->new(); 995 $s = Test::Nginx::HTTP2->new();
1000 $sid = $s->new_stream({ headers => [ 996 $sid = $s->new_stream({ headers => [
1001 { name => ':method', value => 'GET', mode => 0 }, 997 { name => ':method', value => 'GET', mode => 0 },
1002 { name => ':scheme', value => 'http', mode => 0 }, 998 { name => ':scheme', value => 'http', mode => 0 },
1003 { name => ':path', value => '/', mode => 0 }, 999 { name => ':path', value => '/', mode => 0 },
1004 { name => ':authority', value => 'localhost', mode => 1 }, 1000 { name => ':authority', value => 'localhost', mode => 1 },
1005 { name => 'x foo', value => "bar", mode => 2 }]}); 1001 { name => 'x foo', value => "bar", mode => 2 }]});
1006 $frames = $s->read(all => [{ type => 'RST_STREAM' }]); 1002 $frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
1007 1003
1008 ($frame) = grep { $_->{type} eq "RST_STREAM" } @$frames; 1004 ($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
1009 ok($frame, 'space in header name - RST_STREAM sid'); 1005 is($frame->{headers}->{':status'}, 400, 'space in header name');
1010 1006
1011 $s = Test::Nginx::HTTP2->new(); 1007 $s = Test::Nginx::HTTP2->new();
1012 $sid = $s->new_stream({ headers => [ 1008 $sid = $s->new_stream({ headers => [
1013 { name => ':method', value => 'GET', mode => 0 }, 1009 { name => ':method', value => 'GET', mode => 0 },
1014 { name => ':scheme', value => 'http', mode => 0 }, 1010 { name => ':scheme', value => 'http', mode => 0 },
1015 { name => ':path', value => '/', mode => 0 }, 1011 { name => ':path', value => '/', mode => 0 },
1016 { name => ':authority', value => 'localhost', mode => 1 }, 1012 { name => ':authority', value => 'localhost', mode => 1 },
1017 { name => "foo\x02", value => "bar", mode => 2 }]}); 1013 { name => "foo\x02", value => "bar", mode => 2 }]});
1018 $frames = $s->read(all => [{ type => 'RST_STREAM' }]); 1014 $frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
1019 1015
1020 ($frame) = grep { $_->{type} eq "RST_STREAM" } @$frames; 1016 ($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
1021 ok($frame, 'control in header name - RST_STREAM sid'); 1017 is($frame->{headers}->{':status'}, 400, 'control in header name');
1022 1018
1023 } 1019 }
1024 1020
1025 # header name with underscore - underscores_in_headers on 1021 # header name with underscore - underscores_in_headers on
1026 1022