File Coverage

blib/lib/Catalyst/Engine/Server/Base.pm
Criterion Covered Total %
statement 6 6 100.0
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 8 8 100.0


line stmt bran cond sub pod time code
1             package Catalyst::Engine::Server::Base;
2              
3 1     1   6 use strict;
  1         1  
  1         32  
4 1     1   5 use base 'Catalyst::Engine::HTTP::Base';
  1         5  
  1         7231  
5              
6             __PACKAGE__->mk_accessors('server');
7              
8             =head1 NAME
9              
10             Catalyst::Engine::Server::Base - Base class for Server Engines
11              
12             =head1 SYNOPSIS
13              
14             See L<Catalyst>.
15              
16             =head1 DESCRIPTION
17              
18             This is a base class for Catalyst::Engine::Server Engines.
19              
20             =head1 METHODS
21              
22             =over 4
23              
24             =item $c->server
25              
26             Returns an C<Server> object.
27              
28             =back
29              
30             =head1 OVERLOADED METHODS
31              
32             This class overloads some methods from C<Catalyst::Engine::HTTP::Base>.
33              
34             =over 4
35              
36             =item $c->handler
37              
38             =cut
39              
40             sub handler {
41             my ( $class, $request, $response, $server ) = @_;
42              
43             my $client = $server->{server}->{client};
44              
45             $request->uri->scheme('http');
46             $request->uri->host( $request->header('Host') || $client->sockhost );
47             $request->uri->port( $client->sockport );
48              
49             my $http = Catalyst::Engine::HTTP::Base::struct->new(
50             address => $client->peerhost,
51             hostname => $server->{server}->{peerhost},
52             request => $request,
53             response => $response
54             );
55              
56             $class->SUPER::handler( $server, $http );
57             }
58              
59             =item $c->prepare_request
60              
61             =cut
62              
63             sub prepare_request {
64             my ( $c, $server, @arguments ) = @_;
65             $c->server($server);
66             $c->SUPER::prepare_request(@arguments);
67             }
68              
69             =back
70              
71             =head1 SEE ALSO
72              
73             L<Catalyst>, L<Catalyst::Engine>, L<Catalyst::Engine::HTTP::Base>,
74             L<Net::Server>.
75              
76             =head1 AUTHOR
77              
78             Christian Hansen, C<ch@ngmedia.com>
79              
80             =head1 COPYRIGHT
81              
82             This program is free software, you can redistribute it and/or modify it under
83             the same terms as Perl itself.
84              
85             =cut
86              
87             package Catalyst::Engine::Server::Net::Server;
88              
89             use strict;
90             use base 'Class::Accessor::Fast';
91              
92             use HTTP::Parser;
93             use HTTP::Request;
94             use HTTP::Response;
95              
96             __PACKAGE__->mk_accessors('application');
97              
98             sub configure_hook {
99             my $self = shift;
100             my $prop = $self->{server};
101              
102             my $config = $self->application->config->{server} || { };
103              
104             while ( my ( $property, $value ) = each %{ $config } ) {
105             $prop->{ $property } = $value;
106             }
107              
108             if ( $prop->{port} && not ref( $prop->{port} ) ) {
109             $prop->{port} = [ $prop->{port} ];
110             }
111             }
112              
113             sub process_request {
114             my $self = shift;
115             my $prop = $self->{server};
116             my $client = $prop->{client};
117              
118             local $SIG{ALRM} = sub { die "Timeout (30s)\n" };
119              
120             REQUEST:
121              
122             my $timeout = 30;
123             my $parser = HTTP::Parser->new;
124              
125             eval {
126              
127             alarm($timeout);
128              
129             while ( defined( my $read = $client->sysread( my $buf, 2048 ) ) ) {
130             last if $read == 0;
131             last if $parser->add($buf) == 0;
132             }
133              
134             unless ( $client->connected ) {
135             goto DONE;
136             }
137              
138             unless ( $parser->request ) {
139             goto DONE;
140             }
141              
142             my $request = $parser->request;
143             my $response = HTTP::Response->new;
144             my $protocol = sprintf( 'HTTP/%s', $request->header('X-HTTP-Version') );
145              
146             $request->protocol($protocol);
147              
148             $self->application->handler( $request, $response, $self );
149              
150             $response->date( time() );
151             $response->header( Server => "Catalyst/$Catalyst::VERSION" );
152             $response->protocol($protocol);
153              
154             my $connection = $request->header('Connection') || '';
155              
156             if ( $connection =~ /Keep-Alive/i ) {
157             $response->header( 'Connection' => 'Keep-Alive' );
158             $response->header( 'Keep-Alive' => 'timeout=60, max=100' );
159             }
160              
161             if ( $connection =~ /close/i ) {
162             $response->header( 'Connection' => 'close' );
163             }
164              
165             $client->syswrite( $response->as_string("\x0D\x0A") );
166              
167             if ( $protocol eq 'HTTP/1.1' && $connection !~ /close/i ) {
168             goto REQUEST;
169             }
170              
171             if ( $protocol ne 'HTTP/1.1' && $connection =~ /Keep-Alive/i ) {
172             goto REQUEST;
173             }
174             };
175              
176             if ( my $error = $@ ) {
177              
178             chomp($error);
179              
180             unless ( $error =~ /^Timeout/ ) {
181             warn $error;
182             }
183             }
184              
185             DONE:
186              
187             alarm(0);
188              
189             if ( $client->connected ) {
190             $client->shutdown(2);
191             }
192             }
193              
194             1;