-sub event_read { $_[0]->{cb}->() }
-sub event_hup { $_[0]->{cb}->() }
-sub event_err { $_[0]->{cb}->() }
-sub sysread { shift->{sock}->sysread(@_) }
+sub main_cb ($$) {
+ my ($http, $fh) = @_;
+ sub {
+ my ($self) = @_;
+ my $r = sysread($self->{sock}, my $buf, 65536);
+ if ($r) {
+ $fh->write($buf); # may call $http->close
+ if ($http->{sock}) { # !closed
+ $self->requeue;
+ # let other clients get some work done, too
+ return;
+ }
+
+ # else: fall through to close below...
+ } elsif (!defined $r && $! == EAGAIN) {
+ return; # EPOLLET means we'll be notified
+ }
+
+ # Done! Error handling will happen in $fh->close
+ # called by the {cleanup} handler
+ delete $http->{forward};
+ $self->close;
+ }
+}
+
+sub async_pass {
+ my ($self, $http, $fh, $bref) = @_;
+ # In case the client HTTP connection ($http) dies, it
+ # will automatically close this ($self) object.
+ $http->{forward} = $self;
+ $fh->write($$bref); # PublicInbox:HTTP::{chunked,identity}_wcb
+ $$bref = undef; # we're done with this
+ my $cb = $self->{cb} = main_cb($http, $fh);
+ $cb->($self); # either hit EAGAIN or ->requeue to keep EPOLLET happy
+}
+
+sub event_step {
+ # {cb} may be undef after ->requeue due to $http->close happening
+ my $cb = $_[0]->{cb} or return;
+ $cb->(@_);
+}