comparison http_resolver.t @ 834:37747a4ff78e

Tests: simple http resolver tests over TCP.
author Sergey Kandaurov <pluknet@nginx.com>
date Thu, 28 Jan 2016 20:08:54 +0300
parents 9caacdb56b53
children a9c4cebcfe69
comparison
equal deleted inserted replaced
833:62315953d703 834:37747a4ff78e
9 9
10 use warnings; 10 use warnings;
11 use strict; 11 use strict;
12 12
13 use Test::More; 13 use Test::More;
14
15 use IO::Select;
14 16
15 BEGIN { use FindBin; chdir($FindBin::Bin); } 17 BEGIN { use FindBin; chdir($FindBin::Bin); }
16 18
17 use lib 'lib'; 19 use lib 'lib';
18 use Test::Nginx qw/ :DEFAULT http_end /; 20 use Test::Nginx qw/ :DEFAULT http_end /;
78 location /bad { 80 location /bad {
79 resolver 127.0.0.1:8089; 81 resolver 127.0.0.1:8089;
80 resolver_timeout 1s; 82 resolver_timeout 1s;
81 proxy_pass http://$host:8080/backend; 83 proxy_pass http://$host:8080/backend;
82 } 84 }
85 location /tcp {
86 resolver 127.0.0.1:8083 127.0.0.1:8084;
87 resolver_timeout 1s;
88 proxy_pass http://$host:8080/backend;
89 proxy_connect_timeout 1s;
90 add_header X-IP $upstream_addr;
91 error_page 504 502 /50x;
92
93 location /tcp2 {
94 resolver_timeout 8s;
95 proxy_pass http://$host:8080/backend;
96 }
97 }
83 98
84 location /backend { 99 location /backend {
85 return 200; 100 return 200;
86 } 101 }
87 location /50x { 102 location /50x {
92 107
93 EOF 108 EOF
94 109
95 $t->run_daemon(\&dns_daemon, 8081, $t); 110 $t->run_daemon(\&dns_daemon, 8081, $t);
96 $t->run_daemon(\&dns_daemon, 8082, $t); 111 $t->run_daemon(\&dns_daemon, 8082, $t);
112 $t->run_daemon(\&dns_daemon, 8083, $t, tcp => 1);
97 $t->run_daemon(\&dns_daemon, 8089, $t); 113 $t->run_daemon(\&dns_daemon, 8089, $t);
98 114
99 $t->run()->plan(35); 115 $t->run()->plan(38);
100 116
101 $t->waitforfile($t->testdir . '/8081'); 117 $t->waitforfile($t->testdir . '/8081');
102 $t->waitforfile($t->testdir . '/8082'); 118 $t->waitforfile($t->testdir . '/8082');
119 $t->waitforfile($t->testdir . '/8083');
103 $t->waitforfile($t->testdir . '/8089'); 120 $t->waitforfile($t->testdir . '/8089');
104 121
105 ############################################################################### 122 ###############################################################################
106 123
107 # schedule resend test, which takes about 5 seconds to complete 124 # schedule resend test, which takes about 5 seconds to complete
255 select undef, undef, undef, 1.1; 272 select undef, undef, undef, 1.1;
256 273
257 close $s; 274 close $s;
258 275
259 like(http_end($s2), qr/502 Bad/, 'timeout after aborted request'); 276 like(http_end($s2), qr/502 Bad/, 'timeout after aborted request');
277
278 # resend DNS query over TCP once UDP response came truncated
279
280 TODO: {
281 local $TODO = 'not yet' unless $t->has_version('1.9.11');
282
283 unlike(http_host_header('tcp.example.net', '/tcp'), qr/127.0.0.201/, 'tc');
284 like(http_host_header('tcp.example.net', '/tcp'), qr/X-IP: 127.0.0.1/, 'tcp');
285 like(http_host_header('tcp2.example.net', '/tcp2'), qr/X-IP: 127.0.0.1/,
286 'tcp with resend');
287
288 }
260 289
261 ############################################################################### 290 ###############################################################################
262 291
263 sub http_host_header { 292 sub http_host_header {
264 my ($host, $uri, %extra) = @_; 293 my ($host, $uri, %extra) = @_;
279 } 308 }
280 309
281 ############################################################################### 310 ###############################################################################
282 311
283 sub reply_handler { 312 sub reply_handler {
284 my ($recv_data, $port, $state) = @_; 313 my ($recv_data, $port, $state, %extra) = @_;
285 314
286 my (@name, @rdata); 315 my (@name, @rdata);
287 316
288 use constant NOERROR => 0; 317 use constant NOERROR => 0;
289 use constant FORMERR => 1; 318 use constant FORMERR => 1;
462 } 491 }
463 492
464 if ($type == A) { 493 if ($type == A) {
465 push @rdata, rd_addr($ttl, '127.0.0.1'); 494 push @rdata, rd_addr($ttl, '127.0.0.1');
466 } 495 }
496
497 } elsif ($name =~ /tcp2?.example.net/) {
498 $hdr |= 0x0300 unless $extra{tcp};
499 push @rdata, rd_addr($ttl, $extra{tcp}
500 ? '127.0.0.1' : '127.0.0.201') if $type == A;
467 } 501 }
468 502
469 $len = @name; 503 $len = @name;
470 pack("n6 (C/a*)$len x n2", $id, $hdr | $rcode, 1, scalar @rdata, 504 pack("n6 (C/a*)$len x n2", $id, $hdr | $rcode, 1, scalar @rdata,
471 0, 0, @name, $type, $class) . join('', @rdata); 505 0, 0, @name, $type, $class) . join('', @rdata);
480 514
481 pack 'n3N nC4', 0xc00c, A, IN, $ttl, eval "scalar $code", eval($code); 515 pack 'n3N nC4', 0xc00c, A, IN, $ttl, eval "scalar $code", eval($code);
482 } 516 }
483 517
484 sub dns_daemon { 518 sub dns_daemon {
485 my ($port, $t) = @_; 519 my ($port, $t, %extra) = @_;
486 520
487 my ($data, $recv_data); 521 my ($data, $recv_data);
488 my $socket = IO::Socket::INET->new( 522 my $socket = IO::Socket::INET->new(
489 LocalAddr => '127.0.0.1', 523 LocalAddr => '127.0.0.1',
490 LocalPort => $port, 524 LocalPort => $port,
491 Proto => 'udp', 525 Proto => 'udp',
492 ) 526 )
493 or die "Can't create listening socket: $!\n"; 527 or die "Can't create listening socket: $!\n";
528
529 my $sel = IO::Select->new($socket);
530 my $tcp = 0;
531
532 if ($extra{tcp}) {
533 $tcp = IO::Socket::INET->new(
534 Proto => 'tcp',
535 LocalHost => "127.0.0.1:$port",
536 Listen => 5,
537 Reuse => 1
538 )
539 or die "Can't create listening socket: $!\n";
540
541 $sel->add($tcp);
542 }
543
544 local $SIG{PIPE} = 'IGNORE';
494 545
495 # track number of relevant queries 546 # track number of relevant queries
496 547
497 my %state = ( 548 my %state = (
498 cnamecnt => 0, 549 cnamecnt => 0,
510 # signal we are ready 561 # signal we are ready
511 562
512 open my $fh, '>', $t->testdir() . '/' . $port; 563 open my $fh, '>', $t->testdir() . '/' . $port;
513 close $fh; 564 close $fh;
514 565
515 while (1) { 566 while (my @ready = $sel->can_read) {
516 $socket->recv($recv_data, 65536); 567 foreach my $fh (@ready) {
517 next if $port == 8089; 568 if ($tcp == $fh) {
518 $data = reply_handler($recv_data, $port, \%state); 569 my $new = $fh->accept;
519 $socket->send($data); 570 $new->autoflush(1);
571 $sel->add($new);
572
573 } elsif ($socket == $fh) {
574 $fh->recv($recv_data, 65536);
575 $data = reply_handler($recv_data, $port,
576 \%state);
577 $fh->send($data);
578
579 } else {
580 $fh->recv($recv_data, 65536);
581 unless (length $recv_data) {
582 $sel->remove($fh);
583 $fh->close;
584 next;
585 }
586
587 again:
588 my $len = unpack("n", $recv_data);
589 $data = substr $recv_data, 2, $len;
590 $data = reply_handler($data, $port, \%state,
591 tcp => 1);
592 $data = pack("n", length $data) . $data;
593 $fh->send($data);
594 $recv_data = substr $recv_data, 2 + $len;
595 goto again if length $recv_data;
596 }
597 }
520 } 598 }
521 } 599 }
522 600
523 ############################################################################### 601 ###############################################################################