source: main/trunk/greenstone2/perllib/cpan/Mojolicious/Controller.pm@ 32205

Last change on this file since 32205 was 32205, checked in by ak19, 6 years ago

First set of commits to do with implementing the new 'paged_html' output option of PDFPlugin that uses using xpdftools' new pdftohtml. So far tested only on Linux (64 bit), but things work there so I'm optimistically committing the changes since they work. 2. Committing the pre-built Linux binaries of XPDFtools for both 32 and 64 bit built by the XPDF group. 2. To use the correct bitness variant of xpdftools, setup.bash now exports the BITNESS env var, consulted by gsConvert.pl. 3. All the perl code changes to do with using xpdf tools' pdftohtml to generate paged_html and feed it in the desired form into GS(3): gsConvert.pl, PDFPlugin.pm and its parent ConvertBinaryPFile.pm have been modified to make it all work. xpdftools' pdftohtml generates a folder containing an html file and a screenshot for each page in a PDF (as well as an index.html linking to each page's html). However, we want a single html file that contains each individual 'page' html's content in a div, and need to do some further HTML style, attribute and structure modifications to massage the xpdftool output to what we want for GS. In order to parse and manipulate the HTML 'DOM' to do this, we're using the Mojo::DOM package that Dr Bainbridge found and which he's compiled up. Mojo::DOM is therefore also committed in this revision. Some further changes and some display fixes are required, but need to check with the others about that.

File size: 31.0 KB
Line 
1package Mojolicious::Controller;
2use Mojo::Base -base;
3
4# No imports, for security reasons!
5use Carp ();
6use Mojo::ByteStream;
7use Mojo::URL;
8use Mojo::Util;
9use Mojolicious::Routes::Match;
10use Scalar::Util ();
11
12has [qw(app tx)];
13has match =>
14 sub { Mojolicious::Routes::Match->new(root => shift->app->routes) };
15
16# Reserved stash values
17my %RESERVED = map { $_ => 1 } (
18 qw(action app cb controller data extends format handler inline json layout),
19 qw(namespace path status template text variant)
20);
21
22sub AUTOLOAD {
23 my $self = shift;
24
25 my ($package, $method) = our $AUTOLOAD =~ /^(.+)::(.+)$/;
26 Carp::croak "Undefined subroutine &${package}::$method called"
27 unless Scalar::Util::blessed $self && $self->isa(__PACKAGE__);
28
29 # Call helper with current controller
30 Carp::croak qq{Can't locate object method "$method" via package "$package"}
31 unless my $helper = $self->app->renderer->get_helper($method);
32 return $self->$helper(@_);
33}
34
35sub continue { $_[0]->app->routes->continue($_[0]) }
36
37sub cookie {
38 my ($self, $name) = (shift, shift);
39
40 # Response cookie
41 if (@_) {
42
43 # Cookie too big
44 my $cookie = {name => $name, value => shift, %{shift || {}}};
45 $self->app->log->error(qq{Cookie "$name" is bigger than 4096 bytes})
46 if length $cookie->{value} > 4096;
47
48 $self->res->cookies($cookie);
49 return $self;
50 }
51
52 # Request cookies
53 return undef unless my $cookie = $self->req->cookie($name);
54 return $cookie->value;
55}
56
57sub every_cookie {
58 [map { $_->value } @{shift->req->every_cookie(shift)}];
59}
60
61sub every_param {
62 my ($self, $name) = @_;
63
64 # Captured unreserved values
65 my $captures = $self->stash->{'mojo.captures'} ||= {};
66 if (!$RESERVED{$name} && exists $captures->{$name}) {
67 my $value = $captures->{$name};
68 return ref $value eq 'ARRAY' ? $value : [$value];
69 }
70
71 # Uploads or param values
72 my $req = $self->req;
73 my $uploads = $req->every_upload($name);
74 return @$uploads ? $uploads : $req->every_param($name);
75}
76
77sub every_signed_cookie {
78 my ($self, $name) = @_;
79
80 my $secrets = $self->app->secrets;
81 my @results;
82 for my $value (@{$self->every_cookie($name)}) {
83
84 # Check signature with rotating secrets
85 if ($value =~ s/--([^\-]+)$//) {
86 my $signature = $1;
87
88 my $valid;
89 for my $secret (@$secrets) {
90 my $check = Mojo::Util::hmac_sha1_sum($value, $secret);
91 ++$valid and last if Mojo::Util::secure_compare($signature, $check);
92 }
93 if ($valid) { push @results, $value }
94
95 else { $self->app->log->debug(qq{Cookie "$name" has a bad signature}) }
96 }
97
98 else { $self->app->log->debug(qq{Cookie "$name" is not signed}) }
99 }
100
101 return \@results;
102}
103
104sub finish {
105 my $self = shift;
106
107 # WebSocket
108 my $tx = $self->tx || Carp::croak 'Connection already closed';
109 $tx->finish(@_) and return $tx->established ? $self : $self->rendered(101)
110 if $tx->is_websocket;
111
112 # Chunked stream
113 return @_ ? $self->write_chunk(@_)->write_chunk('') : $self->write_chunk('')
114 if $tx->res->content->is_chunked;
115
116 # Normal stream
117 return @_ ? $self->write(@_)->write('') : $self->write('');
118}
119
120sub flash {
121 my $self = shift;
122
123 # Check old flash
124 my $session = $self->session;
125 return $session->{flash} ? $session->{flash}{$_[0]} : undef
126 if @_ == 1 && !ref $_[0];
127
128 # Initialize new flash and merge values
129 my $values = ref $_[0] ? $_[0] : {@_};
130 @{$session->{new_flash} ||= {}}{keys %$values} = values %$values;
131
132 return $self;
133}
134
135sub helpers { $_[0]->app->renderer->get_helper('')->($_[0]) }
136
137sub on {
138 my ($self, $name, $cb) = @_;
139 my $tx = $self->tx || Carp::croak 'Connection already closed';
140 $self->rendered(101) if $tx->is_websocket && !$tx->established;
141 return $tx->on($name => sub { shift; $self->$cb(@_) });
142}
143
144sub param {
145 my ($self, $name) = (shift, shift);
146 return $self->every_param($name)->[-1] unless @_;
147 $self->stash->{'mojo.captures'}{$name} = @_ > 1 ? [@_] : $_[0];
148 return $self;
149}
150
151sub redirect_to {
152 my $self = shift;
153
154 # Don't override 3xx status
155 my $res = $self->res;
156 $res->headers->location($self->url_for(@_));
157 return $self->rendered($res->is_redirect ? () : 302);
158}
159
160sub render {
161 my $self = shift;
162
163 # Template may be first argument
164 my ($template, $args) = (@_ % 2 ? shift : undef, {@_});
165 $args->{template} = $template if $template;
166 my $app = $self->app;
167 my $plugins = $app->plugins->emit_hook(before_render => $self, $args);
168
169 # Localize "extends" and "layout" to allow argument overrides
170 my ($maybe, $ts) = @{$args}{'mojo.maybe', 'mojo.string'};
171 my $stash = $self->stash;
172 local $stash->{layout} = $stash->{layout} if exists $stash->{layout};
173 local $stash->{extends} = $stash->{extends} if exists $stash->{extends};
174
175 # Rendering to string
176 local @{$stash}{keys %$args} if $ts || $maybe;
177 delete @{$stash}{qw(layout extends)} if $ts;
178
179 # All other arguments just become part of the stash
180 @$stash{keys %$args} = values %$args;
181 my ($output, $format) = $app->renderer->render($self, $args);
182
183 # Maybe no 404
184 return defined $output ? Mojo::ByteStream->new($output) : undef if $ts;
185 return $maybe ? undef : !$self->helpers->reply->not_found
186 unless defined $output;
187
188 $plugins->emit_hook(after_render => $self, \$output, $format);
189 my $headers = $self->res->body($output)->headers;
190 $headers->content_type($app->types->type($format) || 'text/plain')
191 unless $headers->content_type;
192 return !!$self->rendered($stash->{status});
193}
194
195sub render_later { shift->stash('mojo.rendered' => 1) }
196
197sub render_maybe { shift->render(@_, 'mojo.maybe' => 1) }
198
199sub render_to_string { shift->render(@_, 'mojo.string' => 1) }
200
201sub rendered {
202 my ($self, $status) = @_;
203
204 # Make sure we have a status
205 my $res = $self->res;
206 $res->code($status || 200) if $status || !$res->code;
207
208 # Finish transaction
209 my $stash = $self->stash;
210 if (!$stash->{'mojo.finished'} && ++$stash->{'mojo.finished'}) {
211
212 # Disable auto rendering and stop timer
213 my $app = $self->render_later->app;
214 my $timing = $self->helpers->timing;
215 if (defined(my $elapsed = $timing->elapsed('mojo.timer'))) {
216 my $rps = $timing->rps($elapsed) // '??';
217 my $code = $res->code;
218 my $msg = $res->message || $res->default_message($code);
219 $app->log->debug("$code $msg (${elapsed}s, $rps/s)");
220 }
221
222 $app->plugins->emit_hook_reverse(after_dispatch => $self);
223 $app->sessions->store($self);
224 }
225 $self->tx->resume;
226 return $self;
227}
228
229sub req { (shift->tx || Carp::croak 'Connection already closed')->req }
230sub res { (shift->tx || Carp::croak 'Connection already closed')->res }
231
232sub respond_to {
233 my ($self, $args) = (shift, ref $_[0] ? $_[0] : {@_});
234
235 # Find target
236 my $target;
237 my $renderer = $self->app->renderer;
238 my @formats = @{$renderer->accepts($self)};
239 for my $format (@formats ? @formats : ($renderer->default_format)) {
240 next unless $target = $args->{$format};
241 $self->stash->{format} = $format;
242 last;
243 }
244
245 # Fallback
246 unless ($target) {
247 return $self->rendered(204) unless $target = $args->{any};
248 delete $self->stash->{format};
249 }
250
251 # Dispatch
252 ref $target eq 'CODE' ? $target->($self) : $self->render(%$target);
253
254 return $self;
255}
256
257sub send {
258 my ($self, $msg, $cb) = @_;
259 my $tx = $self->tx || Carp::croak 'Connection already closed';
260 Carp::croak 'No WebSocket connection to send message to'
261 unless $tx->is_websocket;
262 $tx->send($msg, $cb ? sub { shift; $self->$cb(@_) } : ());
263 return $tx->established ? $self : $self->rendered(101);
264}
265
266sub session {
267 my $self = shift;
268
269 my $stash = $self->stash;
270 $self->app->sessions->load($self)
271 unless exists $stash->{'mojo.active_session'};
272
273 # Hash
274 my $session = $stash->{'mojo.session'} ||= {};
275 return $session unless @_;
276
277 # Get
278 return $session->{$_[0]} unless @_ > 1 || ref $_[0];
279
280 # Set
281 my $values = ref $_[0] ? $_[0] : {@_};
282 @$session{keys %$values} = values %$values;
283
284 return $self;
285}
286
287sub signed_cookie {
288 my ($self, $name, $value, $options) = @_;
289
290 # Request cookie
291 return $self->every_signed_cookie($name)->[-1] unless defined $value;
292
293 # Response cookie
294 my $checksum = Mojo::Util::hmac_sha1_sum($value, $self->app->secrets->[0]);
295 return $self->cookie($name, "$value--$checksum", $options);
296}
297
298sub stash { Mojo::Util::_stash(stash => @_) }
299
300sub url_for {
301 my ($self, $target) = (shift, shift // '');
302
303 # Absolute URL
304 return $target if Scalar::Util::blessed $target && $target->isa('Mojo::URL');
305 return Mojo::URL->new($target) if $target =~ m!^(?:[^:/?#]+:|//|#)!;
306
307 # Base
308 my $url = Mojo::URL->new;
309 my $req = $self->req;
310 my $base = $url->base($req->url->base->clone)->base->userinfo(undef);
311
312 # Relative URL
313 my $path = $url->path;
314 if ($target =~ m!^/!) {
315 if (defined(my $prefix = $self->stash->{path})) {
316 my $real = $req->url->path->to_route;
317 $real =~ s!/?\Q$prefix\E$!$target!;
318 $target = $real;
319 }
320 $url->parse($target);
321 }
322
323 # Route
324 else {
325 my $generated = $self->match->path_for($target, @_);
326 $path->parse($generated->{path}) if $generated->{path};
327 $base->scheme($base->protocol eq 'https' ? 'wss' : 'ws')
328 if $generated->{websocket};
329 }
330
331 # Make path absolute
332 my $base_path = $base->path;
333 unshift @{$path->parts}, @{$base_path->parts};
334 $base_path->parts([])->trailing_slash(0);
335
336 return $url;
337}
338
339sub validation {
340 my $self = shift;
341
342 my $stash = $self->stash;
343 return $stash->{'mojo.validation'} if $stash->{'mojo.validation'};
344
345 my $req = $self->req;
346 my $token = $self->session->{csrf_token};
347 my $header = $req->headers->header('X-CSRF-Token');
348 my $hash = $req->params->to_hash;
349 $hash->{csrf_token} //= $header if $token && $header;
350 $hash->{$_} = $req->every_upload($_) for map { $_->name } @{$req->uploads};
351 my $v = $self->app->validator->validation->input($hash);
352 return $stash->{'mojo.validation'} = $v->csrf_token($token);
353}
354
355sub write {
356 my ($self, $chunk, $cb) = @_;
357 $self->res->content->write($chunk, $cb ? sub { shift; $self->$cb(@_) } : ());
358 return $self->rendered;
359}
360
361sub write_chunk {
362 my ($self, $chunk, $cb) = @_;
363 my $content = $self->res->content;
364 $content->write_chunk($chunk, $cb ? sub { shift; $self->$cb(@_) } : ());
365 return $self->rendered;
366}
367
3681;
369
370=encoding utf8
371
372=head1 NAME
373
374Mojolicious::Controller - Controller base class
375
376=head1 SYNOPSIS
377
378 # Controller
379 package MyApp::Controller::Foo;
380 use Mojo::Base 'Mojolicious::Controller';
381
382 # Action
383 sub bar {
384 my $self = shift;
385 my $name = $self->param('name');
386 $self->res->headers->cache_control('max-age=1, no-cache');
387 $self->render(json => {hello => $name});
388 }
389
390=head1 DESCRIPTION
391
392L<Mojolicious::Controller> is the base class for your L<Mojolicious>
393controllers. It is also the default controller class unless you set
394L<Mojolicious/"controller_class">.
395
396=head1 ATTRIBUTES
397
398L<Mojolicious::Controller> inherits all attributes from L<Mojo::Base> and
399implements the following new ones.
400
401=head2 app
402
403 my $app = $c->app;
404 $c = $c->app(Mojolicious->new);
405
406A reference back to the application that dispatched to this controller, usually
407a L<Mojolicious> object.
408
409 # Use application logger
410 $c->app->log->debug('Hello Mojo');
411
412 # Generate path
413 my $path = $c->app->home->child('templates', 'foo', 'bar.html.ep');
414
415=head2 match
416
417 my $m = $c->match;
418 $c = $c->match(Mojolicious::Routes::Match->new);
419
420Router results for the current request, defaults to a
421L<Mojolicious::Routes::Match> object.
422
423 # Introspect
424 my $name = $c->match->endpoint->name;
425 my $foo = $c->match->endpoint->pattern->defaults->{foo};
426 my $action = $c->match->stack->[-1]{action};
427
428=head2 tx
429
430 my $tx = $c->tx;
431 $c = $c->tx(Mojo::Transaction::HTTP->new);
432
433The transaction that is currently being processed, usually a
434L<Mojo::Transaction::HTTP> or L<Mojo::Transaction::WebSocket> object. Note that
435this reference is usually weakened, so the object needs to be referenced
436elsewhere as well when you're performing non-blocking operations and the
437underlying connection might get closed early.
438
439 # Check peer information
440 my $address = $c->tx->remote_address;
441 my $port = $c->tx->remote_port;
442
443 # Increase size limit for WebSocket messages to 16MiB
444 $c->tx->max_websocket_size(16777216) if $c->tx->is_websocket;
445
446 # Perform non-blocking operation without knowing the connection status
447 my $tx = $c->tx;
448 Mojo::IOLoop->timer(2 => sub {
449 $c->app->log->debug($tx->is_finished ? 'Finished' : 'In progress');
450 });
451
452=head1 METHODS
453
454L<Mojolicious::Controller> inherits all methods from L<Mojo::Base> and
455implements the following new ones.
456
457=head2 continue
458
459 $c->continue;
460
461Continue dispatch chain from an intermediate destination with
462L<Mojolicious::Routes/"continue">.
463
464=head2 cookie
465
466 my $value = $c->cookie('foo');
467 $c = $c->cookie(foo => 'bar');
468 $c = $c->cookie(foo => 'bar', {path => '/'});
469
470Access request cookie values and create new response cookies. If there are
471multiple values sharing the same name, and you want to access more than just
472the last one, you can use L</"every_cookie">.
473
474 # Create response cookie with domain and expiration date
475 $c->cookie(user => 'sri', {domain => 'example.com', expires => time + 60});
476
477 # Create secure response cookie
478 $c->cookie(secret => 'I <3 Mojolicious', {secure => 1, httponly => 1});
479
480=head2 every_cookie
481
482 my $values = $c->every_cookie('foo');
483
484Similar to L</"cookie">, but returns all request cookie values sharing the same
485name as an array reference.
486
487 $ Get first cookie value
488 my $first = $c->every_cookie('foo')->[0];
489
490=head2 every_param
491
492 my $values = $c->every_param('foo');
493
494Similar to L</"param">, but returns all values sharing the same name as an
495array reference.
496
497 # Get first value
498 my $first = $c->every_param('foo')->[0];
499
500=head2 every_signed_cookie
501
502 my $values = $c->every_signed_cookie('foo');
503
504Similar to L</"signed_cookie">, but returns all signed request cookie values
505sharing the same name as an array reference.
506
507 # Get first signed cookie value
508 my $first = $c->every_signed_cookie('foo')->[0];
509
510=head2 finish
511
512 $c = $c->finish;
513 $c = $c->finish(1000);
514 $c = $c->finish(1003 => 'Cannot accept data!');
515 $c = $c->finish('Bye!');
516
517Close WebSocket connection or long poll stream gracefully. This method will
518automatically respond to WebSocket handshake requests with a C<101> response
519status, to establish the WebSocket connection.
520
521=head2 flash
522
523 my $foo = $c->flash('foo');
524 $c = $c->flash({foo => 'bar'});
525 $c = $c->flash(foo => 'bar');
526
527Data storage persistent only for the next request, stored in the L</"session">.
528
529 # Show message after redirect
530 $c->flash(message => 'User created successfully!');
531 $c->redirect_to('show_user', id => 23);
532
533=head2 helpers
534
535 my $helpers = $c->helpers;
536
537Return a proxy object containing the current controller object and on which
538helpers provided by L</"app"> can be called. This includes all helpers from
539L<Mojolicious::Plugin::DefaultHelpers> and L<Mojolicious::Plugin::TagHelpers>.
540
541 # Make sure to use the "title" helper and not the controller method
542 $c->helpers->title('Welcome!');
543
544 # Use a nested helper instead of the "reply" controller method
545 $c->helpers->reply->not_found;
546
547=head2 on
548
549 my $cb = $c->on(finish => sub {...});
550
551Subscribe to events of L</"tx">, which is usually a L<Mojo::Transaction::HTTP>
552or L<Mojo::Transaction::WebSocket> object. This method will automatically
553respond to WebSocket handshake requests with a C<101> response status, to
554establish the WebSocket connection.
555
556 # Do something after the transaction has been finished
557 $c->on(finish => sub {
558 my $c = shift;
559 $c->app->log->debug('All data has been sent');
560 });
561
562 # Receive WebSocket message
563 $c->on(message => sub {
564 my ($c, $msg) = @_;
565 $c->app->log->debug("Message: $msg");
566 });
567
568 # Receive JSON object via WebSocket message
569 $c->on(json => sub {
570 my ($c, $hash) = @_;
571 $c->app->log->debug("Test: $hash->{test}");
572 });
573
574 # Receive WebSocket "Binary" message
575 $c->on(binary => sub {
576 my ($c, $bytes) = @_;
577 my $len = length $bytes;
578 $c->app->log->debug("Received $len bytes");
579 });
580
581=head2 param
582
583 my $value = $c->param('foo');
584 $c = $c->param(foo => 'ba;r');
585 $c = $c->param(foo => 'ba;r', 'baz');
586 $c = $c->param(foo => ['ba;r', 'baz']);
587
588Access route placeholder values that are not reserved stash values, file
589uploads as well as C<GET> and C<POST> parameters extracted from the query
590string and C<application/x-www-form-urlencoded> or C<multipart/form-data>
591message body, in that order. If there are multiple values sharing the same
592name, and you want to access more than just the last one, you can use
593L</"every_param">. Parts of the request body need to be loaded into memory to
594parse C<POST> parameters, so you have to make sure it is not excessively large.
595There's a 16MiB limit for requests by default.
596
597 # Get first value
598 my $first = $c->every_param('foo')->[0];
599
600For more control you can also access request information directly.
601
602 # Only GET parameters
603 my $foo = $c->req->query_params->param('foo');
604
605 # Only POST parameters
606 my $foo = $c->req->body_params->param('foo');
607
608 # Only GET and POST parameters
609 my $foo = $c->req->param('foo');
610
611 # Only file uploads
612 my $foo = $c->req->upload('foo');
613
614=head2 redirect_to
615
616 $c = $c->redirect_to('named', foo => 'bar');
617 $c = $c->redirect_to('named', {foo => 'bar'});
618 $c = $c->redirect_to('/index.html');
619 $c = $c->redirect_to('http://example.com/index.html');
620
621Prepare a C<302> (if the status code is not already C<3xx>) redirect response
622with C<Location> header, takes the same arguments as L</"url_for">.
623
624 # Moved Permanently
625 $c->res->code(301);
626 $c->redirect_to('some_route');
627
628 # Temporary Redirect
629 $c->res->code(307);
630 $c->redirect_to('some_route');
631
632=head2 render
633
634 my $bool = $c->render;
635 my $bool = $c->render(foo => 'bar', baz => 23);
636 my $bool = $c->render(template => 'foo/index');
637 my $bool = $c->render(template => 'index', format => 'html');
638 my $bool = $c->render(data => $bytes);
639 my $bool = $c->render(text => 'Hello!');
640 my $bool = $c->render(json => {foo => 'bar'});
641 my $bool = $c->render(handler => 'something');
642 my $bool = $c->render('foo/index');
643
644Render content with L<Mojolicious/"renderer"> and emit hooks
645L<Mojolicious/"before_render"> as well as L<Mojolicious/"after_render">, or
646call L<Mojolicious::Plugin::DefaultHelpers/"reply-E<gt>not_found"> if no
647response could be generated, all additional key/value pairs get merged into the
648L</"stash">.
649
650 # Render characters
651 $c->render(text => 'I ♥ Mojolicious!');
652
653 # Render characters (alternative)
654 $c->stash(text => 'I ♥ Mojolicious!')->render;
655
656 # Render binary data
657 use Mojo::JSON 'encode_json';
658 $c->render(data => encode_json({test => 'I ♥ Mojolicious!'}));
659
660 # Render JSON
661 $c->render(json => {test => 'I ♥ Mojolicious!'});
662
663 # Render inline template
664 $c->render(inline => '<%= 1 + 1 %>');
665
666 # Render template "foo/bar.html.ep"
667 $c->render(template => 'foo/bar', format => 'html', handler => 'ep');
668
669 # Render template "test.*.*" with arbitrary values "foo" and "bar"
670 $c->render(template => 'test', foo => 'test', bar => 23);
671
672 # Render template "test.xml.*"
673 $c->render(template => 'test', format => 'xml');
674
675 # Render template "test.xml.*" (alternative)
676 $c->render('test', format => 'xml');
677
678=head2 render_later
679
680 $c = $c->render_later;
681
682Disable automatic rendering to delay response generation, only necessary if
683automatic rendering would result in a response.
684
685 # Delayed rendering
686 $c->render_later;
687 Mojo::IOLoop->timer(2 => sub {
688 $c->render(text => 'Delayed by 2 seconds!');
689 });
690
691=head2 render_maybe
692
693 my $bool = $c->render_maybe;
694 my $bool = $c->render_maybe(foo => 'bar', baz => 23);
695 my $bool = $c->render_maybe('foo/index', format => 'html');
696
697Try to render content, but do not call
698L<Mojolicious::Plugin::DefaultHelpers/"reply-E<gt>not_found"> if no response
699could be generated, all arguments get localized automatically and are only
700available during this render operation, takes the same arguments as
701L</"render">.
702
703 # Render template "index_local" only if it exists
704 $c->render_maybe('index_local') or $c->render('index');
705
706=head2 render_to_string
707
708 my $output = $c->render_to_string('foo/index', format => 'pdf');
709
710Try to render content and return it wrapped in a L<Mojo::ByteStream> object or
711return C<undef>, all arguments get localized automatically and are only
712available during this render operation, takes the same arguments as
713L</"render">.
714
715 # Render inline template
716 my $two = $c->render_to_string(inline => '<%= 1 + 1 %>');
717
718=head2 rendered
719
720 $c = $c->rendered;
721 $c = $c->rendered(302);
722
723Finalize response and emit hook L<Mojolicious/"after_dispatch">, defaults to
724using a C<200> response code.
725
726 # Custom response
727 $c->res->headers->content_type('text/plain');
728 $c->res->body('Hello World!');
729 $c->rendered(200);
730
731=head2 req
732
733 my $req = $c->req;
734
735Get L<Mojo::Message::Request> object from L</"tx">.
736
737 # Longer version
738 my $req = $c->tx->req;
739
740 # Extract request information
741 my $method = $c->req->method;
742 my $url = $c->req->url->to_abs;
743 my $info = $c->req->url->to_abs->userinfo;
744 my $host = $c->req->url->to_abs->host;
745 my $agent = $c->req->headers->user_agent;
746 my $custom = $c->req->headers->header('Custom-Header');
747 my $bytes = $c->req->body;
748 my $str = $c->req->text;
749 my $hash = $c->req->params->to_hash;
750 my $all = $c->req->uploads;
751 my $value = $c->req->json;
752 my $foo = $c->req->json('/23/foo');
753 my $dom = $c->req->dom;
754 my $bar = $c->req->dom('div.bar')->first->text;
755
756=head2 res
757
758 my $res = $c->res;
759
760Get L<Mojo::Message::Response> object from L</"tx">.
761
762 # Longer version
763 my $res = $c->tx->res;
764
765 # Force file download by setting a response header
766 $c->res->headers->content_disposition('attachment; filename=foo.png;');
767
768 # Use a custom response header
769 $c->res->headers->header('Custom-Header' => 'whatever');
770
771 # Make sure response is cached correctly
772 $c->res->headers->cache_control('public, max-age=300');
773 $c->res->headers->append(Vary => 'Accept-Encoding');
774
775=head2 respond_to
776
777 $c = $c->respond_to(
778 json => {json => {message => 'Welcome!'}},
779 html => {template => 'welcome'},
780 any => sub {...}
781 );
782
783Automatically select best possible representation for resource from C<format>
784C<GET>/C<POST> parameter, C<format> stash value or C<Accept> request header,
785defaults to L<Mojolicious::Renderer/"default_format"> or rendering an empty
786C<204> response. Each representation can be handled with a callback or a hash
787reference containing arguments to be passed to L</"render">.
788
789 # Everything else than "json" and "xml" gets a 204 response
790 $c->respond_to(
791 json => sub { $c->render(json => {just => 'works'}) },
792 xml => {text => '<just>works</just>'},
793 any => {data => '', status => 204}
794 );
795
796For more advanced negotiation logic you can also use the helper
797L<Mojolicious::Plugin::DefaultHelpers/"accepts">.
798
799=head2 send
800
801 $c = $c->send({binary => $bytes});
802 $c = $c->send({text => $bytes});
803 $c = $c->send({json => {test => [1, 2, 3]}});
804 $c = $c->send([$fin, $rsv1, $rsv2, $rsv3, $op, $payload]);
805 $c = $c->send($chars);
806 $c = $c->send($chars => sub {...});
807
808Send message or frame non-blocking via WebSocket, the optional drain callback
809will be executed once all data has been written. This method will automatically
810respond to WebSocket handshake requests with a C<101> response status, to
811establish the WebSocket connection.
812
813 # Send "Text" message
814 $c->send('I ♥ Mojolicious!');
815
816 # Send JSON object as "Text" message
817 $c->send({json => {test => 'I ♥ Mojolicious!'}});
818
819 # Send JSON object as "Binary" message
820 use Mojo::JSON 'encode_json';
821 $c->send({binary => encode_json({test => 'I ♥ Mojolicious!'})});
822
823 # Send "Ping" frame
824 use Mojo::WebSocket 'WS_PING';
825 $c->send([1, 0, 0, 0, WS_PING, 'Hello World!']);
826
827 # Make sure the first message has been written before continuing
828 $c->send('First message!' => sub {
829 my $c = shift;
830 $c->send('Second message!');
831 });
832
833For mostly idle WebSockets you might also want to increase the inactivity
834timeout with L<Mojolicious::Plugin::DefaultHelpers/"inactivity_timeout">, which
835usually defaults to C<15> seconds.
836
837 # Increase inactivity timeout for connection to 300 seconds
838 $c->inactivity_timeout(300);
839
840=head2 session
841
842 my $session = $c->session;
843 my $foo = $c->session('foo');
844 $c = $c->session({foo => 'bar'});
845 $c = $c->session(foo => 'bar');
846
847Persistent data storage for the next few requests, all session data gets
848serialized with L<Mojo::JSON> and stored Base64 encoded in HMAC-SHA1 signed
849cookies, to prevent tampering. Note that cookies usually have a C<4096> byte
850(4KiB) limit, depending on browser.
851
852 # Manipulate session
853 $c->session->{foo} = 'bar';
854 my $foo = $c->session->{foo};
855 delete $c->session->{foo};
856
857 # Expiration date in seconds from now (persists between requests)
858 $c->session(expiration => 604800);
859
860 # Expiration date as absolute epoch time (only valid for one request)
861 $c->session(expires => time + 604800);
862
863 # Delete whole session by setting an expiration date in the past
864 $c->session(expires => 1);
865
866=head2 signed_cookie
867
868 my $value = $c->signed_cookie('foo');
869 $c = $c->signed_cookie(foo => 'bar');
870 $c = $c->signed_cookie(foo => 'bar', {path => '/'});
871
872Access signed request cookie values and create new signed response cookies. If
873there are multiple values sharing the same name, and you want to access more
874than just the last one, you can use L</"every_signed_cookie">. Cookies are
875cryptographically signed with HMAC-SHA1, to prevent tampering, and the ones
876failing signature verification will be automatically discarded.
877
878=head2 stash
879
880 my $hash = $c->stash;
881 my $foo = $c->stash('foo');
882 $c = $c->stash({foo => 'bar', baz => 23});
883 $c = $c->stash(foo => 'bar', baz => 23);
884
885Non-persistent data storage and exchange for the current request, application
886wide default values can be set with L<Mojolicious/"defaults">. Some stash
887values have a special meaning and are reserved, the full list is currently
888C<action>, C<app>, C<cb>, C<controller>, C<data>, C<extends>, C<format>,
889C<handler>, C<inline>, C<json>, C<layout>, C<namespace>, C<path>, C<status>,
890C<template>, C<text> and C<variant>. Note that all stash values with a
891C<mojo.*> prefix are reserved for internal use.
892
893 # Remove value
894 my $foo = delete $c->stash->{foo};
895
896 # Assign multiple values at once
897 $c->stash(foo => 'test', bar => 23);
898
899=head2 url_for
900
901 my $url = $c->url_for;
902 my $url = $c->url_for(name => 'sebastian');
903 my $url = $c->url_for({name => 'sebastian'});
904 my $url = $c->url_for('test', name => 'sebastian');
905 my $url = $c->url_for('test', {name => 'sebastian'});
906 my $url = $c->url_for('/index.html');
907 my $url = $c->url_for('//example.com/index.html');
908 my $url = $c->url_for('http://example.com/index.html');
909 my $url = $c->url_for('mailto:[email protected]');
910 my $url = $c->url_for('#whatever');
911
912Generate a portable L<Mojo::URL> object with base for a path, URL or route.
913
914 # Rebuild URL for the current route
915 $c->url_for;
916
917 # Rebuild URL for the current route, but replace the "name" placeholder value
918 $c->url_for(name => 'sebastian');
919
920 # Absolute URL for the current route
921 $c->url_for->to_abs;
922
923 # Build URL for route "test" with two placeholder values
924 $c->url_for('test', name => 'sebastian', foo => 'bar');
925
926 # "http://127.0.0.1:3000/index.html" if application was started with Morbo
927 $c->url_for('/index.html')->to_abs;
928
929 # "https://127.0.0.1:443/index.html" if application was started with Morbo
930 $c->url_for('/index.html')->to_abs->scheme('https')->port(443);
931
932 # "/index.html?foo=bar" if application is deployed under "/"
933 $c->url_for('/index.html')->query(foo => 'bar');
934
935 # "/myapp/index.html?foo=bar" if application is deployed under "/myapp"
936 $c->url_for('/index.html')->query(foo => 'bar');
937
938You can also use the helper L<Mojolicious::Plugin::DefaultHelpers/"url_with">
939to inherit query parameters from the current request.
940
941 # "/list?q=mojo&page=2" if current request was for "/list?q=mojo&page=1"
942 $c->url_with->query([page => 2]);
943
944=head2 validation
945
946 my $v = $c->validation;
947
948Get L<Mojolicious::Validator::Validation> object for current request to
949validate file uploads as well as C<GET> and C<POST> parameters extracted from
950the query string and C<application/x-www-form-urlencoded> or
951C<multipart/form-data> message body. Parts of the request body need to be loaded
952into memory to parse C<POST> parameters, so you have to make sure it is not
953excessively large. There's a 16MiB limit for requests by default.
954
955 # Validate GET/POST parameter
956 my $v = $c->validation;
957 $v->required('title', 'trim')->size(3, 50);
958 my $title = $v->param('title');
959
960 # Validate file upload
961 my $v = $c->validation;
962 $v->required('tarball')->upload->size(1, 1048576);
963 my $tarball = $v->param('tarball');
964
965=head2 write
966
967 $c = $c->write;
968 $c = $c->write('');
969 $c = $c->write($bytes);
970 $c = $c->write($bytes => sub {...});
971
972Write dynamic content non-blocking, the optional drain callback will be executed
973once all data has been written. Calling this method without a chunk of data
974will finalize the response headers and allow for dynamic content to be written
975later.
976
977 # Keep connection alive (with Content-Length header)
978 $c->res->headers->content_length(6);
979 $c->write('Hel' => sub {
980 my $c = shift;
981 $c->write('lo!');
982 });
983
984 # Close connection when finished (without Content-Length header)
985 $c->write('Hel' => sub {
986 my $c = shift;
987 $c->write('lo!' => sub {
988 my $c = shift;
989 $c->finish;
990 });
991 });
992
993You can call L</"finish"> or write an empty chunk of data at any time to end
994the stream.
995
996 HTTP/1.1 200 OK
997 Date: Sat, 13 Sep 2014 16:48:29 GMT
998 Content-Length: 6
999 Server: Mojolicious (Perl)
1000
1001 Hello!
1002
1003 HTTP/1.1 200 OK
1004 Connection: close
1005 Date: Sat, 13 Sep 2014 16:48:29 GMT
1006 Server: Mojolicious (Perl)
1007
1008 Hello!
1009
1010For Comet (long polling) you might also want to increase the inactivity timeout
1011with L<Mojolicious::Plugin::DefaultHelpers/"inactivity_timeout">, which usually
1012defaults to C<15> seconds.
1013
1014 # Increase inactivity timeout for connection to 300 seconds
1015 $c->inactivity_timeout(300);
1016
1017=head2 write_chunk
1018
1019 $c = $c->write_chunk;
1020 $c = $c->write_chunk('');
1021 $c = $c->write_chunk($bytes);
1022 $c = $c->write_chunk($bytes => sub {...});
1023
1024Write dynamic content non-blocking with chunked transfer encoding, the optional
1025drain callback will be executed once all data has been written. Calling this
1026method without a chunk of data will finalize the response headers and allow for
1027dynamic content to be written later.
1028
1029 # Make sure previous chunk has been written before continuing
1030 $c->write_chunk('H' => sub {
1031 my $c = shift;
1032 $c->write_chunk('ell' => sub {
1033 my $c = shift;
1034 $c->finish('o!');
1035 });
1036 });
1037
1038You can call L</"finish"> or write an empty chunk of data at any time to end
1039the stream.
1040
1041 HTTP/1.1 200 OK
1042 Date: Sat, 13 Sep 2014 16:48:29 GMT
1043 Transfer-Encoding: chunked
1044 Server: Mojolicious (Perl)
1045
1046 1
1047 H
1048 3
1049 ell
1050 2
1051 o!
1052 0
1053
1054=head1 AUTOLOAD
1055
1056In addition to the L</"ATTRIBUTES"> and L</"METHODS"> above you can also call
1057helpers provided by L</"app"> on L<Mojolicious::Controller> objects. This
1058includes all helpers from L<Mojolicious::Plugin::DefaultHelpers> and
1059L<Mojolicious::Plugin::TagHelpers>.
1060
1061 # Call helpers
1062 $c->layout('green');
1063 $c->title('Welcome!');
1064
1065 # Longer version
1066 $c->helpers->layout('green');
1067
1068=head1 SEE ALSO
1069
1070L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.
1071
1072=cut
Note: See TracBrowser for help on using the repository browser.