Version 5.90006
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Request.pm
CommitLineData
fc7ec1d9 1package Catalyst::Request;
2
b4ca0ee8 3use IO::Socket qw[AF_INET inet_aton];
bd917b94 4use Carp;
fc42a730 5use utf8;
de19de2e 6use URI::http;
7use URI::https;
e669e88a 8use URI::QueryParam;
6680c772 9use HTTP::Headers;
b4ca0ee8 10
059c085b 11use Moose;
12
6802c884 13use namespace::clean -except => 'meta';
14
b99ff5d8 15with 'MooseX::Emulate::Class::Accessor::Fast';
16
5fb12dbb 17has action => (is => 'rw');
18has address => (is => 'rw');
19has arguments => (is => 'rw', default => sub { [] });
20has cookies => (is => 'rw', default => sub { {} });
21has query_keywords => (is => 'rw');
22has match => (is => 'rw');
23has method => (is => 'rw');
24has protocol => (is => 'rw');
059c085b 25has query_parameters => (is => 'rw', default => sub { {} });
5fb12dbb 26has secure => (is => 'rw', default => 0);
27has captures => (is => 'rw', default => sub { [] });
6cb9e383 28has uri => (is => 'rw', predicate => 'has_uri');
8026359e 29has remote_user => (is => 'rw');
5fb12dbb 30has headers => (
e5ecd5bc 31 is => 'rw',
059c085b 32 isa => 'HTTP::Headers',
33 handles => [qw(content_encoding content_length content_type header referer user_agent)],
6680c772 34 default => sub { HTTP::Headers->new() },
35 required => 1,
36 lazy => 1,
059c085b 37);
38
39has _context => (
40 is => 'rw',
41 weak_ref => 1,
0fc2d522 42 handles => ['read'],
02570318 43 clearer => '_clear_context',
059c085b 44);
45
46has body_parameters => (
5fb12dbb 47 is => 'rw',
48 required => 1,
49 lazy => 1,
50 default => sub { {} },
fc7ec1d9 51);
52
059c085b 53has uploads => (
5fb12dbb 54 is => 'rw',
55 required => 1,
5fb12dbb 56 default => sub { {} },
059c085b 57);
58
059c085b 59has parameters => (
60 is => 'rw',
61 required => 1,
62 lazy => 1,
63 default => sub { {} },
64);
65
341620d5 66# TODO:
67# - Can we lose the before modifiers which just call prepare_body ?
68# they are wasteful, slow us down and feel cluttery.
69
70# Can we make _body an attribute, have the rest of
71# these lazy build from there and kill all the direct hash access
72# in Catalyst.pm and Engine.pm?
73
74before $_ => sub {
75 my ($self) = @_;
76 my $context = $self->_context || return;
77 $context->prepare_body;
78} for qw/parameters body_parameters/;
79
e99ec2dc 80around parameters => sub {
81 my ($orig, $self, $params) = @_;
82 if ($params) {
83 if ( !ref $params ) {
84 $self->_context->log->warn(
85 "Attempt to retrieve '$params' with req->params(), " .
86 "you probably meant to call req->param('$params')"
87 );
88 $params = undef;
89 }
90 return $self->$orig($params);
91 }
92 $self->$orig();
059c085b 93};
94
95has base => (
5fb12dbb 96 is => 'rw',
97 required => 1,
98 lazy => 1,
99 default => sub {
059c085b 100 my $self = shift;
6cb9e383 101 return $self->path if $self->has_uri;
059c085b 102 },
103);
104
069355da 105has _body => (
0f56bbcf 106 is => 'rw', clearer => '_clear_body', predicate => '_has_body',
059c085b 107);
610bc6ec 108# Eugh, ugly. Should just be able to rename accessor methods to 'body'
b0ad47c1 109# and provide a custom reader..
610bc6ec 110sub body {
111 my $self = shift;
059c085b 112 $self->_context->prepare_body();
14c057aa 113 croak 'body is a reader' if scalar @_;
610bc6ec 114 return blessed $self->_body ? $self->_body->body : $self->_body;
115}
059c085b 116
117has hostname => (
118 is => 'rw',
119 required => 1,
120 lazy => 1,
121 default => sub {
122 my ($self) = @_;
9fb936e5 123 gethostbyaddr( inet_aton( $self->address ), AF_INET ) || $self->address
059c085b 124 },
125);
126
02570318 127has _path => ( is => 'rw', predicate => '_has_path', clearer => '_clear_path' );
128
8026359e 129# XXX: Deprecated in docs ages ago (2006), deprecated with warning in 5.8000 due
130# to confusion between Engines and Plugin::Authentication. Remove in 5.8100?
131has user => (is => 'rw');
132
059c085b 133sub args { shift->arguments(@_) }
134sub body_params { shift->body_parameters(@_) }
135sub input { shift->body(@_) }
136sub params { shift->parameters(@_) }
137sub query_params { shift->query_parameters(@_) }
138sub path_info { shift->path(@_) }
139sub snippets { shift->captures(@_) }
f7e4e231 140
965f3e35 141=for stopwords param params
142
fc7ec1d9 143=head1 NAME
144
3e19f4f6 145Catalyst::Request - provides information about the current client request
fc7ec1d9 146
147=head1 SYNOPSIS
148
b22c6668 149 $req = $c->request;
150 $req->action;
151 $req->address;
b22c6668 152 $req->arguments;
3e19f4f6 153 $req->args;
b22c6668 154 $req->base;
06e1b616 155 $req->body;
fbcc39ad 156 $req->body_parameters;
b5176d9e 157 $req->content_encoding;
158 $req->content_length;
159 $req->content_type;
b77e7869 160 $req->cookie;
b22c6668 161 $req->cookies;
b5176d9e 162 $req->header;
b22c6668 163 $req->headers;
164 $req->hostname;
61bacdcc 165 $req->input;
3b4d1251 166 $req->query_keywords;
b22c6668 167 $req->match;
168 $req->method;
e7c0c583 169 $req->param;
e7c0c583 170 $req->parameters;
3e19f4f6 171 $req->params;
b22c6668 172 $req->path;
bfde09a2 173 $req->protocol;
fbcc39ad 174 $req->query_parameters;
175 $req->read;
b5176d9e 176 $req->referer;
bfde09a2 177 $req->secure;
2982e768 178 $req->captures; # previously knows as snippets
e7c0c583 179 $req->upload;
b22c6668 180 $req->uploads;
77d12cae 181 $req->uri;
7ce7ca2e 182 $req->user;
66294129 183 $req->user_agent;
b22c6668 184
3e22baa5 185See also L<Catalyst>, L<Catalyst::Request::Upload>.
fc7ec1d9 186
187=head1 DESCRIPTION
188
3e19f4f6 189This is the Catalyst Request class, which provides an interface to data for the
190current client request. The request object is prepared by L<Catalyst::Engine>,
191thus hiding the details of the particular engine implementation.
b22c6668 192
193=head1 METHODS
fc7ec1d9 194
b5ecfcf0 195=head2 $req->action
fc7ec1d9 196
aae8d418 197[DEPRECATED] Returns the name of the requested action.
198
199
200Use C<< $c->action >> instead (which returns a
201L<Catalyst::Action|Catalyst::Action> object).
fc7ec1d9 202
b5ecfcf0 203=head2 $req->address
0556eb49 204
3e19f4f6 205Returns the IP address of the client.
61b1e958 206
b5ecfcf0 207=head2 $req->arguments
61b1e958 208
b22c6668 209Returns a reference to an array containing the arguments.
fc7ec1d9 210
211 print $c->request->arguments->[0];
212
c436c1e8 213For example, if your action was
214
7d7519a4 215 package MyApp::Controller::Foo;
85d9fce6 216
217 sub moose : Local {
218 ...
219 }
c436c1e8 220
3e19f4f6 221and the URI for the request was C<http://.../foo/moose/bah>, the string C<bah>
c436c1e8 222would be the first and only argument.
223
6d920953 224Arguments get automatically URI-unescaped for you.
8f58057d 225
b5ecfcf0 226=head2 $req->args
3e19f4f6 227
01011731 228Shortcut for L</arguments>.
3e19f4f6 229
b5ecfcf0 230=head2 $req->base
fc7ec1d9 231
328f225e 232Contains the URI base. This will always have a trailing slash. Note that the
f4dda4a8 233URI scheme (e.g., http vs. https) must be determined through heuristics;
328f225e 234depending on your server configuration, it may be incorrect. See $req->secure
235for more info.
c436c1e8 236
3e19f4f6 237If your application was queried with the URI
238C<http://localhost:3000/some/path> then C<base> is C<http://localhost:3000/>.
fc7ec1d9 239
b5ecfcf0 240=head2 $req->body
06e1b616 241
843871cf 242Returns the message body of the request, as returned by L<HTTP::Body>: a string,
243unless Content-Type is C<application/x-www-form-urlencoded>, C<text/xml>, or
244C<multipart/form-data>, in which case a L<File::Temp> object is returned.
e060fe05 245
b5ecfcf0 246=head2 $req->body_parameters
fbcc39ad 247
3e19f4f6 248Returns a reference to a hash containing body (POST) parameters. Values can
fbcc39ad 249be either a scalar or an arrayref containing scalars.
250
251 print $c->request->body_parameters->{field};
252 print $c->request->body_parameters->{field}->[0];
c436c1e8 253
d631b5f9 254These are the parameters from the POST part of the request, if any.
e5ecd5bc 255
b5ecfcf0 256=head2 $req->body_params
fbcc39ad 257
3e19f4f6 258Shortcut for body_parameters.
fbcc39ad 259
b5ecfcf0 260=head2 $req->content_encoding
b5176d9e 261
3e19f4f6 262Shortcut for $req->headers->content_encoding.
b5176d9e 263
b5ecfcf0 264=head2 $req->content_length
b5176d9e 265
3e19f4f6 266Shortcut for $req->headers->content_length.
b5176d9e 267
b5ecfcf0 268=head2 $req->content_type
b5176d9e 269
3e19f4f6 270Shortcut for $req->headers->content_type.
b5176d9e 271
b5ecfcf0 272=head2 $req->cookie
3ad654e0 273
3e19f4f6 274A convenient method to access $req->cookies.
3ad654e0 275
276 $cookie = $c->request->cookie('name');
277 @cookies = $c->request->cookie;
278
279=cut
280
281sub cookie {
282 my $self = shift;
283
284 if ( @_ == 0 ) {
b77e7869 285 return keys %{ $self->cookies };
3ad654e0 286 }
287
288 if ( @_ == 1 ) {
289
290 my $name = shift;
291
b77e7869 292 unless ( exists $self->cookies->{$name} ) {
3ad654e0 293 return undef;
294 }
fbcc39ad 295
b77e7869 296 return $self->cookies->{$name};
3ad654e0 297 }
298}
299
b5ecfcf0 300=head2 $req->cookies
fc7ec1d9 301
b22c6668 302Returns a reference to a hash containing the cookies.
fc7ec1d9 303
304 print $c->request->cookies->{mycookie}->value;
305
7e743798 306The cookies in the hash are indexed by name, and the values are L<CGI::Simple::Cookie>
c436c1e8 307objects.
308
b5ecfcf0 309=head2 $req->header
b5176d9e 310
3e19f4f6 311Shortcut for $req->headers->header.
b5176d9e 312
b5ecfcf0 313=head2 $req->headers
fc7ec1d9 314
3e19f4f6 315Returns an L<HTTP::Headers> object containing the headers for the current request.
fc7ec1d9 316
317 print $c->request->headers->header('X-Catalyst');
318
b5ecfcf0 319=head2 $req->hostname
0556eb49 320
178dca5f 321Returns the hostname of the client. Use C<< $req->uri->host >> to get the hostname of the server.
e5ecd5bc 322
b5ecfcf0 323=head2 $req->input
61bacdcc 324
3e19f4f6 325Alias for $req->body.
61bacdcc 326
3b4d1251 327=head2 $req->query_keywords
328
329Contains the keywords portion of a query string, when no '=' signs are
330present.
331
332 http://localhost/path?some+keywords
b0ad47c1 333
3b4d1251 334 $c->request->query_keywords will contain 'some keywords'
335
b5ecfcf0 336=head2 $req->match
fc7ec1d9 337
3e19f4f6 338This contains the matching part of a Regex action. Otherwise
2c83fd5a 339it returns the same as 'action', except for default actions,
340which return an empty string.
fc7ec1d9 341
b5ecfcf0 342=head2 $req->method
b5176d9e 343
344Contains the request method (C<GET>, C<POST>, C<HEAD>, etc).
345
b5ecfcf0 346=head2 $req->param
e7c0c583 347
b0ad47c1 348Returns GET and POST parameters with a CGI.pm-compatible param method. This
3e19f4f6 349is an alternative method for accessing parameters in $c->req->parameters.
e7c0c583 350
a82c2894 351 $value = $c->request->param( 'foo' );
352 @values = $c->request->param( 'foo' );
e7c0c583 353 @params = $c->request->param;
354
3e705254 355Like L<CGI>, and B<unlike> earlier versions of Catalyst, passing multiple
a82c2894 356arguments to this method, like this:
357
85d9fce6 358 $c->request->param( 'foo', 'bar', 'gorch', 'quxx' );
a82c2894 359
360will set the parameter C<foo> to the multiple values C<bar>, C<gorch> and
361C<quxx>. Previously this would have added C<bar> as another value to C<foo>
3e19f4f6 362(creating it if it didn't exist before), and C<quxx> as another value for
363C<gorch>.
a82c2894 364
83312afd 365B<NOTE> this is considered a legacy interface and care should be taken when
366using it. C<< scalar $c->req->param( 'foo' ) >> will return only the first
367C<foo> param even if multiple are present; C<< $c->req->param( 'foo' ) >> will
368return a list of as many are present, which can have unexpected consequences
369when writing code of the form:
370
371 $foo->bar(
372 a => 'b',
373 baz => $c->req->param( 'baz' ),
374 );
375
376If multiple C<baz> parameters are provided this code might corrupt data or
377cause a hash initialization error. For a more straightforward interface see
378C<< $c->req->parameters >>.
379
e7c0c583 380=cut
381
382sub param {
383 my $self = shift;
384
385 if ( @_ == 0 ) {
386 return keys %{ $self->parameters };
387 }
388
bfde09a2 389 if ( @_ == 1 ) {
e7c0c583 390
bfde09a2 391 my $param = shift;
6bd2b72c 392
bfde09a2 393 unless ( exists $self->parameters->{$param} ) {
394 return wantarray ? () : undef;
395 }
396
397 if ( ref $self->parameters->{$param} eq 'ARRAY' ) {
398 return (wantarray)
399 ? @{ $self->parameters->{$param} }
400 : $self->parameters->{$param}->[0];
401 }
402 else {
403 return (wantarray)
404 ? ( $self->parameters->{$param} )
405 : $self->parameters->{$param};
406 }
d7945f32 407 }
a82c2894 408 elsif ( @_ > 1 ) {
409 my $field = shift;
410 $self->parameters->{$field} = [@_];
d7945f32 411 }
e7c0c583 412}
b5176d9e 413
b5ecfcf0 414=head2 $req->parameters
61b1e958 415
3e19f4f6 416Returns a reference to a hash containing GET and POST parameters. Values can
d08ced28 417be either a scalar or an arrayref containing scalars.
fc7ec1d9 418
e7c0c583 419 print $c->request->parameters->{field};
420 print $c->request->parameters->{field}->[0];
fc7ec1d9 421
c436c1e8 422This is the combination of C<query_parameters> and C<body_parameters>.
423
b5ecfcf0 424=head2 $req->params
3e19f4f6 425
426Shortcut for $req->parameters.
427
b5ecfcf0 428=head2 $req->path
fc7ec1d9 429
3e19f4f6 430Returns the path, i.e. the part of the URI after $req->base, for the current request.
fc7ec1d9 431
be6801fa 432 http://localhost/path/foo
433
434 $c->request->path will contain 'path/foo'
435
b5ecfcf0 436=head2 $req->path_info
fbcc39ad 437
10011c19 438Alias for path, added for compatibility with L<CGI>.
fbcc39ad 439
440=cut
441
442sub path {
02fb5d78 443 my ( $self, @params ) = @_;
4f5ebacd 444
02fb5d78 445 if (@params) {
446 $self->uri->path(@params);
02570318 447 $self->_clear_path;
fbcc39ad 448 }
02570318 449 elsif ( $self->_has_path ) {
450 return $self->_path;
e561386f 451 }
02fb5d78 452 else {
453 my $path = $self->uri->path;
454 my $location = $self->base->path;
455 $path =~ s/^(\Q$location\E)?//;
456 $path =~ s/^\///;
02570318 457 $self->_path($path);
fbcc39ad 458
02fb5d78 459 return $path;
460 }
fbcc39ad 461}
462
b5ecfcf0 463=head2 $req->protocol
bfde09a2 464
3e19f4f6 465Returns the protocol (HTTP/1.0 or HTTP/1.1) used for the current request.
bfde09a2 466
b5ecfcf0 467=head2 $req->query_parameters
fbcc39ad 468
def54ce2 469=head2 $req->query_params
470
3e19f4f6 471Returns a reference to a hash containing query string (GET) parameters. Values can
fbcc39ad 472be either a scalar or an arrayref containing scalars.
473
474 print $c->request->query_parameters->{field};
475 print $c->request->query_parameters->{field}->[0];
b0ad47c1 476
b5ecfcf0 477=head2 $req->read( [$maxlength] )
fbcc39ad 478
3e19f4f6 479Reads a chunk of data from the request body. This method is intended to be
480used in a while loop, reading $maxlength bytes on every call. $maxlength
fbcc39ad 481defaults to the size of the request if not specified.
482
9779c885 483You have to set MyApp->config(parse_on_demand => 1) to use this directly.
fbcc39ad 484
b5ecfcf0 485=head2 $req->referer
fc7ec1d9 486
3e19f4f6 487Shortcut for $req->headers->referer. Returns the referring page.
fc7ec1d9 488
b5ecfcf0 489=head2 $req->secure
bfde09a2 490
328f225e 491Returns true or false, indicating whether the connection is secure
f4dda4a8 492(https). Note that the URI scheme (e.g., http vs. https) must be determined
ae7da8f5 493through heuristics, and therefore the reliability of $req->secure will depend
328f225e 494on your server configuration. If you are serving secure pages on the standard
495SSL port (443) and/or setting the HTTPS environment variable, $req->secure
496should be valid.
bfde09a2 497
2982e768 498=head2 $req->captures
499
5c6a56e0 500Returns a reference to an array containing captured args from chained
501actions or regex captures.
fc7ec1d9 502
2982e768 503 my @captures = @{ $c->request->captures };
504
505=head2 $req->snippets
fc7ec1d9 506
10011c19 507C<captures> used to be called snippets. This is still available for backwards
2982e768 508compatibility, but is considered deprecated.
fc7ec1d9 509
b5ecfcf0 510=head2 $req->upload
e7c0c583 511
3e19f4f6 512A convenient method to access $req->uploads.
e7c0c583 513
514 $upload = $c->request->upload('field');
515 @uploads = $c->request->upload('field');
516 @fields = $c->request->upload;
bfde09a2 517
e7c0c583 518 for my $upload ( $c->request->upload('field') ) {
146554c5 519 print $upload->filename;
e7c0c583 520 }
521
522=cut
523
524sub upload {
525 my $self = shift;
526
527 if ( @_ == 0 ) {
528 return keys %{ $self->uploads };
529 }
530
bfde09a2 531 if ( @_ == 1 ) {
e7c0c583 532
bfde09a2 533 my $upload = shift;
534
535 unless ( exists $self->uploads->{$upload} ) {
536 return wantarray ? () : undef;
537 }
6bd2b72c 538
bfde09a2 539 if ( ref $self->uploads->{$upload} eq 'ARRAY' ) {
540 return (wantarray)
541 ? @{ $self->uploads->{$upload} }
542 : $self->uploads->{$upload}->[0];
543 }
544 else {
545 return (wantarray)
fbcc39ad 546 ? ( $self->uploads->{$upload} )
547 : $self->uploads->{$upload};
bfde09a2 548 }
d7945f32 549 }
bfde09a2 550
a4f5c51e 551 if ( @_ > 1 ) {
bfde09a2 552
553 while ( my ( $field, $upload ) = splice( @_, 0, 2 ) ) {
554
555 if ( exists $self->uploads->{$field} ) {
556 for ( $self->uploads->{$field} ) {
557 $_ = [$_] unless ref($_) eq "ARRAY";
558 push( @$_, $upload );
559 }
560 }
561 else {
562 $self->uploads->{$field} = $upload;
563 }
564 }
e7c0c583 565 }
566}
567
b5ecfcf0 568=head2 $req->uploads
fc7ec1d9 569
bfde09a2 570Returns a reference to a hash containing uploads. Values can be either a
b0ad47c1 571L<Catalyst::Request::Upload> object, or an arrayref of
84e7aa89 572L<Catalyst::Request::Upload> objects.
e7c0c583 573
574 my $upload = $c->request->uploads->{field};
575 my $upload = $c->request->uploads->{field}->[0];
576
b5ecfcf0 577=head2 $req->uri
fbcc39ad 578
d26ee0d0 579Returns a L<URI> object for the current request. Stringifies to the URI text.
fbcc39ad 580
a375a206 581=head2 $req->mangle_params( { key => 'value' }, $appendmode);
bd917b94 582
a375a206 583Returns a hashref of parameters stemming from the current request's params,
584plus the ones supplied. Keys for which no current param exists will be
585added, keys with undefined values will be removed and keys with existing
586params will be replaced. Note that you can supply a true value as the final
587argument to change behavior with regards to existing parameters, appending
588values rather than replacing them.
589
590A quick example:
591
592 # URI query params foo=1
593 my $hashref = $req->mangle_params({ foo => 2 });
594 # Result is query params of foo=2
595
596versus append mode:
597
598 # URI query params foo=1
599 my $hashref = $req->mangle_params({ foo => 2 }, 1);
600 # Result is query params of foo=1&foo=2
601
602This is the code behind C<uri_with>.
bd917b94 603
604=cut
605
a375a206 606sub mangle_params {
607 my ($self, $args, $append) = @_;
b0ad47c1 608
a375a206 609 carp('No arguments passed to mangle_params()') unless $args;
fbb513f7 610
2f381252 611 foreach my $value ( values %$args ) {
d0f0fcf6 612 next unless defined $value;
fbb513f7 613 for ( ref $value eq 'ARRAY' ? @$value : $value ) {
614 $_ = "$_";
7066a4d5 615 utf8::encode( $_ ) if utf8::is_utf8($_);
fc42a730 616 }
fc42a730 617 };
b0ad47c1 618
a375a206 619 my %params = %{ $self->uri->query_form_hash };
620 foreach my $key (keys %{ $args }) {
621 my $val = $args->{$key};
622 if(defined($val)) {
623
624 if($append && exists($params{$key})) {
625
626 # This little bit of heaven handles appending a new value onto
627 # an existing one regardless if the existing value is an array
628 # or not, and regardless if the new value is an array or not
629 $params{$key} = [
630 ref($params{$key}) eq 'ARRAY' ? @{ $params{$key} } : $params{$key},
631 ref($val) eq 'ARRAY' ? @{ $val } : $val
632 ];
633
634 } else {
635 $params{$key} = $val;
636 }
637 } else {
638
639 # If the param wasn't defined then we delete it.
640 delete($params{$key});
641 }
642 }
643
644
645 return \%params;
646}
647
648=head2 $req->uri_with( { key => 'value' } );
649
650Returns a rewritten URI object for the current request. Key/value pairs
651passed in will override existing parameters. You can remove an existing
652parameter by passing in an undef value. Unmodified pairs will be
653preserved.
654
655You may also pass an optional second parameter that puts C<uri_with> into
656append mode:
657
658 $req->uri_with( { key => 'value' }, { mode => 'append' } );
9779c885 659
a375a206 660See C<mangle_params> for an explanation of this behavior.
661
662=cut
663
664sub uri_with {
665 my( $self, $args, $behavior) = @_;
666
667 carp( 'No arguments passed to uri_with()' ) unless $args;
668
669 my $append = 0;
670 if((ref($behavior) eq 'HASH') && defined($behavior->{mode}) && ($behavior->{mode} eq 'append')) {
671 $append = 1;
672 }
673
674 my $params = $self->mangle_params($args, $append);
675
676 my $uri = $self->uri->clone;
677 $uri->query_form($params);
2f381252 678
bd917b94 679 return $uri;
680}
681
8026359e 682=head2 $req->remote_user
683
684Returns the value of the C<REMOTE_USER> environment variable.
7ce7ca2e 685
b5ecfcf0 686=head2 $req->user_agent
b5176d9e 687
3e19f4f6 688Shortcut to $req->headers->user_agent. Returns the user agent (browser)
689version string.
b5176d9e 690
059c085b 691=head2 meta
692
693Provided by Moose
694
3e19f4f6 695=head1 AUTHORS
fc7ec1d9 696
2f381252 697Catalyst Contributors, see Catalyst.pm
fc7ec1d9 698
699=head1 COPYRIGHT
700
536bee89 701This library is free software. You can redistribute it and/or modify
61b1e958 702it under the same terms as Perl itself.
fc7ec1d9 703
704=cut
705
e5ecd5bc 706__PACKAGE__->meta->make_immutable;
707
fc7ec1d9 7081;