From 58daab21cd043e1dc37024a7f99b396788372918 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 9 Mar 2024 14:19:48 +0100 Subject: Merging upstream version 1.44.3. Signed-off-by: Daniel Baumann --- web/server/h2o/libh2o/t/50mruby-http-request.t | 269 +++++++++++++++++++++++++ 1 file changed, 269 insertions(+) create mode 100644 web/server/h2o/libh2o/t/50mruby-http-request.t (limited to 'web/server/h2o/libh2o/t/50mruby-http-request.t') 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 000000000..991d34ba0 --- /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 /()/ + \@parts.each_with_index do |part, index| + if /^ 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(); -- cgit v1.2.3