8950d73dd04dfa0f790337b70dfd92c26267a02c
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Engine / CGI.pm
1 package Catalyst::Engine::CGI;
2
3 use strict;
4 use base 'Catalyst::Engine';
5
6 use CGI;
7 use URI;
8 use URI::http;
9
10 __PACKAGE__->mk_accessors('cgi');
11
12 =head1 NAME
13
14 Catalyst::Engine::CGI - The CGI Engine
15
16 =head1 SYNOPSIS
17
18 A script using the Catalyst::Engine::CGI module might look like:
19
20     #!/usr/bin/perl -w
21
22     use strict;
23     use lib '/path/to/MyApp/lib';
24     use MyApp;
25
26     MyApp->run;
27
28 The application module (C<MyApp>) would use C<Catalyst>, which loads the
29 appropriate engine module.
30
31 =head1 DESCRIPTION
32
33 This is the Catalyst engine specialized for the CGI environment (using the
34 C<CGI> and C<CGI::Cookie> modules).  Normally Catalyst will select the
35 appropriate engine according to the environment that it detects, however you
36 can force Catalyst to use the CGI engine by specifying the following in your
37 application module:
38
39     use Catalyst qw(-Engine=CGI);
40
41 The performance of this way of using Catalyst is not expected to be
42 useful in production applications, but it may be helpful for development.
43
44 =head1 METHODS
45
46 =over 4
47
48 =item $c->cgi
49
50 This config parameter contains the C<CGI> object.
51
52 =back
53
54 =head1 OVERLOADED METHODS
55
56 This class overloads some methods from C<Catalyst::Engine>.
57
58 =over 4
59
60 =item $c->finalize_body
61
62 Prints the response output to STDOUT.
63
64 =cut
65
66 sub finalize_body {
67     my $c = shift;
68     print $c->response->output;
69 }
70
71 =item $c->finalize_headers
72
73 =cut
74
75 sub finalize_headers {
76     my $c = shift;
77
78     $c->response->header( Status => $c->response->status );
79
80     print $c->response->headers->as_string("\015\012");
81     print "\015\012";
82 }
83
84 =item $c->prepare_body
85
86 =cut
87
88 sub prepare_body {
89     my $c = shift;
90
91     # XXX this is undocumented in CGI.pm. If Content-Type is not
92     # application/x-www-form-urlencoded or multipart/form-data
93     # CGI.pm will read STDIN into a param, POSTDATA.
94
95     $c->request->body( $c->cgi->param('POSTDATA') );
96 }
97
98 =item $c->prepare_connection
99
100 =cut
101
102 sub prepare_connection {
103     my $c = shift;
104     $c->req->hostname( $ENV{REMOTE_HOST} );
105     $c->req->address( $ENV{REMOTE_ADDR} );
106 }
107
108 =item $c->prepare_headers
109
110 =cut
111
112 sub prepare_headers {
113     my $c = shift;
114
115     while ( my ( $header, $value ) = each %ENV ) {
116
117         next unless $header =~ /^(HTTP|CONTENT)/i;
118
119         ( my $field = $header ) =~ s/^HTTPS?_//;
120
121         $c->req->headers->header( $field => $value );
122     }
123
124     $c->req->method( $ENV{REQUEST_METHOD} || 'GET' );
125 }
126
127 =item $c->prepare_parameters
128
129 =cut
130
131 sub prepare_parameters {
132     my $c = shift;
133     
134     my ( @params );
135  
136     if ( $c->request->method eq 'POST' ) {
137         for my $param ( $c->cgi->url_param ) {
138             for my $value (  $c->cgi->url_param($param) ) {
139                 push ( @params, $param, $value );
140             }
141         }
142     }
143
144     for my $param ( $c->cgi->param ) { 
145         for my $value (  $c->cgi->param($param) ) {
146             push ( @params, $param, $value );
147         }
148     }
149  
150     $c->request->param(\@params);
151 }
152
153 =item $c->prepare_path
154
155 =cut
156
157 sub prepare_path {
158     my $c = shift;
159
160     my $base;
161     {
162         my $scheme = $ENV{HTTPS} ? 'https' : 'http';
163         my $host   = $ENV{HTTP_HOST}   || $ENV{SERVER_NAME};
164         my $port   = $ENV{SERVER_PORT} || 80;
165         my $path   = $ENV{SCRIPT_NAME} || '/';
166
167         $base = URI->new;
168         $base->scheme($scheme);
169         $base->host($host);
170         $base->port($port);
171         $base->path($path);
172
173         $base = $base->canonical->as_string;
174     }
175
176     my $path = $ENV{PATH_INFO} || '/';
177     $path =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
178     $path =~ s/^\///;
179
180     $c->req->base($base);
181     $c->req->path($path);
182 }
183
184 =item $c->prepare_request
185
186 =cut
187
188 sub prepare_request { 
189     my ( $c, $cgi ) = @_;
190     $c->cgi( $cgi || CGI->new );
191     $c->cgi->_reset_globals;
192 }
193
194 =item $c->prepare_uploads
195
196 =cut
197
198 sub prepare_uploads {
199     my $c = shift;
200
201     my @uploads;
202     
203     for my $param ( $c->cgi->param ) {
204     
205         my @values = $c->cgi->param($param);
206
207         next unless ref( $values[0] );
208
209         for my $fh (@values) {
210
211             next unless my $size = ( stat $fh )[7];
212
213             my $info        = $c->cgi->uploadInfo($fh);
214             my $tempname    = $c->cgi->tmpFileName($fh);
215             my $type        = $info->{'Content-Type'};
216             my $disposition = $info->{'Content-Disposition'};
217             my $filename    = ( $disposition =~ / filename="([^;]*)"/ )[0];
218
219             my $upload = Catalyst::Request::Upload->new(
220                 filename => $filename,
221                 size     => $size,
222                 tempname => $tempname,
223                 type     => $type
224             );
225             
226             push( @uploads, $param, $upload );
227         }
228     }
229     
230     $c->request->upload(\@uploads);
231 }
232
233 =item $c->run
234
235 =cut
236
237 sub run { shift->handler }
238
239 =back
240
241 =head1 SEE ALSO
242
243 L<Catalyst>.
244
245 =head1 AUTHOR
246
247 Sebastian Riedel, C<sri@cpan.org>
248
249 =head1 COPYRIGHT
250
251 This program is free software, you can redistribute it and/or modify it under
252 the same terms as Perl itself.
253
254 =cut
255
256 1;