Improved H::Daemon
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Engine / HTTP / Daemon.pm
CommitLineData
2cdfbf5e 1package Catalyst::Engine::HTTP::Daemon;
2
3use strict;
4use base 'Catalyst::Engine::HTTP::Base';
5
8a0ec4fd 6use IO::Select;
2cdfbf5e 7
8=head1 NAME
9
10Catalyst::Engine::HTTP::Daemon - Catalyst HTTP Daemon Engine
11
12=head1 SYNOPSIS
13
14A script using the Catalyst::Engine::HTTP::Daemon module might look like:
15
16 #!/usr/bin/perl -w
17
18 BEGIN { $ENV{CATALYST_ENGINE} = 'HTTP::Daemon' }
19
20 use strict;
21 use lib '/path/to/MyApp/lib';
22 use MyApp;
23
24 MyApp->run;
25
26=head1 DESCRIPTION
27
28This is the Catalyst engine specialized for development and testing.
29
30=head1 OVERLOADED METHODS
31
32This class overloads some methods from C<Catalyst::Engine::HTTP::Base>.
33
34=over 4
35
bce14c0d 36=item $c->handler
2cdfbf5e 37
38=cut
39
bce14c0d 40sub handler {
8a0ec4fd 41 my ( $class, $request, $response, $client ) = @_;
bce14c0d 42
8a0ec4fd 43 $request->uri->scheme('http'); # Force URI::http
44 $request->uri->host( $request->header('Host') || $client->sockhost );
45 $request->uri->port( $client->sockport );
bce14c0d 46
8a0ec4fd 47 my $http = Catalyst::Engine::HTTP::Base::struct->new(
48 address => $client->peerhost,
49 request => $request,
50 response => $response
51 );
bce14c0d 52
8a0ec4fd 53 $class->SUPER::handler($http);
bce14c0d 54}
55
56=item $c->run
57
58=cut
2cdfbf5e 59
60sub run {
61 my $class = shift;
62 my $port = shift || 3000;
8a0ec4fd 63
bce14c0d 64 $SIG{'PIPE'} = 'IGNORE';
2cdfbf5e 65
296e7663 66 my $daemon = Catalyst::Engine::HTTP::Daemon::Catalyst->new(
8a0ec4fd 67 Listen => 1,
2cdfbf5e 68 LocalPort => $port,
69 ReuseAddr => 1,
8a0ec4fd 70 Timeout => 5
2cdfbf5e 71 );
8a0ec4fd 72
b4ca0ee8 73 unless ( defined $daemon ) {
8a0ec4fd 74 die(qq/Failed to create daemon. Reason: '$!'/);
b4ca0ee8 75 }
2cdfbf5e 76
2cdfbf5e 77 my $base = URI->new( $daemon->url )->canonical;
78
79 printf( "You can connect to your server at %s\n", $base );
80
8a0ec4fd 81 my $select = IO::Select->new($daemon);
82
83 while (1) {
84
abdcb6e4 85 for my $client ( $select->can_read(0.1) ) {
8a0ec4fd 86
87 if ( $client == $daemon ) {
88 $client = $daemon->accept;
89 $client->blocking(0);
90 $select->add($client);
91 }
92
93 else {
94 next if $client->request;
95 next if $client->response;
96
97 my $read = $client->sysread( my $buf, 4096 );
abdcb6e4 98
8a0ec4fd 99 unless ( defined($read) && length($buf) ) {
abdcb6e4 100
8a0ec4fd 101 $select->remove($client);
102 $client->close;
103
104 next;
105 }
106
abdcb6e4 107 $client->request_buffer .= $buf;
108 $client->request = $client->get_request;
8a0ec4fd 109 }
110 }
111
112 for my $client ( $select->handles ) {
113
114 next if $client == $daemon;
115 next if $client->response;
116 next unless $client->request;
117
abdcb6e4 118 $client->response = HTTP::Response->new;
119 $client->response->protocol( $client->request->protocol );
120 $class->handler( $client->request, $client->response, $client );
8a0ec4fd 121 }
122
123 for my $client ( $select->can_write(0) ) {
124
125 next unless $client->response;
126
abdcb6e4 127 unless ( $client->response_buffer ) {
128 $client->response_buffer = $client->response->as_string;
129 $client->response_offset = 0;
130 }
131
132 my $write = $client->syswrite( $client->response_buffer,
133 $client->response_length,
134 $client->response_offset );
8a0ec4fd 135
abdcb6e4 136 $client->response_offset += $write;
137
138 unless ( defined($write) ) {
8a0ec4fd 139
8a0ec4fd 140 $select->remove($client);
141 $client->close;
abdcb6e4 142
143 next;
8a0ec4fd 144 }
145
abdcb6e4 146 if ( $client->response_offset == $client->response_length ) {
147
148 my $connection = $client->request->header('Connection');
149
150 unless ( $connection && $connection =~ /Keep-Alive/i ) {
151 $select->remove($client);
152 $client->close;
153 }
154
155 $client->response = undef;
156 $client->request = undef;
157 $client->response_buffer = undef;
158 }
8a0ec4fd 159 }
2cdfbf5e 160 }
161}
162
163=back
164
165=head1 SEE ALSO
166
8a0ec4fd 167L<Catalyst>, L<Catalyst::Engine>, L<Catalyst::Engine::HTTP::Base>,
2cdfbf5e 168L<HTTP::Daemon>.
169
170=head1 AUTHOR
171
172Sebastian Riedel, C<sri@cpan.org>
173Christian Hansen, C<ch@ngmedia.com>
174
175=head1 COPYRIGHT
176
177This program is free software, you can redistribute it and/or modify it under
178the same terms as Perl itself.
179
180=cut
181
296e7663 182package Catalyst::Engine::HTTP::Daemon::Catalyst;
2cdfbf5e 183
184use strict;
185use base 'HTTP::Daemon';
186
8a0ec4fd 187sub accept {
188 return shift->SUPER::accept('Catalyst::Engine::HTTP::Daemon::Client');
189}
190
2cdfbf5e 191sub product_tokens {
8a0ec4fd 192 return "Catalyst/$Catalyst::VERSION";
193}
194
195package Catalyst::Engine::HTTP::Daemon::Client;
196
197use strict;
198use base 'HTTP::Daemon::ClientConn';
199
abdcb6e4 200sub request : lvalue {
8a0ec4fd 201 my $self = shift;
abdcb6e4 202 ${*$self}{'request'};
8a0ec4fd 203}
204
abdcb6e4 205sub request_buffer : lvalue {
8a0ec4fd 206 my $self = shift;
abdcb6e4 207 ${*$self}{'httpd_rbuf'};
208}
8a0ec4fd 209
abdcb6e4 210sub response : lvalue {
211 my $self = shift;
212 ${*$self}{'response'};
8a0ec4fd 213}
214
abdcb6e4 215sub response_buffer : lvalue {
8a0ec4fd 216 my $self = shift;
abdcb6e4 217 ${*$self}{'httpd_wbuf'};
218}
8a0ec4fd 219
abdcb6e4 220sub response_length {
221 my $self = shift;
222 return length( $self->response_buffer );
223}
8a0ec4fd 224
abdcb6e4 225sub response_offset : lvalue {
226 my $self = shift;
227 ${*$self}{'httpd_woffset'};
2cdfbf5e 228}
229
abdcb6e4 230
2cdfbf5e 2311;