comparison lib/Test/Nginx/HTTP2.pm @ 1622:5b3d33b5556c

Tests: converted HTTP2 raw_read() and raw_write() to class methods.
author Sergey Kandaurov <pluknet@nginx.com>
date Tue, 24 Nov 2020 01:23:00 +0000
parents 4e48bf51714f
children 3fe652bc9dae
comparison
equal deleted inserted replaced
1621:fd440d324700 1622:5b3d33b5556c
37 37
38 my $s = $extra{socket} || new_socket($port, %extra); 38 my $s = $extra{socket} || new_socket($port, %extra);
39 my $preface = defined $extra{preface} ? $extra{preface} 39 my $preface = defined $extra{preface} ? $extra{preface}
40 : 'PRI * HTTP/2.0' . CRLF . CRLF . 'SM' . CRLF . CRLF; 40 : 'PRI * HTTP/2.0' . CRLF . CRLF . 'SM' . CRLF . CRLF;
41 41
42 if ($extra{proxy}) {
43 raw_write($s, $extra{proxy});
44 }
45
46 # preface
47
48 raw_write($s, $preface);
49
50 my $self = bless { 42 my $self = bless {
51 socket => $s, last_stream => -1, 43 socket => $s, last_stream => -1,
52 dynamic_encode => [ static_table() ], 44 dynamic_encode => [ static_table() ],
53 dynamic_decode => [ static_table() ], 45 dynamic_decode => [ static_table() ],
54 static_table_size => scalar @{[static_table()]}, 46 static_table_size => scalar @{[static_table()]},
55 iws => 65535, conn_window => 65535, streams => {} 47 iws => 65535, conn_window => 65535, streams => {}
56 }, $class; 48 }, $class;
57 49
50 if ($extra{proxy}) {
51 $self->raw_write($extra{proxy});
52 }
53
54 # preface
55
56 $self->raw_write($preface);
57
58 return $self if $extra{pure}; 58 return $self if $extra{pure};
59 59
60 # update windows, if any 60 # update windows, if any
61 61
62 my $frames = $self->read(all => [ 62 my $frames = $self->read(all => [
74 } 74 }
75 75
76 sub h2_ping { 76 sub h2_ping {
77 my ($self, $payload) = @_; 77 my ($self, $payload) = @_;
78 78
79 raw_write($self->{socket}, pack("x2C2x5a8", 8, 0x6, $payload)); 79 $self->raw_write(pack("x2C2x5a8", 8, 0x6, $payload));
80 } 80 }
81 81
82 sub h2_rst { 82 sub h2_rst {
83 my ($self, $stream, $error) = @_; 83 my ($self, $stream, $error) = @_;
84 84
85 raw_write($self->{socket}, pack("x2C2xNN", 4, 0x3, $stream, $error)); 85 $self->raw_write(pack("x2C2xNN", 4, 0x3, $stream, $error));
86 } 86 }
87 87
88 sub h2_goaway { 88 sub h2_goaway {
89 my ($self, $stream, $lstream, $err, $debug, %extra) = @_; 89 my ($self, $stream, $lstream, $err, $debug, %extra) = @_;
90 $debug = '' unless defined $debug; 90 $debug = '' unless defined $debug;
91 my $len = defined $extra{len} ? $extra{len} : 8 + length($debug); 91 my $len = defined $extra{len} ? $extra{len} : 8 + length($debug);
92 my $buf = pack("x2C2xN3A*", $len, 0x7, $stream, $lstream, $err, $debug); 92 my $buf = pack("x2C2xN3A*", $len, 0x7, $stream, $lstream, $err, $debug);
93 93
94 my @bufs = map { 94 my @bufs = map {
95 raw_write($self->{socket}, substr $buf, 0, $_, ""); 95 $self->raw_write(substr $buf, 0, $_, "");
96 select undef, undef, undef, 0.2; 96 select undef, undef, undef, 0.2;
97 } @{$extra{split}}; 97 } @{$extra{split}};
98 98
99 raw_write($self->{socket}, $buf); 99 $self->raw_write($buf);
100 } 100 }
101 101
102 sub h2_priority { 102 sub h2_priority {
103 my ($self, $w, $stream, $dep, %extra) = @_; 103 my ($self, $w, $stream, $dep, %extra) = @_;
104 104
105 $stream = 0 unless defined $stream; 105 $stream = 0 unless defined $stream;
106 $dep = 0 unless defined $dep; 106 $dep = 0 unless defined $dep;
107 $dep |= $extra{excl} << 31 if exists $extra{excl}; 107 $dep |= $extra{excl} << 31 if exists $extra{excl};
108 raw_write($self->{socket}, pack("x2C2xNNC", 5, 0x2, $stream, $dep, $w)); 108 $self->raw_write(pack("x2C2xNNC", 5, 0x2, $stream, $dep, $w));
109 } 109 }
110 110
111 sub h2_window { 111 sub h2_window {
112 my ($self, $win, $stream) = @_; 112 my ($self, $win, $stream) = @_;
113 113
114 $stream = 0 unless defined $stream; 114 $stream = 0 unless defined $stream;
115 raw_write($self->{socket}, pack("x2C2xNN", 4, 0x8, $stream, $win)); 115 $self->raw_write(pack("x2C2xNN", 4, 0x8, $stream, $win));
116 } 116 }
117 117
118 sub h2_settings { 118 sub h2_settings {
119 my ($self, $ack, @pairs) = @_; 119 my ($self, $ack, @pairs) = @_;
120 120
121 my $len = 6 * @pairs / 2; 121 my $len = 6 * @pairs / 2;
122 my $buf = pack_length($len) . pack "CCx4", 0x4, $ack ? 0x1 : 0x0; 122 my $buf = pack_length($len) . pack "CCx4", 0x4, $ack ? 0x1 : 0x0;
123 $buf .= pack "nN", splice @pairs, 0, 2 while @pairs; 123 $buf .= pack "nN", splice @pairs, 0, 2 while @pairs;
124 raw_write($self->{socket}, $buf); 124 $self->raw_write($buf);
125 } 125 }
126 126
127 sub h2_unknown { 127 sub h2_unknown {
128 my ($self, $payload) = @_; 128 my ($self, $payload) = @_;
129 129
130 my $buf = pack_length(length($payload)) . pack("Cx5a*", 0xa, $payload); 130 my $buf = pack_length(length($payload)) . pack("Cx5a*", 0xa, $payload);
131 raw_write($self->{socket}, $buf); 131 $self->raw_write($buf);
132 } 132 }
133 133
134 sub h2_continue { 134 sub h2_continue {
135 my ($ctx, $stream, $uri) = @_; 135 my ($ctx, $stream, $uri) = @_;
136 136
165 165
166 $buf .= pack_body($self, $body, 0x1, $extra) if defined $body; 166 $buf .= pack_body($self, $body, 0x1, $extra) if defined $body;
167 167
168 $split = ref $extra->{split} && $extra->{split} || []; 168 $split = ref $extra->{split} && $extra->{split} || [];
169 for (@$split) { 169 for (@$split) {
170 raw_write($self->{socket}, substr($buf, 0, $_, "")); 170 $self->raw_write(substr($buf, 0, $_, ""));
171 return if $extra->{abort}; 171 return if $extra->{abort};
172 select undef, undef, undef, ($extra->{split_delay} || 0.2); 172 select undef, undef, undef, ($extra->{split_delay} || 0.2);
173 } 173 }
174 174
175 raw_write($self->{socket}, $buf); 175 $self->raw_write($buf);
176 } 176 }
177 177
178 sub new_stream { 178 sub new_stream {
179 my ($self, $uri, $stream) = @_; 179 my ($self, $uri, $stream) = @_;
180 my ($input, $buf); 180 my ($input, $buf);
266 266
267 $buf .= pack_body($self, $body, 0x1, $uri) if defined $body; 267 $buf .= pack_body($self, $body, 0x1, $uri) if defined $body;
268 268
269 $split = ref $uri->{split} && $uri->{split} || []; 269 $split = ref $uri->{split} && $uri->{split} || [];
270 for (@$split) { 270 for (@$split) {
271 raw_write($self->{socket}, substr($buf, 0, $_, "")); 271 $self->raw_write(substr($buf, 0, $_, ""));
272 goto done if $uri->{abort}; 272 goto done if $uri->{abort};
273 select undef, undef, undef, ($uri->{split_delay} || 0.2); 273 select undef, undef, undef, ($uri->{split_delay} || 0.2);
274 } 274 }
275 275
276 raw_write($self->{socket}, $buf); 276 $self->raw_write($buf);
277 done: 277 done:
278 return $self->{last_stream}; 278 return $self->{last_stream};
279 } 279 }
280 280
281 sub read { 281 sub read {
286 my $wait = $extra{wait}; 286 my $wait = $extra{wait};
287 287
288 local $Data::Dumper::Terse = 1; 288 local $Data::Dumper::Terse = 1;
289 289
290 while (1) { 290 while (1) {
291 $buf = raw_read($s, $buf, 9, $wait); 291 $buf = $self->raw_read($buf, 9, $wait);
292 last if length $buf < 9; 292 last if length $buf < 9;
293 293
294 my $length = unpack_length($buf); 294 my $length = unpack_length($buf);
295 my $type = unpack('x3C', $buf); 295 my $type = unpack('x3C', $buf);
296 my $flags = unpack('x4C', $buf); 296 my $flags = unpack('x4C', $buf);
297 297
298 my $stream = unpack "x5 B32", $buf; 298 my $stream = unpack "x5 B32", $buf;
299 substr($stream, 0, 1) = 0; 299 substr($stream, 0, 1) = 0;
300 $stream = unpack("N", pack("B32", $stream)); 300 $stream = unpack("N", pack("B32", $stream));
301 301
302 $buf = raw_read($s, $buf, $length + 9, $wait); 302 $buf = $self->raw_read($buf, $length + 9, $wait);
303 last if length($buf) < $length + 9; 303 last if length($buf) < $length + 9;
304 304
305 $buf = substr($buf, 9); 305 $buf = substr($buf, 9);
306 306
307 my $frame = $cframe{$type}{value}($self, $buf, $length, $flags, 307 my $frame = $cframe{$type}{value}($self, $buf, $length, $flags,
317 $buf = substr($buf, $length); 317 $buf = substr($buf, $length);
318 318
319 last unless $extra{all} && test_fin($got[-1], $extra{all}); 319 last unless $extra{all} && test_fin($got[-1], $extra{all});
320 }; 320 };
321 return \@got; 321 return \@got;
322 }
323
324 sub raw_read {
325 my ($self, $buf, $len, $timo) = @_;
326 $timo = 8 unless $timo;
327 my $got = '';
328 my $s = $self->{socket};
329
330 while (length($buf) < $len && IO::Select->new($s)->can_read($timo)) {
331 $s->sysread($got, 16384) or last;
332 log_in($got);
333 $buf .= $got;
334 }
335 return $buf;
336 }
337
338 sub raw_write {
339 my ($self, $message) = @_;
340 my $s = $self->{socket};
341
342 local $SIG{PIPE} = 'IGNORE';
343
344 while (IO::Select->new($s)->can_write(0.4)) {
345 log_out($message);
346 my $n = $s->syswrite($message);
347 last unless $n;
348 $message = substr($message, $n);
349 last unless length $message;
350 }
322 } 351 }
323 352
324 ############################################################################### 353 ###############################################################################
325 354
326 sub pack_body { 355 sub pack_body {
459 pack 'c3', unpack 'xc3', pack 'N', $_[0]; 488 pack 'c3', unpack 'xc3', pack 'N', $_[0];
460 } 489 }
461 490
462 sub unpack_length { 491 sub unpack_length {
463 unpack 'N', pack 'xc3', unpack 'c3', $_[0]; 492 unpack 'N', pack 'xc3', unpack 'c3', $_[0];
464 }
465
466 sub raw_read {
467 my ($s, $buf, $len, $timo) = @_;
468 $timo = 8 unless $timo;
469 my $got = '';
470
471 while (length($buf) < $len && IO::Select->new($s)->can_read($timo)) {
472 $s->sysread($got, 16384) or last;
473 log_in($got);
474 $buf .= $got;
475 }
476 return $buf;
477 }
478
479 sub raw_write {
480 my ($s, $message) = @_;
481
482 local $SIG{PIPE} = 'IGNORE';
483
484 while (IO::Select->new($s)->can_write(0.4)) {
485 log_out($message);
486 my $n = $s->syswrite($message);
487 last unless $n;
488 $message = substr($message, $n);
489 last unless length $message;
490 }
491 } 493 }
492 494
493 sub new_socket { 495 sub new_socket {
494 my ($port, %extra) = @_; 496 my ($port, %extra) = @_;
495 my $npn = $extra{'npn'}; 497 my $npn = $extra{'npn'};