examples/public-inbox.psgi | 5 ----- lib/PublicInbox/HTTP.pm | 39 +++++++++++++++++++++++++++++++-------- script/public-inbox-httpd | 1 - t/git-http-backend.psgi | 1 - diff --git a/examples/public-inbox.psgi b/examples/public-inbox.psgi index 876fc76226d651d60dbe2901f89332fabcfd0f06..4edbf5e369914f3f12334b5aa4afa5f14f5bce4a 100644 --- a/examples/public-inbox.psgi +++ b/examples/public-inbox.psgi @@ -12,11 +12,6 @@ PublicInbox::WWW->preload; use Plack::Builder; my $www = PublicInbox::WWW->new; builder { - # Chunked middleware conflicts with Starman: - # https://github.com/miyagawa/Starman/issues/23 - # However, it is strongly recommended to enable it if using - # public-inbox-httpd to allow persistent connections - # enable 'Chunked'; eval { enable 'Deflater', content_type => [ qw( diff --git a/lib/PublicInbox/HTTP.pm b/lib/PublicInbox/HTTP.pm index 480800bd90b00c51a747bf4cd3a0ff1957ab4f7e..77b178c07e6fea56cfe47c9b95a7358499f91088 100644 --- a/lib/PublicInbox/HTTP.pm +++ b/lib/PublicInbox/HTTP.pm @@ -180,12 +180,19 @@ } my $conn = $env->{HTTP_CONNECTION} || ''; my $term = defined($len) || $chunked; - my $alive = $term && - (($proto eq 'HTTP/1.1' && $conn !~ /\bclose\b/i) || - ($conn =~ /\bkeep-alive\b/i)); - - $h .= 'Connection: ' . ($alive ? 'keep-alive' : 'close'); - $h .= "\r\nDate: " . http_date() . "\r\n\r\n"; + my $prot_persist = ($proto eq 'HTTP/1.1') && ($conn !~ /\bclose\b/i); + my $alive; + if (!$term && $prot_persist) { # auto-chunk + $chunked = $alive = 2; + $h .= "Transfer-Encoding: chunked\r\n"; + # no need for "Connection: keep-alive" with HTTP/1.1 + } elsif ($term && ($prot_persist || ($conn =~ /\bkeep-alive\b/i))) { + $alive = 1; + $h .= "Connection: keep-alive\r\n"; + } else { + $h .= "Connection: close\r\n"; + } + $h .= 'Date: ' . http_date() . "\r\n\r\n"; if (($len || $chunked) && $env->{REQUEST_METHOD} ne 'HEAD') { more($self, $h); @@ -195,13 +202,29 @@ } $alive; } +# middlewares such as Deflater may write empty strings +sub chunked_wcb ($) { + my ($self) = @_; + sub { + return if $_[0] eq ''; + more($self, sprintf("%x\r\n", bytes::length($_[0]))); + more($self, $_[0]); + $self->write("\r\n"); + } +} + +sub identity_wcb ($) { + my ($self) = @_; + sub { $self->write(\($_[0])) if $_[0] ne '' } +} + sub response_write { my ($self, $env, $res) = @_; my $alive = response_header_write($self, $env, $res); - # middlewares such as Deflater may write empty strings - my $write = sub { $self->write(\($_[0])) if $_[0] ne '' }; + my $write = $alive == 2 ? chunked_wcb($self) : identity_wcb($self); my $close = sub { + $self->write("0\r\n\r\n") if $alive == 2; if ($alive) { $self->event_write; # watch for readability if done } else { diff --git a/script/public-inbox-httpd b/script/public-inbox-httpd index b29effcccb4ff25c3966de527b271e92253cbaa3..f19582fafc600ccea7730ed98f45533ff8381ad6 100755 --- a/script/public-inbox-httpd +++ b/script/public-inbox-httpd @@ -25,7 +25,6 @@ require PublicInbox::WWW; PublicInbox::WWW->preload; my $www = PublicInbox::WWW->new; $app = builder { - enable 'Chunked'; eval { enable 'Deflater', content_type => [ qw( diff --git a/t/git-http-backend.psgi b/t/git-http-backend.psgi index 8cec7d35365b69ac1fd42fedbd585c92df0e39e3..c9607143e636a70a298e6072f5414912b496969a 100644 --- a/t/git-http-backend.psgi +++ b/t/git-http-backend.psgi @@ -11,7 +11,6 @@ use BSD::Resource qw(getrusage); my $git_dir = $ENV{GIANT_GIT_DIR} or die 'GIANT_GIT_DIR not defined in env'; my $git = PublicInbox::Git->new($git_dir); builder { - enable 'Chunked' if $ENV{TEST_CHUNK}; enable 'Head'; sub { my ($env) = @_;