File Coverage

blib/lib/Mojolicious/Controller.pm
Criterion Covered Total %
statement 191 213 89.6
branch 99 110 90.0
condition 35 55 63.6
subroutine 114 116 98.2
pod 28 29 96.5
total 467 523 89.2


line stmt bran cond sub pod time code
1             package Mojolicious::Controller;
2 55     55   77020 use Mojo::Base -base;
  55         89  
  55         348  
3              
4             # No imports, for security reasons!
5 55     55   270 use Carp ();
  55         85  
  55         617  
6 55     55   1072 use Digest::SHA ();
  55         5378  
  55         752  
7 55     55   962 use Mojo::ByteStream;
  55         77  
  55         2399  
8 55     55   1035 use Mojo::DynamicMethods -dispatch;
  55         89  
  55         362  
9 55     55   1061 use Mojo::URL;
  55         108  
  55         386  
10 55     55   189 use Mojo::Util;
  55         76  
  55         1629  
11 55     55   23276 use Mojolicious::Routes::Match;
  55         158  
  55         343  
12 55     55   343 use Scalar::Util ();
  55         102  
  55         186466  
13              
14             my $ABSOLUTE = qr!^(?:[^:/?#]+:|//|#)!;
15              
16             has [qw(app tx)] => undef, weak => 1;
17             has match => sub { Mojolicious::Routes::Match->new(root => shift->app->routes) };
18              
19             sub BUILD_DYNAMIC {
20 3661     3661 0 5087 my ($class, $method, $dyn_methods) = @_;
21              
22             return sub {
23 512     512   2690 my $self = shift;
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        568      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        529      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        512      
        568      
        568      
        568      
        568      
        512      
        512      
        536      
        512      
        512      
        512      
        512      
        512      
        512      
        159      
24 512         3632 my $dynamic = $dyn_methods->{$self->{app}{renderer}}{$method};
25 512 50       2016 return $self->$dynamic(@_) if $dynamic;
26 0         0 my $package = ref $self;
27 0         0 Carp::croak qq{Can't locate object method "$method" via package "$package"};
28 3661         14523 };
29             }
30              
31 1     1 1 6 sub continue { $_[0]->app->routes->continue($_[0]) }
32              
33             sub cookie {
34 154     154 1 576 my ($self, $name) = (shift, shift);
35              
36             # Response cookie
37 154 100       295 if (@_) {
38              
39             # Cookie too big
40 120   100     166 my $cookie = {name => $name, value => shift, %{shift // {}}};
  120         577  
41 120 50       737 $self->helpers->log->error(qq{Cookie "$name" is bigger than 4KiB}) if length $cookie->{value} > 4096;
42              
43 120         237 $self->res->cookies($cookie);
44 120         434 return $self;
45             }
46              
47             # Request cookies
48 34 100       67 return undef unless my $cookie = $self->req->cookie($name);
49 21         39 return $cookie->value;
50             }
51              
52             sub encrypted_cookie {
53 0     0 1 0 my ($self, $name, $value, $options) = @_;
54              
55             # Request cookie
56 0 0       0 return $self->every_encrypted_cookie($name)->[-1] unless defined $value;
57              
58             # Response cookie
59 0         0 my $app = $self->app;
60 0         0 my $secret = $app->secrets->[0];
61 0         0 my $moniker = $app->moniker;
62 0         0 return $self->cookie($name, Mojo::Util::encrypt_cookie($value, $secret, $moniker), $options);
63             }
64              
65 261     261 1 330 sub every_cookie { [map { $_->value } @{shift->req->every_cookie(shift)}] }
  78         150  
  261         510  
66              
67             sub every_encrypted_cookie {
68 0     0 1 0 my ($self, $name) = @_;
69              
70 0         0 my $app = $self->app;
71 0         0 my $secrets = $app->secrets;
72 0         0 my $moniker = $app->moniker;
73 0         0 my @results;
74 0         0 for my $value (@{$self->every_cookie($name)}) {
  0         0  
75 0         0 my $decrypted;
76 0         0 for my $secret (@$secrets) {
77 0 0       0 last if defined($decrypted = Mojo::Util::decrypt_cookie($value, $secret, $moniker));
78             }
79 0 0       0 if (defined $decrypted) { push @results, $decrypted }
  0         0  
80              
81 0         0 else { $self->helpers->log->trace(qq{Cookie "$name" is not encrypted}) }
82             }
83              
84 0         0 return \@results;
85             }
86              
87             sub every_param {
88 391     391 1 744 my ($self, $name) = @_;
89              
90             # Captured unreserved values
91 391   100     872 my $captures = $self->stash->{'mojo.captures'} //= {};
92 391 100 100     1306 if (exists $captures->{$name} && !$self->app->routes->is_reserved($name)) {
93 84         160 my $value = $captures->{$name};
94 84 100       570 return ref $value eq 'ARRAY' ? $value : [$value];
95             }
96              
97             # Uploads or param values
98 307         672 my $req = $self->req;
99 307         1152 my $uploads = $req->every_upload($name);
100 307 100       1108 return @$uploads ? $uploads : $req->every_param($name);
101             }
102              
103             sub every_signed_cookie {
104 259     259 1 420 my ($self, $name) = @_;
105              
106 259         431 my $secrets = $self->app->secrets;
107 259         422 my @results;
108 259         342 for my $value (@{$self->every_cookie($name)}) {
  259         560  
109              
110             # Check signature with rotating secrets
111 76 100       372 if ($value =~ s/--([^\-]+)$//) {
112 67         126 my $signature = $1;
113              
114 67         80 my $valid;
115 67         128 for my $secret (@$secrets) {
116 76         648 my $check = Digest::SHA::hmac_sha256_hex("$name=$value", $secret);
117 76 100 50     232 ++$valid and last if Mojo::Util::secure_compare($signature, $check);
118             }
119 67 100       141 if ($valid) { push @results, $value }
  55         140  
120              
121 12         25 else { $self->helpers->log->trace(qq{Cookie "$name" has bad signature}) }
122             }
123              
124 9         21 else { $self->helpers->log->trace(qq{Cookie "$name" is not signed}) }
125             }
126              
127 259         986 return \@results;
128             }
129              
130             sub finish {
131 35     35 1 144 my $self = shift;
132              
133             # WebSocket
134 35   33     103 my $tx = $self->tx || Carp::croak 'Transaction already destroyed';
135 35 100 50     125 $tx->finish(@_) and return $tx->established ? $self : $self->rendered(101) if $tx->is_websocket;
    100          
136              
137             # Chunked stream
138 26 100       83 return @_ ? $self->write_chunk(@_)->write_chunk('') : $self->write_chunk('') if $tx->res->content->is_chunked;
    100          
139              
140             # Normal stream
141 20 100       72 return @_ ? $self->write(@_)->write('') : $self->write('');
142             }
143              
144 4961     4961 1 11219 sub helpers { $_[0]->app->renderer->get_helper('')->($_[0]) }
145              
146             sub on {
147 93     93 1 492 my ($self, $name, $cb) = @_;
148 93   33     233 my $tx = $self->tx || Carp::croak 'Transaction already destroyed';
149 93 100 66     310 $self->rendered(101) if $tx->is_websocket && !$tx->established;
150 93     89   449 return $tx->on($name => sub { shift; $self->$cb(@_) });
  89         149  
  89         317  
151             }
152              
153             sub param {
154 259     259 1 959 my ($self, $name) = (shift, shift);
155 259 100       971 return $self->every_param($name)->[-1] unless @_;
156 27 100       123 $self->stash->{'mojo.captures'}{$name} = @_ > 1 ? [@_] : $_[0];
157 27         97 return $self;
158             }
159              
160             sub render {
161 1010     1010 1 2344 my $self = shift;
162              
163             # Template may be first argument
164 1010 100       5180 my ($template, $args) = (@_ % 2 ? shift : undef, {@_});
165 1010 100       2009 $args->{template} = $template if $template;
166 1010         2119 my $app = $self->app;
167 1010         2288 my $plugins = $app->plugins->emit_hook(before_render => $self, $args);
168              
169             # Localize "extends" and "layout" to allow argument overrides
170 1010         1582 my ($maybe, $ts) = @{$args}{'mojo.maybe', 'mojo.string'};
  1010         2142  
171 1010         1780 my $stash = $self->stash;
172 1010 100       2444 local $stash->{layout} = $stash->{layout} if exists $stash->{layout};
173 1010 100       2007 local $stash->{extends} = $stash->{extends} if exists $stash->{extends};
174              
175             # Rendering to string
176 1010 100 100     3785 local @{$stash}{keys %$args} if $ts || $maybe;
  580         1558  
177 1010 100       2012 delete @{$stash}{qw(layout extends)} if $ts;
  26         50  
178              
179             # All other arguments just become part of the stash
180 1010         2898 @$stash{keys %$args} = values %$args;
181 1010         2160 my $renderer = $app->renderer;
182 1010         3023 my ($output, $format) = $renderer->render($self);
183              
184             # Maybe no 404
185 990 50       2277 return defined $output ? Mojo::ByteStream->new($output) : undef if $ts;
    100          
186 965 100       5741 return $maybe ? undef : Carp::croak("Could not render a response") unless defined $output;
    100          
187              
188 774         2482 $plugins->emit_hook(after_render => $self, \$output, $format);
189 774         3125 return $renderer->respond($self, $output, $format, $stash->{status});
190             }
191              
192 1038     1038 1 2057 sub render_later { shift->stash('mojo.rendered' => 1) }
193              
194 559     559 1 1574 sub render_maybe { shift->render(@_, 'mojo.maybe' => 1) }
195              
196 26     26 1 159 sub render_to_string { shift->render(@_, 'mojo.string' => 1) }
197              
198             sub rendered {
199 1169     1169 1 2288 my ($self, $status) = @_;
200              
201             # Make sure we have a status
202 1169 100       2511 $self->res->code($status) if $status;
203              
204             # Finish transaction
205 1169         2334 my $stash = $self->stash;
206 1169 100 66     5404 if (!$stash->{'mojo.finished'} && ++$stash->{'mojo.finished'}) {
207 1014         1958 my $res = $self->res;
208 1014 100 100     3486 $res->code(200) if !$status && !$res->code;
209              
210             # Disable auto rendering and stop timer
211 1014         2535 my $app = $self->render_later->app;
212             $self->helpers->log->trace(sub {
213 279     279   495 my $timing = $self->helpers->timing;
214 279   50     849 my $elapsed = $timing->elapsed('mojo.timer') // 0;
215 279   50     4094 my $rps = $timing->rps($elapsed) // '??';
216 279         780 my $code = $res->code;
217 279   33     670 my $msg = $res->message || $res->default_message($code);
218 279         1937 return "$code $msg (${elapsed}s, $rps/s)";
219 1014 100       3510 }) unless $stash->{'mojo.static'};
220              
221 1014         7287 $app->plugins->emit_hook_reverse(after_dispatch => $self);
222 1014         2566 $app->sessions->store($self);
223             }
224 1169         2550 $self->tx->resume;
225 1169         8330 return $self;
226             }
227              
228 5893   33 5893 1 13926 sub req { (shift->tx || Carp::croak 'Transaction already destroyed')->req }
229 3689   33 3689 1 7550 sub res { (shift->tx || Carp::croak 'Transaction already destroyed')->res }
230              
231             sub send {
232 105     105 1 943 my ($self, $msg, $cb) = @_;
233 105   33     346 my $tx = $self->tx || Carp::croak 'Transaction already destroyed';
234 105 100       376 Carp::croak 'No WebSocket connection to send message to' unless $tx->is_websocket;
235 104 100   2   433 $tx->send($msg, $cb ? sub { shift; $self->$cb(@_) } : ());
  2         5  
  2         9  
236 104 100       292 return $tx->established ? $self : $self->rendered(101);
237             }
238              
239             sub session {
240 253     253 1 501 my $self = shift;
241              
242 253         473 my $stash = $self->stash;
243 253 100       776 $self->app->sessions->load($self) unless exists $stash->{'mojo.active_session'};
244              
245             # Hash
246 253   100     762 my $session = $stash->{'mojo.session'} //= {};
247 253 100       798 return $session unless @_;
248              
249             # Get
250 41 100 66     153 return $session->{$_[0]} unless @_ > 1 || ref $_[0];
251              
252             # Set
253 23 50       81 my $values = ref $_[0] ? $_[0] : {@_};
254 23         71 @$session{keys %$values} = values %$values;
255              
256 23         58 return $self;
257             }
258              
259             sub signed_cookie {
260 331     331 1 836 my ($self, $name, $value, $options) = @_;
261              
262             # Request cookie
263 331 100       888 return $self->every_signed_cookie($name)->[-1] unless defined $value;
264              
265             # Response cookie
266 74         216 my $sum = Digest::SHA::hmac_sha256_hex("$name=$value", $self->app->secrets->[0]);
267 74         278 return $self->cookie($name, "$value--$sum", $options);
268             }
269              
270 21013     21013 1 40907 sub stash { Mojo::Util::_stash(stash => @_) }
271              
272             sub url_for {
273 656   100 656 1 1913 my ($self, $target) = (shift, shift // '');
274              
275             # Absolute URL
276 656 100 66     1548 return $target if Scalar::Util::blessed $target && $target->isa('Mojo::URL');
277 636 100       2980 return Mojo::URL->new($target) if $target =~ $ABSOLUTE;
278              
279             # Base
280 615         7347 my $url = Mojo::URL->new;
281 615         1259 my $req = $self->req;
282 615         1699 my $base = $url->base($req->url->base->clone)->base->userinfo(undef);
283              
284             # Relative URL
285 615         1318 my $path = $url->path;
286 615 100       1385 if ($target =~ m!^/!) {
287 451 100       751 if (defined(my $prefix = $self->stash->{path})) {
288 30         57 my $real = $req->url->path->to_route;
289 30         587 $real =~ s!/?\Q$prefix\E$!$target!;
290 30         71 $target = $real;
291             }
292 451         885 $url->parse($target);
293             }
294              
295             # Route
296             else {
297 164         356 my $generated = $self->match->path_for($target, @_);
298 164 100       838 $path->parse($generated->{path}) if $generated->{path};
299 164 50       487 $base->scheme($base->protocol eq 'https' ? 'wss' : 'ws') if $generated->{websocket};
    100          
300             }
301              
302             # Make path absolute
303 615         1145 my $base_path = $base->path;
304 615         769 unshift @{$path->parts}, @{$base_path->parts};
  615         1057  
  615         1039  
305 615         1223 $base_path->parts([])->trailing_slash(0);
306              
307 615         2363 return $url;
308             }
309              
310             sub url_for_asset {
311 21     21 1 44 my ($self, $asset) = @_;
312 21 100       182 return $self->url_for($asset =~ $ABSOLUTE ? $asset : $self->app->static->asset_path($asset));
313             }
314              
315             sub url_for_file {
316 386     386 1 586 my ($self, $file) = @_;
317 386 100       2625 return $self->url_for($file =~ $ABSOLUTE ? $file : $self->app->static->file_path($file));
318             }
319              
320             sub write {
321 41     41 1 145 my ($self, $chunk, $cb) = @_;
322 41 100   4   92 $self->res->content->write($chunk, $cb ? sub { shift; $self->$cb(@_) } : ());
  4         7  
  4         11  
323 41         104 return $self->rendered;
324             }
325              
326             sub write_chunk {
327 61     61 1 405 my ($self, $chunk, $cb) = @_;
328 61 100   37   163 $self->res->content->write_chunk($chunk, $cb ? sub { shift; $self->$cb(@_) } : ());
  37         49  
  37         116  
329 61         196 return $self->rendered;
330             }
331              
332             sub write_sse {
333 57     57 1 456 my ($self, $event, $cb) = @_;
334 57 100   1   122 $self->res->content->write_sse($event, $cb ? sub { shift; $self->$cb(@_) } : ());
  1         1  
  1         5  
335 57         150 return $self->rendered;
336             }
337              
338             1;
339              
340             =encoding utf8
341              
342             =head1 NAME
343              
344             Mojolicious::Controller - Controller base class
345              
346             =head1 SYNOPSIS
347              
348             # Controller
349             package MyApp::Controller::Foo;
350             use Mojo::Base 'Mojolicious::Controller', -signatures;
351              
352             # Action
353             sub bar ($self) {
354             my $name = $self->param('name');
355             $self->res->headers->cache_control('max-age=1, no-cache');
356             $self->render(json => {hello => $name});
357             }
358              
359             =head1 DESCRIPTION
360              
361             L is the base class for your L controllers. It is also the default controller
362             class unless you set L.
363              
364             =head1 ATTRIBUTES
365              
366             L implements the following attributes.
367              
368             =head2 app
369              
370             my $app = $c->app;
371             $c = $c->app(Mojolicious->new);
372              
373             A reference back to the application that dispatched to this controller, usually a L object. Note that this
374             attribute is weakened.
375              
376             # Use application logger
377             $c->app->log->debug('Hello Mojo');
378              
379             # Generate path
380             my $path = $c->app->home->child('templates', 'foo', 'bar.html.ep');
381              
382             =head2 match
383              
384             my $m = $c->match;
385             $c = $c->match(Mojolicious::Routes::Match->new);
386              
387             Router results for the current request, defaults to a L object.
388              
389             # Introspect
390             my $name = $c->match->endpoint->name;
391             my $foo = $c->match->endpoint->pattern->defaults->{foo};
392             my $action = $c->match->stack->[-1]{action};
393              
394             =head2 tx
395              
396             my $tx = $c->tx;
397             $c = $c->tx(Mojo::Transaction::HTTP->new);
398              
399             The transaction that is currently being processed, usually a L or
400             L object. Note that this attribute is weakened. So the object needs to be referenced
401             elsewhere as well when you're performing non-blocking operations and the underlying connection might get closed early.
402              
403             # Check peer information
404             my $address = $c->tx->remote_address;
405             my $port = $c->tx->remote_port;
406              
407             # Increase size limit for WebSocket messages to 16MiB
408             $c->tx->max_websocket_size(16777216) if $c->tx->is_websocket;
409              
410             # Perform non-blocking operation without knowing the connection status
411             my $tx = $c->tx;
412             Mojo::IOLoop->timer(2 => sub {
413             $c->app->log->debug($tx->is_finished ? 'Finished' : 'In progress');
414             });
415              
416             =head1 METHODS
417              
418             L inherits all methods from L and implements the following new ones.
419              
420             =head2 continue
421              
422             $c->continue;
423              
424             Continue dispatch chain from an intermediate destination with L.
425              
426             =head2 cookie
427              
428             my $value = $c->cookie('foo');
429             $c = $c->cookie(foo => 'bar');
430             $c = $c->cookie(foo => 'bar', {path => '/'});
431              
432             Access request cookie values and create new response cookies. If there are multiple values sharing the same name, and
433             you want to access more than just the last one, you can use L.
434              
435             # Create response cookie with domain and expiration date
436             $c->cookie(user => 'sri', {domain => 'example.com', expires => time + 60});
437              
438             # Create secure response cookie
439             $c->cookie(secret => 'I <3 Mojolicious', {secure => 1, httponly => 1});
440              
441             =head2 encrypted_cookie
442              
443             my $value = $c->encrypted_cookie('foo');
444             $c = $c->encrypted_cookie(foo => 'bar');
445             $c = $c->encrypted_cookie(foo => 'bar', {path => '/'});
446              
447             Access encrypted request cookie values and create new encrypted response cookies. If there are multiple values sharing
448             the same name, and you want to access more than just the last one, you can use L. Cookies
449             are encrypted with ChaCha20-Poly1305, to prevent tampering, and the ones failing decryption will be automatically
450             discarded.
451              
452             =head2 every_cookie
453              
454             my $values = $c->every_cookie('foo');
455              
456             Similar to L, but returns all request cookie values sharing the same name as an array reference.
457              
458             $ Get first cookie value
459             my $first = $c->every_cookie('foo')->[0];
460              
461             =head2 every_encrypted_cookie
462              
463             my $values = $c->every_encrypted_cookie('foo');
464              
465             Similar to L, but returns all encrypted request cookie values sharing the same name as an array
466             reference.
467              
468             # Get first encrypted cookie value
469             my $first = $c->every_encrypted_cookie('foo')->[0];
470              
471             =head2 every_param
472              
473             my $values = $c->every_param('foo');
474              
475             Similar to L, but returns all values sharing the same name as an array reference.
476              
477             # Get first value
478             my $first = $c->every_param('foo')->[0];
479              
480             =head2 every_signed_cookie
481              
482             my $values = $c->every_signed_cookie('foo');
483              
484             Similar to L, but returns all signed request cookie values sharing the same name as an array
485             reference.
486              
487             # Get first signed cookie value
488             my $first = $c->every_signed_cookie('foo')->[0];
489              
490             =head2 finish
491              
492             $c = $c->finish;
493             $c = $c->finish(1000);
494             $c = $c->finish(1003 => 'Cannot accept data!');
495             $c = $c->finish('Bye!');
496              
497             Close WebSocket connection or long poll stream gracefully. This method will automatically respond to WebSocket
498             handshake requests with a C<101> response status, to establish the WebSocket connection.
499              
500             =head2 helpers
501              
502             my $helpers = $c->helpers;
503              
504             Return a proxy object containing the current controller object and on which helpers provided by L can be
505             called. This includes all helpers from L and L.
506              
507             # Make sure to use the "title" helper and not the controller method
508             $c->helpers->title('Welcome!');
509              
510             # Use a nested helper instead of the "reply" controller method
511             $c->helpers->reply->not_found;
512              
513             =head2 on
514              
515             my $cb = $c->on(finish => sub {...});
516              
517             Subscribe to events of L, which is usually a L or L
518             object. This method will automatically respond to WebSocket handshake requests with a C<101> response status, to
519             establish the WebSocket connection.
520              
521             # Do something after the transaction has been finished
522             $c->on(finish => sub ($c) {
523             $c->app->log->debug('All data has been sent');
524             });
525              
526             # Receive WebSocket message
527             $c->on(message => sub ($c, $msg) {
528             $c->app->log->debug("Message: $msg");
529             });
530              
531             # Receive JSON object via WebSocket message
532             $c->on(json => sub ($c, $hash) {
533             $c->app->log->debug("Test: $hash->{test}");
534             });
535              
536             # Receive WebSocket "Binary" message
537             $c->on(binary => sub ($c, $bytes) {
538             my $len = length $bytes;
539             $c->app->log->debug("Received $len bytes");
540             });
541              
542             =head2 param
543              
544             my $value = $c->param('foo');
545             $c = $c->param(foo => 'ba;r');
546             $c = $c->param(foo => 'ba;r', 'baz');
547             $c = $c->param(foo => ['ba;r', 'baz']);
548              
549             Access route placeholder values that are not reserved stash values, file uploads as well as C and C
550             parameters extracted from the query string and C or C message
551             body, in that order. If there are multiple values sharing the same name, and you want to access more than just the last
552             one, you can use L. Parts of the request body need to be loaded into memory to parse C
553             parameters, so you have to make sure it is not excessively large. There's a 16MiB limit for requests by default.
554              
555             # Get first value
556             my $first = $c->every_param('foo')->[0];
557              
558             For more control you can also access request information directly.
559              
560             # Only GET parameters
561             my $foo = $c->req->query_params->param('foo');
562              
563             # Only POST parameters
564             my $foo = $c->req->body_params->param('foo');
565              
566             # Only GET and POST parameters
567             my $foo = $c->req->param('foo');
568              
569             # Only file uploads
570             my $foo = $c->req->upload('foo');
571              
572             =head2 render
573              
574             my $bool = $c->render;
575             my $bool = $c->render(foo => 'bar', baz => 23);
576             my $bool = $c->render(template => 'foo/index');
577             my $bool = $c->render(template => 'index', format => 'html');
578             my $bool = $c->render(data => $bytes);
579             my $bool = $c->render(text => 'Hello!');
580             my $bool = $c->render(json => {foo => 'bar'});
581             my $bool = $c->render(handler => 'something');
582             my $bool = $c->render('foo/index');
583              
584             Render content with L and emit hooks L as well as
585             L, or dies if no response could be generated. All additional key/value pairs get merged into
586             the L.
587              
588             # Render characters
589             $c->render(text => 'I ♥ Mojolicious!');
590              
591             # Render characters (alternative)
592             $c->stash(text => 'I ♥ Mojolicious!')->render;
593              
594             # Render binary data
595             use Mojo::JSON qw(encode_json);
596             $c->render(data => encode_json({test => 'I ♥ Mojolicious!'}));
597              
598             # Render JSON
599             $c->render(json => {test => 'I ♥ Mojolicious!'});
600              
601             # Render inline template
602             $c->render(inline => '<%= 1 + 1 %>');
603              
604             # Render template "foo/bar.html.ep"
605             $c->render(template => 'foo/bar', format => 'html', handler => 'ep');
606              
607             # Render template "test.*.*" with arbitrary values "foo" and "bar"
608             $c->render(template => 'test', foo => 'test', bar => 23);
609              
610             # Render template "test.xml.*"
611             $c->render(template => 'test', format => 'xml');
612              
613             # Render template "test.xml.*" (alternative)
614             $c->render('test', format => 'xml');
615              
616             =head2 render_later
617              
618             $c = $c->render_later;
619              
620             Disable automatic rendering to delay response generation, only necessary if automatic rendering would result in a
621             response.
622              
623             # Delayed rendering
624             $c->render_later;
625             Mojo::IOLoop->timer(2 => sub { $c->render(text => 'Delayed by 2 seconds!') });
626              
627             =head2 render_maybe
628              
629             my $bool = $c->render_maybe;
630             my $bool = $c->render_maybe(foo => 'bar', baz => 23);
631             my $bool = $c->render_maybe('foo/index', format => 'html');
632              
633             Try to render content, but do not call Lnot_found"> if no response
634             could be generated, all arguments get localized automatically and are only available during this render operation,
635             takes the same arguments as L.
636              
637             # Render template "index_local" only if it exists
638             $c->render_maybe('index_local') or $c->render('index');
639              
640             =head2 render_to_string
641              
642             my $output = $c->render_to_string('foo/index', format => 'pdf');
643              
644             Try to render content and return it wrapped in a L object or return C, all arguments get
645             localized automatically and are only available during this render operation, takes the same arguments as L.
646              
647             # Render inline template
648             my $two = $c->render_to_string(inline => '<%= 1 + 1 %>');
649              
650             =head2 rendered
651              
652             $c = $c->rendered;
653             $c = $c->rendered(302);
654              
655             Finalize response and emit hook L, defaults to using a C<200> response code.
656              
657             # Custom response
658             $c->res->headers->content_type('text/plain');
659             $c->res->body('Hello World!');
660             $c->rendered(200);
661              
662             =head2 req
663              
664             my $req = $c->req;
665              
666             Get L object from L.
667              
668             # Longer version
669             my $req = $c->tx->req;
670              
671             # Extract request information
672             my $id = $c->req->request_id;
673             my $method = $c->req->method;
674             my $url = $c->req->url->to_abs;
675             my $info = $c->req->url->to_abs->userinfo;
676             my $host = $c->req->url->to_abs->host;
677             my $agent = $c->req->headers->user_agent;
678             my $custom = $c->req->headers->header('Custom-Header');
679             my $bytes = $c->req->body;
680             my $str = $c->req->text;
681             my $hash = $c->req->params->to_hash;
682             my $all = $c->req->uploads;
683             my $value = $c->req->json;
684             my $foo = $c->req->json('/23/foo');
685             my $dom = $c->req->dom;
686             my $bar = $c->req->dom('div.bar')->first->text;
687              
688             =head2 res
689              
690             my $res = $c->res;
691              
692             Get L object from L.
693              
694             # Longer version
695             my $res = $c->tx->res;
696              
697             # Force file download by setting a response header
698             $c->res->headers->content_disposition('attachment; filename=foo.png;');
699              
700             # Use a custom response header
701             $c->res->headers->header('Custom-Header' => 'whatever');
702              
703             # Make sure response is cached correctly
704             $c->res->headers->cache_control('public, max-age=300');
705             $c->res->headers->append(Vary => 'Accept-Encoding');
706              
707             =head2 send
708              
709             $c = $c->send({binary => $bytes});
710             $c = $c->send({text => $bytes});
711             $c = $c->send({json => {test => [1, 2, 3]}});
712             $c = $c->send([$fin, $rsv1, $rsv2, $rsv3, $op, $payload]);
713             $c = $c->send($chars);
714             $c = $c->send($chars => sub ($c) {...});
715              
716             Send message or frame non-blocking via WebSocket, the optional drain callback will be executed once all data has been
717             written. This method will automatically respond to WebSocket handshake requests with a C<101> response status, to
718             establish the WebSocket connection.
719              
720             # Send "Text" message
721             $c->send('I ♥ Mojolicious!');
722              
723             # Send JSON object as "Text" message
724             $c->send({json => {test => 'I ♥ Mojolicious!'}});
725              
726             # Send JSON object as "Binary" message
727             use Mojo::JSON qw(encode_json);
728             $c->send({binary => encode_json({test => 'I ♥ Mojolicious!'})});
729              
730             # Send "Ping" frame
731             use Mojo::WebSocket qw(WS_PING);
732             $c->send([1, 0, 0, 0, WS_PING, 'Hello World!']);
733              
734             # Make sure the first message has been written before continuing
735             $c->send('First message!' => sub ($c) { $c->send('Second message!') });
736              
737             For mostly idle WebSockets you might also want to increase the inactivity timeout with
738             L, which usually defaults to C<30> seconds.
739              
740             # Increase inactivity timeout for connection to 300 seconds
741             $c->inactivity_timeout(300);
742              
743             =head2 session
744              
745             my $session = $c->session;
746             my $foo = $c->session('foo');
747             $c = $c->session({foo => 'bar'});
748             $c = $c->session(foo => 'bar');
749              
750             Persistent data storage for the next few requests, all session data gets serialized with L and stored
751             Base64 encoded in HMAC-SHA256 signed cookies, to prevent tampering. Note that cookies usually have a C<4096> byte
752             (4KiB) limit, depending on browser.
753              
754             # Manipulate session
755             $c->session->{foo} = 'bar';
756             my $foo = $c->session->{foo};
757             delete $c->session->{foo};
758              
759             # Expiration date in seconds from now (persists between requests)
760             $c->session(expiration => 604800);
761              
762             # Expiration date as absolute epoch time (only valid for one request)
763             $c->session(expires => time + 604800);
764              
765             # Delete whole session by setting an expiration date in the past
766             $c->session(expires => 1);
767              
768             =head2 signed_cookie
769              
770             my $value = $c->signed_cookie('foo');
771             $c = $c->signed_cookie(foo => 'bar');
772             $c = $c->signed_cookie(foo => 'bar', {path => '/'});
773              
774             Access signed request cookie values and create new signed response cookies. If there are multiple values sharing the
775             same name, and you want to access more than just the last one, you can use L. Cookies are
776             cryptographically signed with HMAC-SHA256, to prevent tampering, and the ones failing signature verification will be
777             automatically discarded.
778              
779             =head2 stash
780              
781             my $hash = $c->stash;
782             my $foo = $c->stash('foo');
783             $c = $c->stash({foo => 'bar', baz => 23});
784             $c = $c->stash(foo => 'bar', baz => 23);
785              
786             Non-persistent data storage and exchange for the current request, application wide default values can be set with
787             L. Some stash values have a special meaning and are reserved, the full list is currently
788             C, C, C, C, C, C, C, C, C, C, C,
789             C, C, C, C