+# 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]);
+
+ # use $self->write("\n\n") if you care about real-time
+ # streaming responses, public-inbox WWW does not.
+ more($self, "\r\n");
+ }
+}
+
+sub identity_wcb ($) {
+ my ($self) = @_;
+ sub { $self->write(\($_[0])) if $_[0] ne '' }
+}
+
+sub next_request ($) {
+ my ($self) = @_;
+ $self->watch_write(0);
+ if ($self->{rbuf} eq '') { # wait for next request
+ $self->watch_read(1);
+ } else { # avoid recursion for pipelined requests
+ push @$pipelineq, $self;
+ $pipet ||= PublicInbox::EvCleanup::asap(*process_pipelineq);
+ }
+}
+
+sub response_done ($$) {
+ my ($self, $alive) = @_;
+ my $env = $self->{env};
+ $self->{env} = undef;
+ $self->write("0\r\n\r\n") if $alive == 2;
+ $self->write(sub { $alive ? next_request($self) : $self->close });
+
+ # FIXME: layering violation
+ if (my $obj = $env->{'pi-httpd.inbox'}) {
+ # grace period for reaping resources
+ $WEAKEN->{"$obj"} = $obj;
+ PublicInbox::EvCleanup::later(*weaken_task);
+ }
+}
+
+sub getline_response {
+ my ($self, $body, $write, $close) = @_;
+ $self->{forward} = $body;
+ weaken($self);
+ my $pull = $self->{pull} = sub {
+ local $/ = \8192;
+ my $forward = $self->{forward};
+ # limit our own running time for fairness with other
+ # clients and to avoid buffering too much:
+ while ($forward && defined(my $buf = $forward->getline)) {
+ $write->($buf);
+ last if $self->{closed};
+ if ($self->{write_buf_size}) {
+ $self->write($self->{pull});
+ } else {
+ PublicInbox::EvCleanup::asap($self->{pull});
+ }
+ return;
+ }
+ $self->{forward} = $self->{pull} = undef;
+ $forward->close if $forward; # avoid recursion
+ $close->();
+ };
+ $pull->();
+}
+