-# Copyright (c) 2010-2014 Alexander Bluhm <bluhm@openbsd.org>
+# Copyright (c) 2010-2015 Alexander Bluhm <bluhm@openbsd.org>
# Copyright (c) 2014 Reyk Floeter <reyk@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
-# $OpenBSD: Relayd.pm,v 1.13 2014/12/14 20:30:51 bluhm Exp $
+# $OpenBSD: Relayd.pm,v 1.14 2015/05/17 22:49:03 bluhm Exp $
# Copyright (c) 2010-2014 Alexander Bluhm <bluhm@openbsd.org>
#
open(my $fh, '>', $self->{conffile})
or die ref($self), " conf file $self->{conffile} create failed: $!";
print $fh "log all\n";
+ print $fh "prefork 1\n"; # only crashes of first child are observed
print $fh "table <table-$test> { $self->{connectaddr} }\n"
if defined($self->{table});
--- /dev/null
+# test http connection over http relay invoking the callback.
+# The client uses a bad method in the second request.
+# Check that the relay handles the input after the error correctly.
+
+use strict;
+use warnings;
+
+my @lengths = (4, 3);
+our %args = (
+ client => {
+ func => sub {
+ my $self = shift;
+ print <<'EOF';
+PUT /4 HTTP/1.1
+Host: foo.bar
+Content-Length: 4
+
+123
+XXX
+PUT /3 HTTP/1.1
+Host: foo.bar
+Content-Length: 3
+
+12
+EOF
+ print STDERR "LEN: 4\n";
+ print STDERR "LEN: 3\n";
+ # relayd does not forward the first request if the second one
+ # is invalid. So do not expect any response.
+ #http_response($self, "without len");
+ },
+ http_vers => ["1.1"],
+ lengths => \@lengths,
+ method => "PUT",
+ },
+ relayd => {
+ protocol => [ "http",
+ "match request header log foo",
+ "match response header log bar",
+ ],
+ loggrep => {
+ qr/, malformed, PUT/ => 1,
+ },
+ },
+ server => {
+ func => \&http_server,
+ # The server does not get any connection.
+ noserver => 1,
+ nocheck => 1,
+ },
+ lengths => \@lengths,
+);
+
+1;
--- /dev/null
+# test chunked http connection over http relay invoking the callback
+# The client writes a bad chunk length in the second chunk.
+# Check that the relay handles the input after the error correctly.
+
+use strict;
+use warnings;
+
+my @lengths = ([4, 3]);
+our %args = (
+ client => {
+ func => sub {
+ my $self = shift;
+ print <<'EOF';
+PUT /4/3 HTTP/1.1
+Host: foo.bar
+Transfer-Encoding: chunked
+
+4
+123
+
+XXX
+3
+12
+
+0
+
+EOF
+ print STDERR "LEN: 4\n";
+ print STDERR "LEN: 3\n";
+ # relayd does not forward the first chunk if the second one
+ # is invalid. So do not expect any response.
+ #http_response($self, "without len");
+ },
+ http_vers => ["1.1"],
+ lengths => \@lengths,
+ method => "PUT",
+ },
+ relayd => {
+ protocol => [ "http",
+ "match request header log foo",
+ "match response header log bar",
+ ],
+ loggrep => {
+ qr/, invalid chunk size, PUT/ => 1,
+ },
+ },
+ server => {
+ func => \&http_server,
+ nocheck => 1,
+ },
+ lengths => \@lengths,
+);
+
+1;
--- /dev/null
+# test chunked http request over http relay
+
+use strict;
+use warnings;
+
+my @lengths = ([ 251, 10000, 10 ], 1, [2, 3]);
+our %args = (
+ client => {
+ func => \&http_client,
+ lengths => \@lengths,
+ http_vers => ["1.1"],
+ method => "PUT",
+ },
+ relayd => {
+ protocol => [ "http",
+ "match request header log Transfer-Encoding",
+ "match response header log bar",
+ ],
+ loggrep => {
+ qr/\[Transfer-Encoding: chunked\]/ => 1,
+ qr/\[\(null\)\]/ => 0,
+ },
+ },
+ server => {
+ func => \&http_server,
+ },
+ lengths => \@lengths,
+ md5 => [
+ "bc3a3f39af35fe5b1687903da2b00c7f",
+ "fccd8d69acceb0cc35f2fd4e2f6938d3",
+ "c47658d102d5b989e0da09ce403f7463",
+ "68b329da9893e34099c7d8ad5cb9c940",
+ "897316929176464ebc9ad085f31e7284",
+ "0ade138937c4b9cb36a28e2edb6485fc",
+ ],
+);
+
+1;
--- /dev/null
+# test persistent http connection over http relay invoking the callback
+# The client writes a bad header line in the second request.
+# Check that the relay handles the input after the error correctly.
+
+use strict;
+use warnings;
+
+my @lengths = (4, 3);
+our %args = (
+ client => {
+ func => sub {
+ my $self = shift;
+ print <<'EOF';
+PUT /4 HTTP/1.1
+Host: foo.bar
+Content-Length: 4
+
+123
+PUT /3 HTTP/1.1
+XXX
+Host: foo.bar
+Content-Length: 3
+
+12
+EOF
+ print STDERR "LEN: 4\n";
+ print STDERR "LEN: 3\n";
+ # relayd does not forward the first request if the second one
+ # is invalid. So do not expect any response.
+ #http_response($self, "without len");
+ },
+ http_vers => ["1.1"],
+ lengths => \@lengths,
+ method => "PUT",
+ },
+ relayd => {
+ protocol => [ "http",
+ "match request header log foo",
+ "match response header log bar",
+ ],
+ loggrep => {
+ qr/, malformed, PUT/ => 1,
+ },
+ },
+ server => {
+ func => \&http_server,
+ # The server does not get any connection.
+ noserver => 1,
+ nocheck => 1,
+ },
+ lengths => \@lengths,
+);
+
+1;
--- /dev/null
+# test https connection over http relay invoking the callback.
+# The client uses a bad method in the second request.
+# Check that the relay handles the input after the error correctly.
+
+use strict;
+use warnings;
+
+my @lengths = (4, 3);
+our %args = (
+ client => {
+ func => sub {
+ my $self = shift;
+ print <<'EOF';
+PUT /4 HTTP/1.1
+Host: foo.bar
+Content-Length: 4
+
+123
+XXX
+PUT /3 HTTP/1.1
+Host: foo.bar
+Content-Length: 3
+
+12
+EOF
+ print STDERR "LEN: 4\n";
+ print STDERR "LEN: 3\n";
+ # relayd does not forward the first request if the second one
+ # is invalid. So do not expect any response.
+ #http_response($self, "without len");
+ },
+ ssl => 1,
+ http_vers => ["1.1"],
+ lengths => \@lengths,
+ method => "PUT",
+ },
+ relayd => {
+ protocol => [ "http",
+ "match request header log foo",
+ "match response header log bar",
+ ],
+ forwardssl => 1,
+ listenssl => 1,
+ loggrep => {
+ qr/, malformed, PUT/ => 1,
+ },
+ },
+ server => {
+ func => \&http_server,
+ ssl => 1,
+ # The server does not get any connection.
+ noserver => 1,
+ nocheck => 1,
+ },
+ lengths => \@lengths,
+);
+
+1;
--- /dev/null
+# test chunked https connection over http relay invoking the callback
+# The client writes a bad chunk length in the second chunk.
+# Check that the relay handles the input after the error correctly.
+
+use strict;
+use warnings;
+
+my @lengths = ([4, 3]);
+our %args = (
+ client => {
+ func => sub {
+ my $self = shift;
+ print <<'EOF';
+PUT /4/3 HTTP/1.1
+Host: foo.bar
+Transfer-Encoding: chunked
+
+4
+123
+
+XXX
+3
+12
+
+0
+
+EOF
+ print STDERR "LEN: 4\n";
+ print STDERR "LEN: 3\n";
+ # relayd does not forward the first chunk if the second one
+ # is invalid. So do not expect any response.
+ #http_response($self, "without len");
+ },
+ ssl => 1,
+ http_vers => ["1.1"],
+ lengths => \@lengths,
+ method => "PUT",
+ },
+ relayd => {
+ protocol => [ "http",
+ "match request header log foo",
+ "match response header log bar",
+ ],
+ forwardssl => 1,
+ listenssl => 1,
+ loggrep => {
+ qr/, invalid chunk size, PUT/ => 1,
+ },
+ },
+ server => {
+ func => \&http_server,
+ # relayd only connects but does no ssl handshake
+ #ssl => 1,
+ nocheck => 1,
+ },
+ lengths => \@lengths,
+);
+
+1;
--- /dev/null
+# test chunked https request over http relay
+
+use strict;
+use warnings;
+
+my @lengths = ([ 251, 10000, 10 ], 1, [2, 3]);
+our %args = (
+ client => {
+ func => \&http_client,
+ ssl => 1,
+ lengths => \@lengths,
+ http_vers => ["1.1"],
+ method => "PUT",
+ },
+ relayd => {
+ protocol => [ "http",
+ "match request header log Transfer-Encoding",
+ "match response header log bar",
+ ],
+ forwardssl => 1,
+ listenssl => 1,
+ loggrep => {
+ qr/\[Transfer-Encoding: chunked\]/ => 1,
+ qr/\[\(null\)\]/ => 0,
+ },
+ },
+ server => {
+ func => \&http_server,
+ ssl => 1,
+ },
+ lengths => \@lengths,
+ md5 => [
+ "bc3a3f39af35fe5b1687903da2b00c7f",
+ "fccd8d69acceb0cc35f2fd4e2f6938d3",
+ "c47658d102d5b989e0da09ce403f7463",
+ "68b329da9893e34099c7d8ad5cb9c940",
+ "897316929176464ebc9ad085f31e7284",
+ "0ade138937c4b9cb36a28e2edb6485fc",
+ ],
+);
+
+1;
--- /dev/null
+# test persistent https connection over http relay invoking the callback
+# The client writes a bad header line in the second request.
+# Check that the relay handles the input after the error correctly.
+
+use strict;
+use warnings;
+
+my @lengths = (4, 3);
+our %args = (
+ client => {
+ func => sub {
+ my $self = shift;
+ print <<'EOF';
+PUT /4 HTTP/1.1
+Host: foo.bar
+Content-Length: 4
+
+123
+PUT /3 HTTP/1.1
+XXX
+Host: foo.bar
+Content-Length: 3
+
+12
+EOF
+ print STDERR "LEN: 4\n";
+ print STDERR "LEN: 3\n";
+ # relayd does not forward the first request if the second one
+ # is invalid. So do not expect any response.
+ #http_response($self, "without len");
+ },
+ ssl => 1,
+ http_vers => ["1.1"],
+ lengths => \@lengths,
+ method => "PUT",
+ },
+ relayd => {
+ protocol => [ "http",
+ "match request header log foo",
+ "match response header log bar",
+ ],
+ forwardssl => 1,
+ listenssl => 1,
+ loggrep => {
+ qr/, malformed, PUT/ => 1,
+ },
+ },
+ server => {
+ func => \&http_server,
+ ssl => 1,
+ # The server does not get any connection.
+ noserver => 1,
+ nocheck => 1,
+ },
+ lengths => \@lengths,
+);
+
+1;
-# $OpenBSD: funcs.pl,v 1.18 2015/01/05 22:41:37 bluhm Exp $
+# $OpenBSD: funcs.pl,v 1.19 2015/05/17 22:49:03 bluhm Exp $
-# Copyright (c) 2010-2014 Alexander Bluhm <bluhm@openbsd.org>
+# Copyright (c) 2010-2015 Alexander Bluhm <bluhm@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
my $len = shift // $self->{len} // 251;
my $cookie = $self->{cookie};
http_request($self, $len, "1.0", $cookie);
+ http_response($self, $len);
return;
}
my @cookies = @{$self->{redo}{cookies} || $self->{cookies} || []};
while (defined (my $len = shift @lengths)) {
my $cookie = shift @cookies || $self->{cookie};
- eval { http_request($self, $len, $vers, $cookie) };
+ eval {
+ http_request($self, $len, $vers, $cookie);
+ http_response($self, $len);
+ };
warn $@ if $@;
if (@lengths && ($@ || $vers eq "1.0")) {
# reconnect and redo the outstanding requests
}
my @request = ("$method /$path HTTP/$vers");
push @request, "Host: foo.bar" unless defined $header{Host};
- push @request, "Content-Length: $len"
- if $vers eq "1.1" && $method eq "PUT" &&
- !defined $header{'Content-Length'};
+ if ($vers eq "1.1" && $method eq "PUT") {
+ if (ref($len) eq 'ARRAY') {
+ push @request, "Transfer-Encoding: chunked"
+ if !defined $header{'Transfer-Encoding'};
+ } else {
+ push @request, "Content-Length: $len"
+ if !defined $header{'Content-Length'};
+ }
+ }
foreach my $key (sort keys %header) {
my $val = $header{$key};
if (ref($val) eq 'ARRAY') {
push @request, "";
print STDERR map { ">>> $_\n" } @request;
print map { "$_\r\n" } @request;
- write_char($self, $len) if $method eq "PUT";
+ if ($method eq "PUT") {
+ if (ref($len) eq 'ARRAY') {
+ if ($vers eq "1.1") {
+ write_chunked($self, @$len);
+ } else {
+ write_char($self, $_) foreach (@$len);
+ }
+ } else {
+ write_char($self, $len);
+ }
+ }
IO::Handle::flush(\*STDOUT);
# XXX client shutdown seems to be broken in relayd
#shutdown(\*STDOUT, SHUT_WR)
# or die ref($self), " shutdown write failed: $!"
# if $vers ne "1.1";
+}
+sub http_response {
+ my ($self, $len) = @_;
+ my $method = $self->{method} || "GET";
+
+ my $vers;
my $chunked = 0;
{
local $/ = "\r\n";
or die ref($self), " missing http $len response";
chomp;
print STDERR "<<< $_\n";
- m{^HTTP/$vers 200 OK$}
+ m{^HTTP/(\d\.\d) 200 OK$}
or die ref($self), " http response not ok"
unless $self->{httpnok};
+ $vers = $1;
while (<STDIN>) {
chomp;
print STDERR "<<< $_\n";
$cookie ||= $1 if /^Cookie: (.*)/;
}
}
- # XXX reading to EOF does not work with relayd
- #read_char($self, $vers eq "1.1" ? $len : undef)
- read_char($self, $len)
- if $method eq "PUT";
+ if ($method eq "PUT" ) {
+ if (ref($len) eq 'ARRAY') {
+ read_chunked($self);
+ } else {
+ read_char($self, $len);
+ }
+ }
my @response = ("HTTP/$vers 200 OK");
$len = defined($len) ? $len : scalar(split /|/,$url);
- if (ref($len) eq 'ARRAY') {
- push @response, "Transfer-Encoding: chunked"
- if $vers eq "1.1";
- } else {
- push @response, "Content-Length: $len"
- if $vers eq "1.1" && $method eq "GET";
+ if ($vers eq "1.1" && $method eq "GET") {
+ if (ref($len) eq 'ARRAY') {
+ push @response, "Transfer-Encoding: chunked";
+ } else {
+ push @response, "Content-Length: $len";
+ }
}
foreach my $key (sort keys %header) {
my $val = $header{$key};
print STDERR map { ">>> $_\n" } @response;
print map { "$_\r\n" } @response;
- if (ref($len) eq 'ARRAY') {
- if ($vers eq "1.1") {
- write_chunked($self, @$len);
+ if ($method eq "GET") {
+ if (ref($len) eq 'ARRAY') {
+ if ($vers eq "1.1") {
+ write_chunked($self, @$len);
+ } else {
+ write_char($self, $_) foreach (@$len);
+ }
} else {
- write_char($self, $_) foreach (@$len);
+ write_char($self, $len);
}
- } else {
- write_char($self, $len) if $method eq "GET";
}
IO::Handle::flush(\*STDOUT);
} while ($vers eq "1.1");
check_len($c, $r, $s, %args);
check_md5($c, $r, $s, %args);
check_loggrep($c, $r, $s, %args);
+ $r->loggrep("lost child")
+ and die "relayd lost child";
}
sub check_len {