File Coverage

blib/lib/Mojolicious/Controller.pm
Criterion Covered Total %
statement 186 188 98.9
branch 93 98 94.9
condition 35 55 63.6
subroutine 112 112 100.0
pod 25 26 96.1
total 451 479 94.1


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