Fixed MP19 uploads. Added request/response body. Added support in all Engines for...
[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->input( $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     for my $param ( $c->cgi->url_param ) { 
137         for my $value (  $c->cgi->url_param($param) ) {
138             push ( @params, $param, $value );
139         }
140     }
141
142     for my $param ( $c->cgi->param ) { 
143         for my $value (  $c->cgi->param($param) ) {
144             push ( @params, $param, $value );
145         }
146     }
147  
148     $c->req->_assign_values( $c->req->parameters, \@params );
149 }
150
151 =item $c->prepare_path
152
153 =cut
154
155 sub prepare_path {
156     my $c = shift;
157
158     my $base;
159     {
160         my $scheme = $ENV{HTTPS} ? 'https' : 'http';
161         my $host   = $ENV{HTTP_HOST}   || $ENV{SERVER_NAME};
162         my $port   = $ENV{SERVER_PORT} || 80;
163         my $path   = $ENV{SCRIPT_NAME} || '/';
164
165         $base = URI->new;
166         $base->scheme($scheme);
167         $base->host($host);
168         $base->port($port);
169         $base->path($path);
170
171         $base = $base->canonical->as_string;
172     }
173
174     my $path = $ENV{PATH_INFO} || '/';
175     $path =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
176     $path =~ s/^\///;
177
178     $c->req->base($base);
179     $c->req->path($path);
180 }
181
182 =item $c->prepare_request
183
184 =cut
185
186 sub prepare_request { 
187     my $c = shift;
188     $c->cgi( CGI->new );
189     $c->cgi->_reset_globals;
190 }
191
192 =item $c->prepare_uploads
193
194 =cut
195
196 sub prepare_uploads {
197     my $c = shift;
198
199     my @uploads;
200     
201     for my $param ( $c->cgi->param ) {
202     
203         my @values = $c->cgi->param($param);
204
205         next unless ref( $values[0] );
206
207         for my $fh (@values) {
208
209             next unless my $size = ( stat $fh )[7];
210
211             my $info        = $c->cgi->uploadInfo($fh);
212             my $tempname    = $c->cgi->tmpFileName($fh);
213             my $type        = $info->{'Content-Type'};
214             my $disposition = $info->{'Content-Disposition'};
215             my $filename    = ( $disposition =~ / filename="([^;]*)"/ )[0];
216
217             my $upload = Catalyst::Request::Upload->new(
218                 filename => $filename,
219                 size     => $size,
220                 tempname => $tempname,
221                 type     => $type
222             );
223             
224             push( @uploads, $param, $upload );
225         }
226     }
227     
228     $c->req->_assign_values( $c->req->uploads, \@uploads );
229 }
230
231 =item $c->run
232
233 =cut
234
235 sub run { shift->handler }
236
237 =back
238
239 =head1 SEE ALSO
240
241 L<Catalyst>.
242
243 =head1 AUTHOR
244
245 Sebastian Riedel, C<sri@cpan.org>
246
247 =head1 COPYRIGHT
248
249 This program is free software, you can redistribute it and/or modify it under
250 the same terms as Perl itself.
251
252 =cut
253
254 1;