first pass at not streaming via the catalyst app, but instead allow the underlying...
[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 sub output { shift->body(@_) }
86
87 sub code   { shift->status(@_) }
88
89 sub write {
90     my ( $self, $buffer ) = @_;
91
92     # Finalize headers if someone manually writes output
93     $self->_context->finalize_headers unless $self->finalized_headers;
94
95     $buffer = q[] unless defined $buffer;
96
97     my $len = length($buffer);
98     $self->_writer->write($buffer);
99
100     return $len;
101 }
102
103 sub finalize_headers {
104     my ($self) = @_;
105     return;
106 }
107
108 sub from_psgi_response {
109     my ($self, $psgi_res) = @_;
110     if(ref $psgi_res eq 'ARRAY') {
111         my ($status, $headers, $body) = @$psgi_res;
112         $self->status($status);
113         $self->headers(HTTP::Headers->new(@$headers));
114         if(ref $body eq 'ARRAY') {
115           $self->body(join '', grep defined, @$body);
116         } else {
117           $self->body($body);
118         }
119     } elsif(ref $psgi_res eq 'CODE') {
120         $psgi_res->(sub {
121             my $response = shift;
122             my ($status, $headers, $maybe_body) = @$response;
123             $self->status($status);
124             $self->headers(HTTP::Headers->new(@$headers));
125             if($maybe_body) {
126                 if(ref $maybe_body eq 'ARRAY') {
127                   $self->body(join '', grep defined, @$maybe_body);
128                 } else {
129                   $self->body($maybe_body);
130                 }
131             } else {
132                 return $self->write_fh;
133             }
134         });  
135      } else {
136         die "You can't set a Catalyst response from that, expect a valid PSGI response";
137     }
138 }
139
140 =head1 NAME
141
142 Catalyst::Response - stores output responding to the current client request
143
144 =head1 SYNOPSIS
145
146     $res = $c->response;
147     $res->body;
148     $res->code;
149     $res->content_encoding;
150     $res->content_length;
151     $res->content_type;
152     $res->cookies;
153     $res->header;
154     $res->headers;
155     $res->output;
156     $res->redirect;
157     $res->status;
158     $res->write;
159
160 =head1 DESCRIPTION
161
162 This is the Catalyst Response class, which provides methods for responding to
163 the current client request. The appropriate L<Catalyst::Engine> for your environment
164 will turn the Catalyst::Response into a HTTP Response and return it to the client.
165
166 =head1 METHODS
167
168 =head2 $res->body( $text | $fh | $iohandle_object )
169
170     $c->response->body('Catalyst rocks!');
171
172 Sets or returns the output (text or binary data). If you are returning a large body,
173 you might want to use a L<IO::Handle> type of object (Something that implements the read method
174 in the same fashion), or a filehandle GLOB. Catalyst
175 will write it piece by piece into the response.
176
177 When using a L<IO::Handle> type of object and no content length has been
178 already set in the response headers Catalyst will make a reasonable attempt
179 to determine the size of the Handle. Depending on the implementation of your
180 handle object, setting the content length may fail. If it is at all possible
181 for you to determine the content length of your handle object, 
182 it is recommended that you set the content length in the response headers
183 yourself, which will be respected and sent by Catalyst in the response.
184
185 =head2 $res->has_body
186
187 Predicate which returns true when a body has been set.
188
189 =head2 $res->code
190
191 Alias for $res->status.
192
193 =head2 $res->content_encoding
194
195 Shortcut for $res->headers->content_encoding.
196
197 =head2 $res->content_length
198
199 Shortcut for $res->headers->content_length.
200
201 =head2 $res->content_type
202
203 Shortcut for $res->headers->content_type.
204
205 This value is typically set by your view or plugin. For example,
206 L<Catalyst::Plugin::Static::Simple> will guess the mime type based on the file
207 it found, while L<Catalyst::View::TT> defaults to C<text/html>.
208
209 =head2 $res->cookies
210
211 Returns a reference to a hash containing cookies to be set. The keys of the
212 hash are the cookies' names, and their corresponding values are hash
213 references used to construct a L<CGI::Simple::Cookie> object.
214
215     $c->response->cookies->{foo} = { value => '123' };
216
217 The keys of the hash reference on the right correspond to the L<CGI::Simple::Cookie>
218 parameters of the same name, except they are used without a leading dash.
219 Possible parameters are:
220
221 =over
222
223 =item value
224
225 =item expires
226
227 =item domain
228
229 =item path
230
231 =item secure
232
233 =item httponly
234
235 =back
236
237 =head2 $res->header
238
239 Shortcut for $res->headers->header.
240
241 =head2 $res->headers
242
243 Returns an L<HTTP::Headers> object, which can be used to set headers.
244
245     $c->response->headers->header( 'X-Catalyst' => $Catalyst::VERSION );
246
247 =head2 $res->output
248
249 Alias for $res->body.
250
251 =head2 $res->redirect( $url, $status )
252
253 Causes the response to redirect to the specified URL. The default status is
254 C<302>.
255
256     $c->response->redirect( 'http://slashdot.org' );
257     $c->response->redirect( 'http://slashdot.org', 307 );
258
259 This is a convenience method that sets the Location header to the
260 redirect destination, and then sets the response status.  You will
261 want to C< return > or C<< $c->detach() >> to interrupt the normal
262 processing flow if you want the redirect to occur straight away.
263
264 B<Note:> do not give a relative URL as $url, i.e: one that is not fully
265 qualified (= C<http://...>, etc.) or that starts with a slash
266 (= C</path/here>). While it may work, it is not guaranteed to do the right
267 thing and is not a standard behaviour. You may opt to use uri_for() or
268 uri_for_action() instead.
269
270 =cut
271
272 sub redirect {
273     my $self = shift;
274
275     if (@_) {
276         my $location = shift;
277         my $status   = shift || 302;
278
279         $self->location($location);
280         $self->status($status);
281     }
282
283     return $self->location;
284 }
285
286 =head2 $res->location
287
288 Sets or returns the HTTP 'Location'.
289
290 =head2 $res->status
291
292 Sets or returns the HTTP status.
293
294     $c->response->status(404);
295
296 $res->code is an alias for this, to match HTTP::Response->code.
297
298 =head2 $res->write( $data )
299
300 Writes $data to the output stream.
301
302 =head2 $res->write_fh
303
304 Returns a PSGI $writer object that has two methods, write and close.  You can
305 close over this object for asynchronous and nonblocking applications.  For
306 example (assuming you are using a supporting server, like L<Twiggy>
307
308     package AsyncExample::Controller::Root;
309
310     use Moose;
311
312     BEGIN { extends 'Catalyst::Controller' }
313
314     sub prepare_cb {
315       my $write_fh = pop;
316       return sub {
317         my $message = shift;
318         $write_fh->write("Finishing: $message\n");
319         $write_fh->close;
320       };
321     }
322
323     sub anyevent :Local :Args(0) {
324       my ($self, $c) = @_;
325       my $cb = $self->prepare_cb($c->res->write_fh);
326
327       my $watcher;
328       $watcher = AnyEvent->timer(
329         after => 5,
330         cb => sub {
331           $cb->(scalar localtime);
332           undef $watcher; # cancel circular-ref
333         });
334     }
335
336 =head2 $res->print( @data )
337
338 Prints @data to the output stream, separated by $,.  This lets you pass
339 the response object to functions that want to write to an L<IO::Handle>.
340
341 =head2 $self->finalize_headers($c)
342
343 Writes headers to response if not already written
344
345 =head2 from_psgi_response
346
347 Given a PSGI response (either three element ARRAY reference OR coderef expecting
348 a $responder) set the response from it.
349
350 Properly supports streaming and delayed response and / or async IO if running
351 under an expected event loop.
352
353 Example:
354
355     package MyApp::Web::Controller::Test;
356
357     use base 'Catalyst::Controller';
358     use Plack::App::Directory;
359
360
361     my $app = Plack::App::Directory->new({ root => "/path/to/htdocs" })
362       ->to_app;
363
364     sub myaction :Local Args {
365       my ($self, $c) = @_;
366       $c->res->from_psgi_response($app->($c->req->env));
367     }
368
369 Please note this does not attempt to map or nest your PSGI application under
370 the Controller and Action namespace or path.  
371
372 =head2 DEMOLISH
373
374 Ensures that the response is flushed and closed at the end of the
375 request.
376
377 =head2 meta
378
379 Provided by Moose
380
381 =cut
382
383 sub print {
384     my $self = shift;
385     my $data = shift;
386
387     defined $self->write($data) or return;
388
389     for (@_) {
390         defined $self->write($,) or return;
391         defined $self->write($_) or return;
392     }
393     defined $self->write($\) or return;
394
395     return 1;
396 }
397
398 =head1 AUTHORS
399
400 Catalyst Contributors, see Catalyst.pm
401
402 =head1 COPYRIGHT
403
404 This library is free software. You can redistribute it and/or modify
405 it under the same terms as Perl itself.
406
407 =cut
408
409 __PACKAGE__->meta->make_immutable;
410
411 1;