summaryrefslogtreecommitdiffstats
path: root/web/server/h2o/libh2o/t/50mruby-http-request.t
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--web/server/h2o/libh2o/t/50mruby-http-request.t269
1 files changed, 269 insertions, 0 deletions
diff --git a/web/server/h2o/libh2o/t/50mruby-http-request.t b/web/server/h2o/libh2o/t/50mruby-http-request.t
new file mode 100644
index 00000000..991d34ba
--- /dev/null
+++ b/web/server/h2o/libh2o/t/50mruby-http-request.t
@@ -0,0 +1,269 @@
+use strict;
+use warnings;
+use Digest::MD5 qw(md5_hex);
+use Net::EmptyPort qw(empty_port check_port);
+use Test::More;
+use t::Util;
+
+plan skip_all => 'mruby support is off'
+ unless server_features()->{mruby};
+
+plan skip_all => 'curl not found'
+ unless prog_exists('curl');
+
+plan skip_all => 'plackup not found'
+ unless prog_exists('plackup');
+
+plan skip_all => 'Starlet not found'
+ unless system('perl -MStarlet /dev/null > /dev/null 2>&1') == 0;
+
+my $upstream_hostport = "127.0.0.1:@{[empty_port()]}";
+
+sub create_upstream {
+ my @args = (
+ qw(plackup -s Starlet --keepalive-timeout 100 --access-log /dev/null --listen),
+ $upstream_hostport,
+ ASSETS_DIR . "/upstream.psgi",
+ );
+ spawn_server(
+ argv => \@args,
+ is_ready => sub {
+ $upstream_hostport =~ /:([0-9]+)$/s
+ or die "failed to extract port number";
+ check_port($1);
+ },
+ );
+};
+
+my $server = spawn_h2o(sub {
+ my ($port, $tls_port) = @_;
+ return << "EOT";
+proxy.timeout.io: 1000
+hosts:
+ default:
+ paths:
+ /:
+ mruby.handler: |
+ Proc.new do |env|
+ headers = {}
+ env.each do |key, value|
+ if /^HTTP_/.match(key)
+ headers[\$'] = value
+ end
+ end
+ headers["x-h2o-mruby"] = "1"
+ http_request("http://$upstream_hostport#{env["PATH_INFO"]}#{env["QUERY_STRING"]}", {
+ method: env["REQUEST_METHOD"],
+ headers: headers,
+ body: env["rack.input"],
+ }).join
+ end
+ /as_str:
+ mruby.handler: |
+ Proc.new do |env|
+ [200, {}, [http_request("http://$upstream_hostport/index.txt").join[2].join]]
+ end
+ /cl:
+ mruby.handler: |
+ Proc.new do |env|
+ if !/^\\/([0-9]+)/.match(env["PATH_INFO"])
+ raise "failed to parse PATH_INFO"
+ end
+ cl = \$1
+ body = ["abc", "def", "ghi", "jkl", "mno"]
+ if \$'.length != 0
+ class T
+ def initialize(a)
+ \@a = a
+ end
+ def each(&b)
+ \@a.each(&b)
+ end
+ end
+ body = T.new(body)
+ end
+ [200, {"content-length" => cl}, body]
+ end
+ /esi:
+ mruby.handler: |
+ class ESIResponse
+ def initialize(input)
+ \@parts = input.split /(<esi:include +src=".*?" *\\/>)/
+ \@parts.each_with_index do |part, index|
+ if /^<esi:include +src=" *(.*?) *"/.match(part)
+ \@parts[index] = http_request("http://$upstream_hostport/#{\$1}")
+ end
+ end
+ end
+ def each(&block)
+ \@parts.each do |part|
+ if part.kind_of? String
+ block.call(part)
+ else
+ part.join[2].each(&block)
+ end
+ end
+ end
+ end
+ Proc.new do |env|
+ resp = http_request("http://$upstream_hostport/esi.html").join
+ resp[2] = ESIResponse.new(resp[2].join)
+ resp
+ end
+ /fast-path-partial:
+ mruby.handler: |
+ Proc.new do |env|
+ resp = http_request("http://$upstream_hostport/streaming-body").join
+ resp[2].each do |x|
+ break
+ end
+ resp
+ end
+ /async-delegate:
+ mruby.handler: |
+ Proc.new do |env|
+ resp = http_request("http://$upstream_hostport#{env["PATH_INFO"]}").join
+ if resp[0] != 200
+ resp = [399, {}, []]
+ end
+ resp
+ end
+ mruby.handler: |
+ Proc.new do |env|
+ [200, {}, ["delegated!"]]
+ end
+EOT
+});
+
+run_with_curl($server, sub {
+ my ($proto, $port, $curl_cmd) = @_;
+ $curl_cmd .= ' --silent --dump-header /dev/stderr';
+ subtest "connection-error" => sub {
+ my ($headers, $body) = run_prog("$curl_cmd $proto://127.0.0.1:$port/index.txt");
+ like $headers, qr{HTTP/[^ ]+ 500\s}is;
+ };
+ my $upstream = create_upstream();
+ subtest "get" => sub {
+ my ($headers, $body) = run_prog("$curl_cmd $proto://127.0.0.1:$port/index.txt");
+ like $headers, qr{HTTP/[^ ]+ 200\s}is;
+ is $body, "hello\n";
+ };
+ subtest "headers" => sub {
+ my ($headers, $body) = run_prog("$curl_cmd $proto://127.0.0.1:$port/echo-headers");
+ like $headers, qr{^HTTP/[^ ]+ 200\s}is;
+ like $body, qr{^host: $upstream_hostport$}im;
+ unlike $body, qr{^host: 127.0.0.1:$port$}im;
+ like $body, qr{^user-agent: *curl/}im;
+ like $body, qr{^accept: *\*/\*$}im;
+ like $body, qr{^x-h2o-mruby:}im;
+ };
+ subtest "post" => sub {
+ my ($headers, $body) = run_prog("$curl_cmd --data 'hello world' $proto://127.0.0.1:$port/echo");
+ like $headers, qr{HTTP/[^ ]+ 200\s}is;
+ is $body, 'hello world';
+ };
+ subtest "slow-chunked" => sub {
+ my ($headers, $body) = run_prog("$curl_cmd $proto://127.0.0.1:$port/streaming-body");
+ like $headers, qr{HTTP/[^ ]+ 200\s}is;
+ is $body, (join "", 1..30);
+ };
+ subtest "as_str" => sub {
+ my ($headers, $body) = run_prog("$curl_cmd $proto://127.0.0.1:$port/as_str/");
+ like $headers, qr{HTTP/[^ ]+ 200\s}is;
+ is $body, "hello\n";
+ };
+ subtest "content-length" => sub {
+ subtest "non-chunked" => sub {
+ for my $i (0..15) {
+ subtest "cl=$i" => sub {
+ my ($headers, $body) = run_prog("$curl_cmd $proto://127.0.0.1:$port/cl/$i");
+ like $headers, qr{^HTTP/[^ ]+ 200\s.*\ncontent-length:\s*$i\r}is;
+ is $body, substr "abcdefghijklmno", 0, $i;
+ }
+ };
+ for my $i (16..30) {
+ subtest "cl=$i" => sub {
+ my ($headers, $body) = run_prog("$curl_cmd $proto://127.0.0.1:$port/cl/$i");
+ like $headers, qr{^HTTP/[^ ]+ 200\s.*\ncontent-length:\s*15\r}is;
+ is $body, "abcdefghijklmno";
+ }
+ };
+ };
+ subtest "chunked" => sub {
+ for my $i (0..30) {
+ subtest "cl=$i" => sub {
+ my ($headers, $body) = run_prog("$curl_cmd $proto://127.0.0.1:$port/cl/$i/chunked");
+ like $headers, qr{^HTTP/[^ ]+ 200\s.*\ncontent-length:\s*$i\r}is;
+ is $body, substr "abcdefghijklmno", 0, $i;
+ }
+ };
+ };
+ };
+ subtest "esi" => sub {
+ my ($headers, $body) = run_prog("$curl_cmd $proto://127.0.0.1:$port/esi/");
+ like $headers, qr{HTTP/[^ ]+ 200\s}is;
+ is $body, "Hello to the world, from H2O!\n";
+ };
+ subtest "fast-path-partial" => sub {
+ my ($headers, $body) = run_prog("$curl_cmd $proto://127.0.0.1:$port/fast-path-partial/");
+ like $headers, qr{HTTP/[^ ]+ 200\s}is;
+ is $body, join "", 2..30;
+ };
+ subtest "async-delegate" => sub {
+ subtest "non-delegated" => sub {
+ my ($headers, $body) = run_prog("$curl_cmd $proto://127.0.0.1:$port/async-delegate/index.txt");
+ like $headers, qr{HTTP/[^ ]+ 200\s}is;
+ is $body, "hello\n";
+ };
+ subtest "delegated" => sub {
+ my ($headers, $body) = run_prog("$curl_cmd $proto://127.0.0.1:$port/async-delegate/notfound");
+ like $headers, qr{HTTP/[^ ]+ 200\s}is;
+ is $body, "delegated!";
+ };
+ };
+});
+
+subtest 'empty body' => sub {
+ my $upstream = create_upstream();
+ my $server = spawn_h2o(sub {
+ my ($port, $tls_port) = @_;
+ return << "EOT";
+hosts:
+ default:
+ paths:
+ /no-content:
+ mruby.handler: |
+ proc {|env|
+ resp = http_request("http://$upstream_hostport/no-content").join
+ resp[2] = [resp[2].join]
+ resp
+ }
+ /head:
+ mruby.handler: |
+ proc {|env|
+ resp = http_request("http://$upstream_hostport/index.txt", { :method => 'HEAD' }).join
+ resp[2] = [resp[2].join]
+ resp
+ }
+EOT
+ });
+
+ run_with_curl($server, sub {
+ my ($proto, $port, $curl_cmd) = @_;
+ $curl_cmd .= ' --silent --dump-header /dev/stderr';
+
+ subtest "no content" => sub {
+ my ($headers, $body) = run_prog("$curl_cmd -m 1 $proto://127.0.0.1:$port/no-content");
+ like $headers, qr{HTTP/[^ ]+ 204\s}is;
+ is $body, "";
+ };
+
+ subtest "head" => sub {
+ my ($headers, $body) = run_prog("$curl_cmd -m 1 $proto://127.0.0.1:$port/head");
+ like $headers, qr{HTTP/[^ ]+ 200\s}is;
+ is $body, "";
+ };
+ });
+};
+
+done_testing();