Replaced the Catalyst::Utils proof of concept with documentation for XSendfile
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Response.pm
1 package Catalyst::Response;
2
3 use Moose;
4 use HTTP::Headers;
5 use Moose::Util::TypeConstraints;
6 use namespace::autoclean;
7
8 with 'MooseX::Emulate::Class::Accessor::Fast';
9
10 has _response_cb => (
11     is      => 'ro',
12     isa     => 'CodeRef', 
13     writer  => '_set_response_cb',
14     clearer => '_clear_response_cb',
15     predicate => '_has_response_cb',
16 );
17
18 subtype 'Catalyst::Engine::Types::Writer',
19     as duck_type([qw(write close)]);
20
21 has _writer => (
22     is      => 'ro',
23     isa     => 'Catalyst::Engine::Types::Writer', #Pointless since we control how this is built
24     #writer  => '_set_writer', Now that its lazy I think this is safe to remove
25     clearer => '_clear_writer',
26     predicate => '_has_writer',
27     lazy      => 1,
28     builder => '_build_writer',
29 );
30
31 sub _build_writer {
32     my $self = shift;
33
34     ## These two lines are probably crap now...
35     $self->_context->finalize_headers unless
36       $self->finalized_headers;
37
38     my @headers;
39     $self->headers->scan(sub { push @headers, @_ });
40
41     my $writer = $self->_response_cb->([ $self->status, \@headers ]);
42     $self->_clear_response_cb;
43
44     return $writer;
45 }
46
47 has write_fh => (
48   is=>'ro',
49   predicate=>'_has_write_fh',
50   lazy=>1,
51   builder=>'_build_write_fh',
52 );
53
54 sub _build_write_fh { shift ->_writer }
55
56 sub DEMOLISH {
57   my $self = shift;
58   return if $self->_has_write_fh;
59   if($self->_has_writer) {
60     $self->_writer->close
61   }
62 }
63
64 has cookies   => (is => 'rw', default => sub { {} });
65 has body      => (is => 'rw', default => undef);
66 sub has_body { defined($_[0]->body) }
67
68 has location  => (is => 'rw');
69 has status    => (is => 'rw', default => 200);
70 has finalized_headers => (is => 'rw', default => 0);
71 has headers   => (
72   is      => 'rw',
73   isa => 'HTTP::Headers',
74   handles => [qw(content_encoding content_length content_type header)],
75   default => sub { HTTP::Headers->new() },
76   required => 1,
77   lazy => 1,
78 );
79 has _context => (
80   is => 'rw',
81   weak_ref => 1,
82   clearer => '_clear_context',
83 );
84
85 before [qw(status headers content_encoding content_length content_type header)] => sub {
86   my $self = shift;
87
88   $self->_context->log->warn( 
89     "Useless setting a header value after finalize_headers called." .
90     " Not what you want." )
91       if ( $self->finalized_headers && @_ );
92 };
93
94 sub output { shift->body(@_) }
95
96 sub code   { shift->status(@_) }
97
98 sub write {
99     my ( $self, $buffer ) = @_;
100
101     # Finalize headers if someone manually writes output
102     $self->_context->finalize_headers unless $self->finalized_headers;
103
104     $buffer = q[] unless defined $buffer;
105
106     my $len = length($buffer);
107     $self->_writer->write($buffer);
108
109     return $len;
110 }
111
112 sub finalize_headers {
113     my ($self) = @_;
114     return;
115 }
116
117 sub from_psgi_response {
118     my ($self, $psgi_res) = @_;
119     if(ref $psgi_res eq 'ARRAY') {
120         my ($status, $headers, $body) = @$psgi_res;
121         $self->status($status);
122         $self->headers(HTTP::Headers->new(@$headers));
123         $self->body($body);
124     } elsif(ref $psgi_res eq 'CODE') {
125         $psgi_res->(sub {
126             my $response = shift;
127             my ($status, $headers, $maybe_body) = @$response;
128             $self->status($status);
129             $self->headers(HTTP::Headers->new(@$headers));
130             if(defined $maybe_body) {
131                 $self->body($maybe_body);
132             } else {
133                 return $self->write_fh;
134             }
135         });  
136      } else {
137         die "You can't set a Catalyst response from that, expect a valid PSGI response";
138     }
139 }
140
141 =head1 NAME
142
143 Catalyst::Response - stores output responding to the current client request
144
145 =head1 SYNOPSIS
146
147     $res = $c->response;
148     $res->body;
149     $res->code;
150     $res->content_encoding;
151     $res->content_length;
152     $res->content_type;
153     $res->cookies;
154     $res->header;
155     $res->headers;
156     $res->output;
157     $res->redirect;
158     $res->status;
159     $res->write;
160
161 =head1 DESCRIPTION
162
163 This is the Catalyst Response class, which provides methods for responding to
164 the current client request. The appropriate L<Catalyst::Engine> for your environment
165 will turn the Catalyst::Response into a HTTP Response and return it to the client.
166
167 =head1 METHODS
168
169 =head2 $res->body( $text | $fh | $iohandle_object )
170
171     $c->response->body('Catalyst rocks!');
172
173 Sets or returns the output (text or binary data). If you are returning a large body,
174 you might want to use a L<IO::Handle> type of object (Something that implements the read method
175 in the same fashion), or a filehandle GLOB. Catalyst
176 will write it piece by piece into the response.
177
178 When using a L<IO::Handle> type of object and no content length has been
179 already set in the response headers Catalyst will make a reasonable attempt
180 to determine the size of the Handle. Depending on the implementation of your
181 handle object, setting the content length may fail. If it is at all possible
182 for you to determine the content length of your handle object, 
183 it is recommended that you set the content length in the response headers
184 yourself, which will be respected and sent by Catalyst in the response.
185
186 Please note that the object needs to implement C<getline>, not just
187 C<read>.
188
189 Starting from version 5.90060, when using an L<IO::Handle> object, you
190 may want to use L<Plack::Middleware::XSendfile>, to delegate the
191 actual serving to the frontend server. To do so, you need to pass to
192 C<body> an IO object with a C<path> method. This can be achieved in
193 two ways.
194
195 Either using L<Plack::Util>:
196
197   my $fh = IO::File->new($file, 'r');
198   Plack::Util::set_io_path($fh, $file);
199
200 Or using L<IO::File::WithPath>
201
202   my $fh = IO::File::WithPath->new($file, 'r');
203
204 And then passing the filehandle to body and setting headers, if needed.
205
206   $c->response->body($fh);
207   $c->response->headers->content_type('text/plain');
208   $c->response->headers->content_length(-s $file);
209   $c->response->headers->last_modified((stat($file))[9]);
210
211 L<Plack::Middleware::XSendfile> can be loaded in the application so:
212
213  __PACKAGE__->config(
214      psgi_middleware => [
215          'XSendfile',
216          # other middlewares here...
217         ],
218  );
219
220 B<Beware> that loading the middleware without configuring the
221 webserver to set the request header C<X-Sendfile-Type> to a supported
222 type (C<X-Accel-Redirect> for nginx, C<X-Sendfile> for Apache and
223 Lighttpd), could lead to the disclosure of private paths to malicious
224 clients setting that header.
225
226 Nginx needs the additional X-Accel-Mapping header to be set in the
227 webserver configuration, so the middleware will replace the absolute
228 path of the IO object with the internal nginx path. This is also
229 useful to prevent a buggy app to server random files from the
230 filesystem, as it's an internal redirect.
231
232 An nginx configuration for FastCGI could look so:
233
234  server {
235      server_name example.com;
236      root /my/app/root;
237      location /private/repo/ {
238          internal;
239          alias /my/app/repo/;
240      }
241      location /private/staging/ {
242          internal;
243          alias /my/app/staging/;
244      }
245      location @proxy {
246          include /etc/nginx/fastcgi_params;
247          fastcgi_param SCRIPT_NAME '';
248          fastcgi_param PATH_INFO   $fastcgi_script_name;
249          fastcgi_param HTTP_X_SENDFILE_TYPE X-Accel-Redirect;
250          fastcgi_param HTTP_X_ACCEL_MAPPING /my/app=/private;
251          fastcgi_pass  unix:/my/app/run/app.sock;
252     }
253  }
254
255 In the example above, passing filehandles with a local path matching
256 /my/app/staging or /my/app/repo will be served by nginx. Passing paths
257 with other locations will lead to an internal server error.
258
259 Setting the body to a filehandle without the C<path> method bypasses
260 the middleware completely.
261
262 For Apache and Lighttpd, the mapping doesn't apply and setting the
263 X-Sendfile-Type is enough.
264
265 =head2 $res->has_body
266
267 Predicate which returns true when a body has been set.
268
269 =head2 $res->code
270
271 Alias for $res->status.
272
273 =head2 $res->content_encoding
274
275 Shortcut for $res->headers->content_encoding.
276
277 =head2 $res->content_length
278
279 Shortcut for $res->headers->content_length.
280
281 =head2 $res->content_type
282
283 Shortcut for $res->headers->content_type.
284
285 This value is typically set by your view or plugin. For example,
286 L<Catalyst::Plugin::Static::Simple> will guess the mime type based on the file
287 it found, while L<Catalyst::View::TT> defaults to C<text/html>.
288
289 =head2 $res->cookies
290
291 Returns a reference to a hash containing cookies to be set. The keys of the
292 hash are the cookies' names, and their corresponding values are hash
293 references used to construct a L<CGI::Simple::Cookie> object.
294
295     $c->response->cookies->{foo} = { value => '123' };
296
297 The keys of the hash reference on the right correspond to the L<CGI::Simple::Cookie>
298 parameters of the same name, except they are used without a leading dash.
299 Possible parameters are:
300
301 =over
302
303 =item value
304
305 =item expires
306
307 =item domain
308
309 =item path
310
311 =item secure
312
313 =item httponly
314
315 =back
316
317 =head2 $res->header
318
319 Shortcut for $res->headers->header.
320
321 =head2 $res->headers
322
323 Returns an L<HTTP::Headers> object, which can be used to set headers.
324
325     $c->response->headers->header( 'X-Catalyst' => $Catalyst::VERSION );
326
327 =head2 $res->output
328
329 Alias for $res->body.
330
331 =head2 $res->redirect( $url, $status )
332
333 Causes the response to redirect to the specified URL. The default status is
334 C<302>.
335
336     $c->response->redirect( 'http://slashdot.org' );
337     $c->response->redirect( 'http://slashdot.org', 307 );
338
339 This is a convenience method that sets the Location header to the
340 redirect destination, and then sets the response status.  You will
341 want to C< return > or C<< $c->detach() >> to interrupt the normal
342 processing flow if you want the redirect to occur straight away.
343
344 B<Note:> do not give a relative URL as $url, i.e: one that is not fully
345 qualified (= C<http://...>, etc.) or that starts with a slash
346 (= C</path/here>). While it may work, it is not guaranteed to do the right
347 thing and is not a standard behaviour. You may opt to use uri_for() or
348 uri_for_action() instead.
349
350 =cut
351
352 sub redirect {
353     my $self = shift;
354
355     if (@_) {
356         my $location = shift;
357         my $status   = shift || 302;
358
359         $self->location($location);
360         $self->status($status);
361     }
362
363     return $self->location;
364 }
365
366 =head2 $res->location
367
368 Sets or returns the HTTP 'Location'.
369
370 =head2 $res->status
371
372 Sets or returns the HTTP status.
373
374     $c->response->status(404);
375
376 $res->code is an alias for this, to match HTTP::Response->code.
377
378 =head2 $res->write( $data )
379
380 Writes $data to the output stream.
381
382 =head2 $res->write_fh
383
384 Returns a PSGI $writer object that has two methods, write and close.  You can
385 close over this object for asynchronous and nonblocking applications.  For
386 example (assuming you are using a supporting server, like L<Twiggy>
387
388     package AsyncExample::Controller::Root;
389
390     use Moose;
391
392     BEGIN { extends 'Catalyst::Controller' }
393
394     sub prepare_cb {
395       my $write_fh = pop;
396       return sub {
397         my $message = shift;
398         $write_fh->write("Finishing: $message\n");
399         $write_fh->close;
400       };
401     }
402
403     sub anyevent :Local :Args(0) {
404       my ($self, $c) = @_;
405       my $cb = $self->prepare_cb($c->res->write_fh);
406
407       my $watcher;
408       $watcher = AnyEvent->timer(
409         after => 5,
410         cb => sub {
411           $cb->(scalar localtime);
412           undef $watcher; # cancel circular-ref
413         });
414     }
415
416 =head2 $res->print( @data )
417
418 Prints @data to the output stream, separated by $,.  This lets you pass
419 the response object to functions that want to write to an L<IO::Handle>.
420
421 =head2 $self->finalize_headers($c)
422
423 Writes headers to response if not already written
424
425 =head2 from_psgi_response
426
427 Given a PSGI response (either three element ARRAY reference OR coderef expecting
428 a $responder) set the response from it.
429
430 Properly supports streaming and delayed response and / or async IO if running
431 under an expected event loop.
432
433 Example:
434
435     package MyApp::Web::Controller::Test;
436
437     use base 'Catalyst::Controller';
438     use Plack::App::Directory;
439
440
441     my $app = Plack::App::Directory->new({ root => "/path/to/htdocs" })
442       ->to_app;
443
444     sub myaction :Local Args {
445       my ($self, $c) = @_;
446       $c->res->from_psgi_response($app->($c->req->env));
447     }
448
449 Please note this does not attempt to map or nest your PSGI application under
450 the Controller and Action namespace or path.  
451
452 =head2 DEMOLISH
453
454 Ensures that the response is flushed and closed at the end of the
455 request.
456
457 =head2 meta
458
459 Provided by Moose
460
461 =cut
462
463 sub print {
464     my $self = shift;
465     my $data = shift;
466
467     defined $self->write($data) or return;
468
469     for (@_) {
470         defined $self->write($,) or return;
471         defined $self->write($_) or return;
472     }
473     defined $self->write($\) or return;
474
475     return 1;
476 }
477
478 =head1 AUTHORS
479
480 Catalyst Contributors, see Catalyst.pm
481
482 =head1 COPYRIGHT
483
484 This library is free software. You can redistribute it and/or modify
485 it under the same terms as Perl itself.
486
487 =cut
488
489 __PACKAGE__->meta->make_immutable;
490
491 1;