about summary refs log tree commit homepage
path: root/lib
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2016-05-21 03:03:16 +0000
committerEric Wong <e@80x24.org>2016-05-21 03:06:06 +0000
commit21cea5b3a662e66e69064456a1fec348f0834f64 (patch)
treef1b1f199870898e3ebbff7e0d56fb2058a5ea9cd /lib
parentfcfef9420b639214b325dd17f8a7ae151c21f627 (diff)
downloadpublic-inbox-21cea5b3a662e66e69064456a1fec348f0834f64.tar.gz
By switching to a "pull"-based I/O model for reading
application responses, we should be able to throttle
buffering to slow clients more effectively and avoid
wasting precious RAM.

This will also allow us to more Danga::Socket-specific
knowledge out of the PSGI application and keep it
confined to PublicInbox::HTTP.
Diffstat (limited to 'lib')
-rw-r--r--lib/PublicInbox/HTTP.pm26
1 files changed, 22 insertions, 4 deletions
diff --git a/lib/PublicInbox/HTTP.pm b/lib/PublicInbox/HTTP.pm
index 1ef3fb31..f69056f8 100644
--- a/lib/PublicInbox/HTTP.pm
+++ b/lib/PublicInbox/HTTP.pm
@@ -205,7 +205,7 @@ sub response_write {
                 if ($alive) {
                         $self->event_write; # watch for readability if done
                 } else {
-                        $self->write(sub { $self->close });
+                        Danga::Socket::write($self, sub { $self->close });
                 }
                 if (my $obj = $env->{'pi-httpd.inbox'}) {
                         # grace period for reaping resources
@@ -215,9 +215,27 @@ sub response_write {
                 $self->{env} = undef;
         };
 
-        if (defined $res->[2]) {
-                Plack::Util::foreach($res->[2], $write);
-                $close->();
+        if (defined(my $body = $res->[2])) {
+                if (ref $body eq 'ARRAY') {
+                        $write->($_) foreach @$body;
+                        $close->();
+                } else {
+                        my $pull;
+                        $pull = sub {
+                                local $/ = \8192;
+                                while (defined(my $buf = $body->getline)) {
+                                        $write->($buf);
+                                        if ($self->{write_buf}) {
+                                                $self->write($pull);
+                                                return;
+                                        }
+                                }
+                                $pull = undef;
+                                $body->close();
+                                $close->();
+                        };
+                        $pull->();
+                }
         } else {
                 # this is returned to the calling application:
                 Plack::Util::inline_object(write => $write, close => $close);