1package Plack::Handler::AnyEvent::ReverseHTTP;
2use strict;
3use 5.008_001;
4our $VERSION = '0.04';
5
6use AnyEvent::ReverseHTTP;
7use HTTP::Message::PSGI;
8use HTTP::Response;
9use Plack::Util;
10
11sub new {
12    my($class, %args) = @_;
13    bless \%args, $class;
14}
15
16sub register_service {
17    my($self, $app) = @_;
18    $self->{guard} = reverse_http $self->{host}, $self->{token}, sub {
19        my $req = shift;
20        my $env = $req->to_psgi;
21
22        if (my $client = delete $env->{HTTP_REQUESTING_CLIENT}) {
23            @{$env}{qw( REMOTE_ADDR REMOTE_PORT )} = split /:/, $client, 2;
24        }
25
26        $env->{'psgi.nonblocking'}  = Plack::Util::TRUE;
27        $env->{'psgi.streaming'}    = Plack::Util::TRUE;
28        $env->{'psgi.multithread'}  = Plack::Util::FALSE;
29        $env->{'psgi.multiprocess'} = Plack::Util::FALSE;
30        $env->{'psgi.run_once'}     = Plack::Util::FALSE;
31
32        my $r = $app->($env);
33        if (ref $r eq 'ARRAY') {
34            return HTTP::Response->from_psgi($r);
35        } elsif (ref $r eq 'CODE') {
36            my $cv = AE::cv;
37            $r->(sub {
38                my $r = shift;
39
40                if (defined $r->[2]) {
41                    my $res = HTTP::Response->from_psgi($r);
42                    $cv->send($res);
43                } else {
44                    my $res = HTTP::Response->from_psgi([ $r->[0], $r->[1], [] ]); # dummy
45                    my @body;
46                    return Plack::Util::inline_object
47                        write => sub { push @body, $_[0] },
48                        close => sub { $res->content(join '', @body); $cv->send($res) };
49                }
50            });
51            return $cv;
52        } else {
53            die "Bad response: $r";
54        }
55    };
56}
57
58sub run {
59    my $self = shift;
60    $self->register_service(@_);
61    AE::cv->recv;
62}
63
641;
65
66__END__
67
68=head1 NAME
69
70Plack::Handler::AnyEvent::ReverseHTTP - reversehttp gateway for PSGI application
71
72=head1 SYNOPSIS
73
74  > plackup --server AnyEvent::ReverseHTTP --host rhttplabel --token your-token
75
76=head1 DESCRIPTION
77
78Plack::Handler::AnyEvent::ReverseHTTP is Plack handler that runs your
79PSGI application on L<AnyEvent::ReverseHTTP>. It uses ReverseHTTP
80gateway to access your PSGI application on your desktop or behind the
81firewall from the internet. Just like Ruby's hookout does with Rack
82applications.
83
84=head1 AUTHOR
85
86Tatsuhiko Miyagawa E<lt>miyagawa@bulknews.netE<gt>
87
88=head1 LICENSE
89
90This module is licensed under the same terms as Perl itself.
91
92=head1 SEE ALSO
93
94L<AnyEvent::ReverseHTTP> L<http://github.com/paulj/hookout/tree/master> L<http://www.reversehttp.net/>
95
96=cut
97