Newer Older
1006 lines | 28.351kb
add files
Yuki Kimoto authored on 2014-03-26
1
package Mojolicious::Controller;
2
use Mojo::Base -base;
3

            
4
# No imports, for security reasons!
5
use Carp ();
6
use Mojo::ByteStream;
7
use Mojo::Exception;
8
use Mojo::Transaction::HTTP;
9
use Mojo::URL;
10
use Mojo::Util;
11
use Mojolicious;
12
use Mojolicious::Routes::Match;
13
use Scalar::Util ();
14
use Time::HiRes  ();
15

            
16
has app => sub { Mojolicious->new };
17
has match =>
18
  sub { Mojolicious::Routes::Match->new(root => shift->app->routes) };
19
has tx => sub { Mojo::Transaction::HTTP->new };
20

            
21
# Reserved stash values
22
my %RESERVED = map { $_ => 1 } (
23
  qw(action app cb controller data extends format handler json layout),
24
  qw(namespace partial path status template text)
25
);
26

            
27
sub AUTOLOAD {
28
  my $self = shift;
29

            
30
  my ($package, $method) = our $AUTOLOAD =~ /^([\w:]+)::(\w+)$/;
31
  Carp::croak "Undefined subroutine &${package}::$method called"
32
    unless Scalar::Util::blessed $self && $self->isa(__PACKAGE__);
33

            
34
  # Call helper with current controller
35
  Carp::croak qq{Can't locate object method "$method" via package "$package"}
36
    unless my $helper = $self->app->renderer->helpers->{$method};
37
  return $self->$helper(@_);
38
}
39

            
40
sub DESTROY { }
41

            
42
sub continue { $_[0]->app->routes->continue($_[0]) }
43

            
44
sub cookie {
45
  my ($self, $name) = (shift, shift);
46

            
47
  # Response cookie
48
  if (@_) {
49

            
50
    # Cookie too big
51
    my $cookie = {name => $name, value => shift, %{shift || {}}};
52
    $self->app->log->error(qq{Cookie "$name" is bigger than 4096 bytes.})
53
      if length $cookie->{value} > 4096;
54

            
55
    $self->res->cookies($cookie);
56
    return $self;
57
  }
58

            
59
  # Request cookies
60
  return map { $_->value } $self->req->cookie($name) if wantarray;
61
  return undef unless my $cookie = $self->req->cookie($name);
62
  return $cookie->value;
63
}
64

            
65
sub finish {
66
  my $self = shift;
67

            
68
  # WebSocket
69
  my $tx = $self->tx;
70
  $tx->finish(@_) and return $self if $tx->is_websocket;
71

            
72
  # Chunked stream
73
  if ($tx->res->content->is_chunked) {
74
    $self->write_chunk(@_) if @_;
75
    return $self->write_chunk('');
76
  }
77

            
78
  # Normal stream
79
  $self->write(@_) if @_;
80
  return $self->write('');
81
}
82

            
83
sub flash {
84
  my $self = shift;
85

            
86
  # Check old flash
87
  my $session = $self->session;
88
  return $session->{flash} ? $session->{flash}{$_[0]} : undef
89
    if @_ == 1 && !ref $_[0];
90

            
91
  # Initialize new flash and merge values
92
  my $flash = $session->{new_flash} ||= {};
93
  %$flash = (%$flash, %{@_ > 1 ? {@_} : $_[0]});
94

            
95
  return $self;
96
}
97

            
98
sub on {
99
  my ($self, $name, $cb) = @_;
100
  my $tx = $self->tx;
101
  $self->rendered(101) if $tx->is_websocket;
102
  return $tx->on($name => sub { shift and $self->$cb(@_) });
103
}
104

            
105
sub param {
106
  my ($self, $name) = (shift, shift);
107

            
108
  # Multiple names
109
  return map { scalar $self->param($_) } @$name if ref $name eq 'ARRAY';
110

            
111
  # List names
112
  my $captures = $self->stash->{'mojo.captures'} ||= {};
113
  my $req = $self->req;
114
  unless (defined $name) {
115
    my %seen;
116
    my @keys = grep { !$seen{$_}++ } $req->param;
117
    push @keys, grep { !$seen{$_}++ } map { $_->name } @{$req->uploads};
118
    push @keys, grep { !$RESERVED{$_} && !$seen{$_}++ } keys %$captures;
119
    return sort @keys;
120
  }
121

            
122
  # Override values
123
  if (@_) {
124
    $captures->{$name} = @_ > 1 ? [@_] : $_[0];
125
    return $self;
126
  }
127

            
128
  # Captured unreserved values
129
  if (!$RESERVED{$name} && defined(my $value = $captures->{$name})) {
130
    return ref $value eq 'ARRAY' ? wantarray ? @$value : $$value[0] : $value;
131
  }
132

            
133
  # Uploads
134
  return $req->upload($name) if $req->upload($name);
135

            
136
  # Param values
137
  return $req->param($name);
138
}
139

            
140
sub redirect_to {
141
  my $self = shift;
142

            
143
  # Don't override 3xx status
144
  my $res = $self->res;
145
  $res->headers->location($self->url_for(@_)->to_abs);
146
  return $self->rendered($res->is_status_class(300) ? () : 302);
147
}
148

            
149
sub render {
150
  my $self = shift;
151

            
152
  # Template may be first argument
153
  my ($template, $args) = (@_ % 2 ? shift : undef, {@_});
154
  $args->{template} = $template if $template;
155
  my $maybe = delete $args->{'mojo.maybe'};
156

            
157
  # Render
158
  my $app = $self->app;
159
  my ($output, $format) = $app->renderer->render($self, $args);
160
  return defined $output ? Mojo::ByteStream->new($output) : undef
161
    if $args->{partial};
162

            
163
  # Maybe
164
  return $maybe ? undef : !$self->render_not_found unless defined $output;
165

            
166
  # Prepare response
167
  $app->plugins->emit_hook(after_render => $self, \$output, $format);
168
  my $headers = $self->res->body($output)->headers;
169
  $headers->content_type($app->types->type($format) || 'text/plain')
170
    unless $headers->content_type;
171
  return !!$self->rendered($self->stash->{status});
172
}
173

            
174
sub render_exception {
175
  my ($self, $e) = @_;
176

            
177
  my $app = $self->app;
178
  $app->log->error($e = Mojo::Exception->new($e));
179

            
180
  # Filtered stash snapshot
181
  my $stash = $self->stash;
182
  my %snapshot = map { $_ => $stash->{$_} }
183
    grep { !/^mojo\./ and defined $stash->{$_} } keys %$stash;
184

            
185
  # Render with fallbacks
186
  my $mode     = $app->mode;
187
  my $renderer = $app->renderer;
188
  my $options  = {
189
    exception => $e,
190
    snapshot  => \%snapshot,
191
    template  => "exception.$mode",
192
    format    => $stash->{format} || $renderer->default_format,
193
    handler   => undef,
194
    status    => 500
195
  };
196
  my $inline = $renderer->_bundled(
197
    $mode eq 'development' ? 'exception.development' : 'exception');
198
  return $self if $self->_fallbacks($options, 'exception', $inline);
199
  $self->_fallbacks({%$options, format => 'html'}, 'exception', $inline);
200
  return $self;
201
}
202

            
203
sub render_later { shift->stash('mojo.rendered' => 1) }
204

            
205
sub render_maybe { shift->render(@_, 'mojo.maybe' => 1) }
206

            
207
sub render_not_found {
208
  my $self = shift;
209

            
210
  # Render with fallbacks
211
  my $app      = $self->app;
212
  my $mode     = $app->mode;
213
  my $renderer = $app->renderer;
214
  my $format   = $self->stash->{format} || $renderer->default_format;
215
  my $options
216
    = {template => "not_found.$mode", format => $format, status => 404};
217
  my $inline = $renderer->_bundled(
218
    $mode eq 'development' ? 'not_found.development' : 'not_found');
219
  return $self if $self->_fallbacks($options, 'not_found', $inline);
220
  $self->_fallbacks({%$options, format => 'html'}, 'not_found', $inline);
221
  return $self;
222
}
223

            
224
sub render_static {
225
  my ($self, $file) = @_;
226
  my $app = $self->app;
227
  return !!$self->rendered if $app->static->serve($self, $file);
228
  $app->log->debug(qq{File "$file" not found, public directory missing?});
229
  return !$self->render_not_found;
230
}
231

            
232
sub rendered {
233
  my ($self, $status) = @_;
234

            
235
  # Disable auto rendering and make sure we have a status
236
  my $res = $self->render_later->res;
237
  $res->code($status || 200) if $status || !$res->code;
238

            
239
  # Finish transaction
240
  my $stash = $self->stash;
241
  unless ($stash->{'mojo.finished'}++) {
242

            
243
    # Stop timer
244
    my $app = $self->app;
245
    if (my $started = delete $stash->{'mojo.started'}) {
246
      my $elapsed = sprintf '%f',
247
        Time::HiRes::tv_interval($started, [Time::HiRes::gettimeofday()]);
248
      my $rps  = $elapsed == 0 ? '??' : sprintf '%.3f', 1 / $elapsed;
249
      my $code = $res->code;
250
      my $msg  = $res->message || $res->default_message($code);
251
      $app->log->debug("$code $msg (${elapsed}s, $rps/s).");
252
    }
253

            
254
    $app->plugins->emit_hook_reverse(after_dispatch => $self);
255
    $app->sessions->store($self);
256
  }
257
  $self->tx->resume;
258
  return $self;
259
}
260

            
261
sub req { shift->tx->req }
262
sub res { shift->tx->res }
263

            
264
sub respond_to {
265
  my $self = shift;
266
  my $args = ref $_[0] ? $_[0] : {@_};
267

            
268
  # Detect formats
269
  my $app     = $self->app;
270
  my $req     = $self->req;
271
  my @formats = @{$app->types->detect($req->headers->accept, $req->is_xhr)};
272
  my $stash   = $self->stash;
273
  unless (@formats) {
274
    my $format = $stash->{format} || $req->param('format');
275
    push @formats, $format ? $format : $app->renderer->default_format;
276
  }
277

            
278
  # Find target
279
  my $target;
280
  for my $format (@formats) {
281
    next unless $target = $args->{$format};
282
    $stash->{format} = $format;
283
    last;
284
  }
285

            
286
  # Fallback
287
  unless ($target) {
288
    return $self->rendered(204) unless $target = $args->{any};
289
    delete $stash->{format};
290
  }
291

            
292
  # Dispatch
293
  ref $target eq 'CODE' ? $target->($self) : $self->render(%$target);
294

            
295
  return $self;
296
}
297

            
298
sub send {
299
  my ($self, $msg, $cb) = @_;
300
  my $tx = $self->tx;
301
  Carp::croak 'No WebSocket connection to send message to'
302
    unless $tx->is_websocket;
303
  $tx->send($msg => sub { shift and $self->$cb(@_) if $cb });
304
  return $self->rendered(101);
305
}
306

            
307
sub session {
308
  my $self = shift;
309

            
310
  # Hash
311
  my $session = $self->stash->{'mojo.session'} ||= {};
312
  return $session unless @_;
313

            
314
  # Get
315
  return $session->{$_[0]} unless @_ > 1 || ref $_[0];
316

            
317
  # Set
318
  %$session = (%$session, %{ref $_[0] ? $_[0] : {@_}});
319

            
320
  return $self;
321
}
322

            
323
sub signed_cookie {
324
  my ($self, $name, $value, $options) = @_;
325

            
326
  # Response cookie
327
  my $secret = $self->stash->{'mojo.secret'};
328
  return $self->cookie($name,
329
    "$value--" . Mojo::Util::hmac_sha1_sum($value, $secret), $options)
330
    if defined $value;
331

            
332
  # Request cookies
333
  my @results;
334
  for my $value ($self->cookie($name)) {
335

            
336
    # Check signature
337
    if ($value =~ s/--([^\-]+)$//) {
338
      my $sig = $1;
339

            
340
      # Verified
341
      my $check = Mojo::Util::hmac_sha1_sum $value, $secret;
342
      if (Mojo::Util::secure_compare $sig, $check) { push @results, $value }
343

            
344
      # Bad cookie
345
      else {
346
        $self->app->log->debug(
347
          qq{Bad signed cookie "$name", possible hacking attempt.});
348
      }
349
    }
350

            
351
    # Not signed
352
    else { $self->app->log->debug(qq{Cookie "$name" not signed.}) }
353
  }
354

            
355
  return wantarray ? @results : $results[0];
356
}
357

            
358
sub stash {
359
  my $self = shift;
360

            
361
  # Hash
362
  my $stash = $self->{stash} ||= {};
363
  return $stash unless @_;
364

            
365
  # Get
366
  return $stash->{$_[0]} unless @_ > 1 || ref $_[0];
367

            
368
  # Set
369
  my $values = ref $_[0] ? $_[0] : {@_};
370
  for my $key (keys %$values) {
371
    $self->app->log->debug(qq{Careful, "$key" is a reserved stash value.})
372
      if $RESERVED{$key};
373
    $stash->{$key} = $values->{$key};
374
  }
375

            
376
  return $self;
377
}
378

            
379
sub url_for {
380
  my $self = shift;
381
  my $target = shift // '';
382

            
383
  # Absolute URL
384
  return $target if Scalar::Util::blessed $target && $target->isa('Mojo::URL');
385
  return Mojo::URL->new($target) if $target =~ m!^(?:[^:/?#]+:|//)!;
386

            
387
  # Base
388
  my $url  = Mojo::URL->new;
389
  my $req  = $self->req;
390
  my $base = $url->base($req->url->base->clone)->base->userinfo(undef);
391

            
392
  # Relative URL
393
  my $path = $url->path;
394
  if ($target =~ m!^/!) {
395
    if (my $prefix = $self->stash->{path}) {
396
      my $real = $req->url->path->to_route;
397
      $real =~ s!/?$prefix$!$target!;
398
      $target = $real;
399
    }
400
    $url->parse($target);
401
  }
402

            
403
  # Route
404
  else {
405
    my ($generated, $ws) = $self->match->path_for($target, @_);
406
    $path->parse($generated) if $generated;
407
    $base->scheme($base->protocol eq 'https' ? 'wss' : 'ws') if $ws;
408
  }
409

            
410
  # Make path absolute
411
  my $base_path = $base->path;
412
  unshift @{$path->parts}, @{$base_path->parts};
413
  $base_path->parts([])->trailing_slash(0);
414

            
415
  return $url;
416
}
417

            
418
sub validation {
419
  my $self = shift;
420
  return $self->stash->{'mojo.validation'}
421
    ||= $self->app->validator->validation->input($self->req->params->to_hash);
422
}
423

            
424
sub write {
425
  my ($self, $chunk, $cb) = @_;
426
  ($cb, $chunk) = ($chunk, undef) if ref $chunk eq 'CODE';
427
  my $content = $self->res->content;
428
  $content->write($chunk => sub { shift and $self->$cb(@_) if $cb });
429
  return $self->rendered;
430
}
431

            
432
sub write_chunk {
433
  my ($self, $chunk, $cb) = @_;
434
  ($cb, $chunk) = ($chunk, undef) if ref $chunk eq 'CODE';
435
  my $content = $self->res->content;
436
  $content->write_chunk($chunk => sub { shift and $self->$cb(@_) if $cb });
437
  return $self->rendered;
438
}
439

            
440
sub _fallbacks {
441
  my ($self, $options, $template, $inline) = @_;
442

            
443
  # Mode specific template
444
  return 1 if $self->render_maybe(%$options);
445

            
446
  # Normal template
447
  return 1 if $self->render_maybe(%$options, template => $template);
448

            
449
  # Inline template
450
  my $stash = $self->stash;
451
  return undef unless $stash->{format} eq 'html';
452
  delete @$stash{qw(extends layout)};
453
  return $self->render_maybe(%$options, inline => $inline, handler => 'ep');
454
}
455

            
456
1;
457

            
458
=encoding utf8
459

            
460
=head1 NAME
461

            
462
Mojolicious::Controller - Controller base class
463

            
464
=head1 SYNOPSIS
465

            
466
  # Controller
467
  package MyApp::Foo;
468
  use Mojo::Base 'Mojolicious::Controller';
469

            
470
  # Action
471
  sub bar {
472
    my $self = shift;
473
    my $name = $self->param('name');
474
    $self->res->headers->cache_control('max-age=1, no-cache');
475
    $self->render(json => {hello => $name});
476
  }
477

            
478
=head1 DESCRIPTION
479

            
480
L<Mojolicious::Controller> is the base class for your L<Mojolicious>
481
controllers. It is also the default controller class unless you set
482
L<Mojolicious/"controller_class">.
483

            
484
=head1 ATTRIBUTES
485

            
486
L<Mojolicious::Controller> inherits all attributes from L<Mojo::Base> and
487
implements the following new ones.
488

            
489
=head2 app
490

            
491
  my $app = $c->app;
492
  $c      = $c->app(Mojolicious->new);
493

            
494
A reference back to the application that dispatched to this controller,
495
defaults to a L<Mojolicious> object.
496

            
497
  # Use application logger
498
  $c->app->log->debug('Hello Mojo!');
499

            
500
  # Generate path
501
  my $path = $c->app->home->rel_file('templates/foo/bar.html.ep');
502

            
503
=head2 match
504

            
505
  my $m = $c->match;
506
  $c    = $c->match(Mojolicious::Routes::Match->new);
507

            
508
Router results for the current request, defaults to a
509
L<Mojolicious::Routes::Match> object.
510

            
511
  # Introspect
512
  my $foo = $c->match->endpoint->pattern->defaults->{foo};
513
  my $bar = $c->match->stack->[-1]{bar};
514

            
515
=head2 tx
516

            
517
  my $tx = $c->tx;
518
  $c     = $c->tx(Mojo::Transaction::HTTP->new);
519

            
520
The transaction that is currently being processed, usually a
521
L<Mojo::Transaction::HTTP> or L<Mojo::Transaction::WebSocket> object. Note
522
that this reference is usually weakened, so the object needs to be referenced
523
elsewhere as well when you're performing non-blocking operations and the
524
underlying connection might get closed early.
525

            
526
  # Check peer information
527
  my $address = $c->tx->remote_address;
528
  my $port    = $c->tx->remote_port;
529

            
530
  # Perform non-blocking operation without knowing the connection status
531
  my $tx = $c->tx;
532
  Mojo::IOLoop->timer(2 => sub {
533
    $c->app->log->debug($tx->is_finished ? 'Finished.' : 'In progress.');
534
  });
535

            
536
=head1 METHODS
537

            
538
L<Mojolicious::Controller> inherits all methods from L<Mojo::Base> and
539
implements the following new ones.
540

            
541
=head2 continue
542

            
543
  $c->continue;
544

            
545
Continue dispatch chain.
546

            
547
=head2 cookie
548

            
549
  my $value  = $c->cookie('foo');
550
  my @values = $c->cookie('foo');
551
  $c         = $c->cookie(foo => 'bar');
552
  $c         = $c->cookie(foo => 'bar', {path => '/'});
553

            
554
Access request cookie values and create new response cookies.
555

            
556
  # Create response cookie with domain and expiration date
557
  $c->cookie(user => 'sri', {domain => 'example.com', expires => time + 60});
558

            
559
=head2 finish
560

            
561
  $c = $c->finish;
562
  $c = $c->finish(1000);
563
  $c = $c->finish(1003 => 'Cannot accept data!');
564
  $c = $c->finish('Bye!');
565

            
566
Close WebSocket connection or long poll stream gracefully.
567

            
568
=head2 flash
569

            
570
  my $foo = $c->flash('foo');
571
  $c      = $c->flash({foo => 'bar'});
572
  $c      = $c->flash(foo => 'bar');
573

            
574
Data storage persistent only for the next request, stored in the
575
L</"session">.
576

            
577
  # Show message after redirect
578
  $c->flash(message => 'User created successfully!');
579
  $c->redirect_to('show_user', id => 23);
580

            
581
=head2 on
582

            
583
  my $cb = $c->on(finish => sub {...});
584

            
585
Subscribe to events of L</"tx">, which is usually a L<Mojo::Transaction::HTTP>
586
or L<Mojo::Transaction::WebSocket> object. Note that this method will
587
automatically respond to WebSocket handshake requests with a C<101> response
588
status.
589

            
590
  # Do something after the transaction has been finished
591
  $c->on(finish => sub {
592
    my $c = shift;
593
    $c->app->log->debug('We are done!');
594
  });
595

            
596
  # Receive WebSocket message
597
  $c->on(message => sub {
598
    my ($c, $msg) = @_;
599
    $c->app->log->debug("Message: $msg");
600
  });
601

            
602
  # Receive JSON object via WebSocket message
603
  $c->on(json => sub {
604
    my ($c, $hash) = @_;
605
    $c->app->log->debug("Test: $hash->{test}");
606
  });
607

            
608
  # Receive WebSocket "Binary" message
609
  $c->on(binary => sub {
610
    my ($c, $bytes) = @_;
611
    my $len = length $bytes;
612
    $c->app->log->debug("Received $len bytes.");
613
  });
614

            
615
=head2 param
616

            
617
  my @names       = $c->param;
618
  my $foo         = $c->param('foo');
619
  my @foo         = $c->param('foo');
620
  my ($foo, $bar) = $c->param(['foo', 'bar']);
621
  $c              = $c->param(foo => 'ba;r');
622
  $c              = $c->param(foo => qw(ba;r ba;z));
623

            
624
Access route placeholder values that are not reserved stash values, file
625
uploads and GET/POST parameters, in that order. Note that this method is
626
context sensitive in some cases and therefore needs to be used with care,
627
there can always be multiple values, which might have unexpected consequences.
628
Parts of the request body need to be loaded into memory to parse POST
629
parameters, so you have to make sure it is not excessively large.
630

            
631
  # List context is ambiguous and should be avoided
632
  my $hash = {foo => $self->param('foo')};
633

            
634
  # Better enforce scalar context
635
  my $hash = {foo => scalar $self->param('foo')};
636

            
637
  # The multi name form can also enforce scalar context
638
  my $hash = {foo => $self->param(['foo'])};
639

            
640
For more control you can also access request information directly.
641

            
642
  # Only GET parameters
643
  my $foo = $c->req->url->query->param('foo');
644

            
645
  # Only GET and POST parameters
646
  my $foo = $c->req->param('foo');
647

            
648
  # Only file uploads
649
  my $foo = $c->req->upload('foo');
650

            
651
=head2 redirect_to
652

            
653
  $c = $c->redirect_to('named', foo => 'bar');
654
  $c = $c->redirect_to('named', {foo => 'bar'});
655
  $c = $c->redirect_to('/perldoc');
656
  $c = $c->redirect_to('http://mojolicio.us/perldoc');
657

            
658
Prepare a C<302> redirect response, takes the same arguments as L</"url_for">.
659

            
660
  # Conditional redirect
661
  return $c->redirect_to('login') unless $c->session('user');
662

            
663
  # Moved permanently
664
  $c->res->code(301);
665
  $c->redirect_to('some_route');
666

            
667
=head2 render
668

            
669
  my $bool    = $c->render;
670
  my $bool    = $c->render(controller => 'foo', action => 'bar');
671
  my $bool    = $c->render(template => 'foo/index');
672
  my $bool    = $c->render(template => 'index', format => 'html');
673
  my $bool    = $c->render(data => $bytes);
674
  my $bool    = $c->render(text => 'Hello!');
675
  my $bool    = $c->render(json => {foo => 'bar'});
676
  my $bool    = $c->render(handler => 'something');
677
  my $bool    = $c->render('foo/index');
678
  my $output  = $c->render('foo/index', partial => 1);
679

            
680
Render content using L<Mojolicious::Renderer/"render"> and emit hook
681
L<Mojolicious/"after_render"> unless the result is C<partial>. If no template
682
is provided a default one based on controller and action or route name will be
683
generated, all additional values get merged into the L</"stash">.
684

            
685
=head2 render_exception
686

            
687
  $c = $c->render_exception('Oops!');
688
  $c = $c->render_exception(Mojo::Exception->new('Oops!'));
689

            
690
Render the exception template C<exception.$mode.$format.*> or
691
C<exception.$format.*> and set the response status code to C<500>. Also sets
692
the stash values C<exception> to a L<Mojo::Exception> object and C<snapshot>
693
to a copy of the L</"stash"> for use in the templates.
694

            
695
=head2 render_later
696

            
697
  $c = $c->render_later;
698

            
699
Disable automatic rendering to delay response generation, only necessary if
700
automatic rendering would result in a response.
701

            
702
  # Delayed rendering
703
  $c->render_later;
704
  Mojo::IOLoop->timer(2 => sub {
705
    $c->render(text => 'Delayed by 2 seconds!');
706
  });
707

            
708
=head2 render_maybe
709

            
710
  my $bool = $c->render_maybe;
711
  my $bool = $c->render_maybe(controller => 'foo', action => 'bar');
712
  my $bool = $c->render_maybe('foo/index', format => 'html');
713

            
714
Try to render content but do not call L</"render_not_found"> if no response
715
could be generated, takes the same arguments as L</"render">.
716

            
717
  # Render template "index_local" only if it exists
718
  $self->render_maybe('index_local') or $self->render('index');
719

            
720
=head2 render_not_found
721

            
722
  $c = $c->render_not_found;
723

            
724
Render the not found template C<not_found.$mode.$format.*> or
725
C<not_found.$format.*> and set the response status code to C<404>.
726

            
727
=head2 render_static
728

            
729
  my $bool = $c->render_static('images/logo.png');
730
  my $bool = $c->render_static('../lib/MyApp.pm');
731

            
732
Render a static file using L<Mojolicious::Static/"serve">, usually from the
733
C<public> directories or C<DATA> sections of your application. Note that this
734
method does not protect from traversing to parent directories.
735

            
736
=head2 rendered
737

            
738
  $c = $c->rendered;
739
  $c = $c->rendered(302);
740

            
741
Finalize response and emit hook L<Mojolicious/"after_dispatch">, defaults to
742
using a C<200> response code.
743

            
744
=head2 req
745

            
746
  my $req = $c->req;
747

            
748
Get L<Mojo::Message::Request> object from L<Mojo::Transaction/"req">.
749

            
750
  # Longer version
751
  my $req = $c->tx->req;
752

            
753
  # Extract request information
754
  my $url      = $c->req->url->to_abs;
755
  my $userinfo = $c->req->url->to_abs->userinfo;
756
  my $host     = $c->req->url->to_abs->host;
757
  my $agent    = $c->req->headers->user_agent;
758
  my $bytes    = $c->req->body;
759
  my $str      = $c->req->text;
760
  my $hash     = $c->req->json;
761
  my $foo      = $c->req->json('/23/foo');
762
  my $dom      = $c->req->dom;
763
  my $bar      = $c->req->dom('div.bar')->first->text;
764

            
765
=head2 res
766

            
767
  my $res = $c->res;
768

            
769
Get L<Mojo::Message::Response> object from L<Mojo::Transaction/"res">.
770

            
771
  # Longer version
772
  my $res = $c->tx->res;
773

            
774
  # Force file download by setting a custom response header
775
  $c->res->headers->content_disposition('attachment; filename=foo.png;');
776

            
777
=head2 respond_to
778

            
779
  $c = $c->respond_to(
780
    json => {json => {message => 'Welcome!'}},
781
    html => {template => 'welcome'},
782
    any  => sub {...}
783
  );
784

            
785
Automatically select best possible representation for resource from C<Accept>
786
request header, C<format> stash value or C<format> GET/POST parameter,
787
defaults to rendering an empty C<204> response. Since browsers often don't
788
really know what they actually want, unspecific C<Accept> request headers with
789
more than one MIME type will be ignored, unless the C<X-Requested-With> header
790
is set to the value C<XMLHttpRequest>.
791

            
792
  $c->respond_to(
793
    json => sub { $c->render(json => {just => 'works'}) },
794
    xml  => {text => '<just>works</just>'},
795
    any  => {data => '', status => 204}
796
  );
797

            
798
=head2 send
799

            
800
  $c = $c->send({binary => $bytes});
801
  $c = $c->send({text   => $bytes});
802
  $c = $c->send({json   => {test => [1, 2, 3]}});
803
  $c = $c->send([$fin, $rsv1, $rsv2, $rsv3, $op, $bytes]);
804
  $c = $c->send($chars);
805
  $c = $c->send($chars => sub {...});
806

            
807
Send message or frame non-blocking via WebSocket, the optional drain callback
808
will be invoked once all data has been written. Note that this method will
809
automatically respond to WebSocket handshake requests with a C<101> response
810
status.
811

            
812
  # Send "Text" message
813
  $c->send('I ♥ Mojolicious!');
814

            
815
  # Send JSON object as "Text" message
816
  $c->send({json => {test => 'I ♥ Mojolicious!'}});
817

            
818
  # Send JSON object as "Binary" message
819
  use Mojo::JSON 'j';
820
  $c->send({binary => j({test => 'I ♥ Mojolicious!'})});
821

            
822
  # Send "Ping" frame
823
  $c->send([1, 0, 0, 0, 9, 'Hello World!']);
824

            
825
  # Make sure previous message has been written before continuing
826
  $c->send('First message!' => sub {
827
    my $c = shift;
828
    $c->send('Second message!');
829
  });
830

            
831
For mostly idle WebSockets you might also want to increase the inactivity
832
timeout, which usually defaults to C<15> seconds.
833

            
834
  # Increase inactivity timeout for connection to 300 seconds
835
  Mojo::IOLoop->stream($c->tx->connection)->timeout(300);
836

            
837
=head2 session
838

            
839
  my $session = $c->session;
840
  my $foo     = $c->session('foo');
841
  $c          = $c->session({foo => 'bar'});
842
  $c          = $c->session(foo => 'bar');
843

            
844
Persistent data storage, all session data gets serialized with L<Mojo::JSON>
845
and stored C<Base64> encoded in C<HMAC-SHA1> signed cookies. Note that cookies
846
usually have a 4096 byte limit, depending on browser.
847

            
848
  # Manipulate session
849
  $c->session->{foo} = 'bar';
850
  my $foo = $c->session->{foo};
851
  delete $c->session->{foo};
852

            
853
  # Expiration date in seconds from now (persists between requests)
854
  $c->session(expiration => 604800);
855

            
856
  # Expiration date as absolute epoch time (only valid for one request)
857
  $c->session(expires => time + 604800);
858

            
859
  # Delete whole session by setting an expiration date in the past
860
  $c->session(expires => 1);
861

            
862
=head2 signed_cookie
863

            
864
  my $value  = $c->signed_cookie('foo');
865
  my @values = $c->signed_cookie('foo');
866
  $c         = $c->signed_cookie(foo => 'bar');
867
  $c         = $c->signed_cookie(foo => 'bar', {path => '/'});
868

            
869
Access signed request cookie values and create new signed response cookies.
870
Cookies failing C<HMAC-SHA1> signature verification will be automatically
871
discarded.
872

            
873
=head2 stash
874

            
875
  my $hash = $c->stash;
876
  my $foo  = $c->stash('foo');
877
  $c       = $c->stash({foo => 'bar'});
878
  $c       = $c->stash(foo => 'bar');
879

            
880
Non persistent data storage and exchange, application wide default values can
881
be set with L<Mojolicious/"defaults">. Some stash values have a special
882
meaning and are reserved, the full list is currently C<action>, C<app>, C<cb>,
883
C<controller>, C<data>, C<extends>, C<format>, C<handler>, C<json>, C<layout>,
884
C<namespace>, C<partial>, C<path>, C<status>, C<template> and C<text>. Note
885
that all stash values with a C<mojo.*> prefix are reserved for internal use.
886

            
887
  # Remove value
888
  my $foo = delete $c->stash->{foo};
889

            
890
=head2 url_for
891

            
892
  my $url = $c->url_for;
893
  my $url = $c->url_for(name => 'sebastian');
894
  my $url = $c->url_for({name => 'sebastian'});
895
  my $url = $c->url_for('test', name => 'sebastian');
896
  my $url = $c->url_for('test', {name => 'sebastian'});
897
  my $url = $c->url_for('/perldoc');
898
  my $url = $c->url_for('//mojolicio.us/perldoc');
899
  my $url = $c->url_for('http://mojolicio.us/perldoc');
900
  my $url = $c->url_for('mailto:sri@example.com');
901

            
902
Generate a portable L<Mojo::URL> object with base for a route, path or URL.
903

            
904
  # "http://127.0.0.1:3000/perldoc" if application has been started with Morbo
905
  $c->url_for('/perldoc')->to_abs;
906

            
907
  # "/perldoc?foo=bar" if application is deployed under "/"
908
  $c->url_for('/perldoc')->query(foo => 'bar');
909

            
910
  # "/myapp/perldoc?foo=bar" if application is deployed under "/myapp"
911
  $c->url_for('/perldoc')->query(foo => 'bar');
912

            
913
You can also use the helper L<Mojolicious::Plugin::DefaultHelpers/"url_with">
914
to inherit query parameters from the current request.
915

            
916
  # "/list?q=mojo&page=2" if current request was for "/list?q=mojo&page=1"
917
  $c->url_with->query([page => 2]);
918

            
919
=head2 validation
920

            
921
  my $validation = $c->validation;
922

            
923
Get L<Mojolicious::Validator::Validation> object for current request to
924
validate GET/POST parameters. Parts of the request body need to be loaded into
925
memory to parse POST parameters, so you have to make sure it is not
926
excessively large.
927

            
928
  my $validation = $c->validation;
929
  $validation->required('title')->size(3, 50);
930
  my $title = $validation->param('title');
931

            
932
=head2 write
933

            
934
  $c = $c->write;
935
  $c = $c->write($bytes);
936
  $c = $c->write(sub {...});
937
  $c = $c->write($bytes => sub {...});
938

            
939
Write dynamic content non-blocking, the optional drain callback will be
940
invoked once all data has been written.
941

            
942
  # Keep connection alive (with Content-Length header)
943
  $c->res->headers->content_length(6);
944
  $c->write('Hel' => sub {
945
    my $c = shift;
946
    $c->write('lo!')
947
  });
948

            
949
  # Close connection when finished (without Content-Length header)
950
  $c->write('Hel' => sub {
951
    my $c = shift;
952
    $c->write('lo!' => sub {
953
      my $c = shift;
954
      $c->finish;
955
    });
956
  });
957

            
958
For Comet (long polling) you might also want to increase the inactivity
959
timeout, which usually defaults to C<15> seconds.
960

            
961
  # Increase inactivity timeout for connection to 300 seconds
962
  Mojo::IOLoop->stream($c->tx->connection)->timeout(300);
963

            
964
=head2 write_chunk
965

            
966
  $c = $c->write_chunk;
967
  $c = $c->write_chunk($bytes);
968
  $c = $c->write_chunk(sub {...});
969
  $c = $c->write_chunk($bytes => sub {...});
970

            
971
Write dynamic content non-blocking with C<chunked> transfer encoding, the
972
optional drain callback will be invoked once all data has been written.
973

            
974
  # Make sure previous chunk has been written before continuing
975
  $c->write_chunk('He' => sub {
976
    my $c = shift;
977
    $c->write_chunk('ll' => sub {
978
      my $c = shift;
979
      $c->finish('o!');
980
    });
981
  });
982

            
983
You can call L</"finish"> at any time to end the stream.
984

            
985
  2
986
  He
987
  2
988
  ll
989
  2
990
  o!
991
  0
992

            
993
=head1 HELPERS
994

            
995
In addition to the attributes and methods above you can also call helpers on
996
L<Mojolicious::Controller> objects. This includes all helpers from
997
L<Mojolicious::Plugin::DefaultHelpers> and L<Mojolicious::Plugin::TagHelpers>.
998

            
999
  $c->layout('green');
1000
  $c->title('Welcome!');
1001

            
1002
=head1 SEE ALSO
1003

            
1004
L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>.
1005

            
1006
=cut