use Data::Dump qw/dump/;
use Errno 'EWOULDBLOCK';
use HTML::Entities;
-use HTTP::Body;
use HTTP::Headers;
-use URI::QueryParam;
use Plack::Loader;
use Catalyst::EngineLoader;
-use Encode ();
+use Encode 2.21 'decode_utf8', 'encode', 'decode';
use Plack::Request::Upload;
use Hash::MultiValue;
-use utf8;
-
use namespace::clean -except => 'meta';
+use utf8;
# Amount of data to read from input on each pass
our $CHUNKSIZE = 64 * 1024;
# XXX - this is only here for compat, do not use!
-has env => ( is => 'rw', writer => '_set_env' );
+has env => ( is => 'rw', writer => '_set_env' , weak_ref=>1);
my $WARN_ABOUT_ENV = 0;
around env => sub {
my ($orig, $self, @args) = @_;
# There's no body...
$body = [];
}
-
$res->_response_cb->([ $res->status, \@headers, $body]);
$res->_clear_response_cb;
close $body;
}
else {
- $self->write($c, $body );
+
+ # Case where body was set after calling ->write. We'd prefer not to
+ # support this, but I can see some use cases with the way most of the
+ # views work. Since body has already been encoded, we need to do
+ # an 'unencoded_write' here.
+ $self->unencoded_write( $c, $body );
}
}
(pt) Por favor volte mais tarde
(ru) Попробуйте еще раз позже
(ua) Спробуйте ще раз пізніше
+(it) Per favore riprova più tardi
</pre>
$name = '';
sub prepare_query_parameters {
my ($self, $c) = @_;
my $env = $c->request->env;
-
- if(my $query_obj = $env->{'plack.request.query'}) {
- $c->request->query_parameters(
- $c->request->_use_hash_multivalue ?
- $query_obj->clone :
- $query_obj->as_hashref_mixed);
- return;
- }
+ my $do_not_decode_query = $c->config->{do_not_decode_query};
+ my $default_query_encoding = $c->config->{default_query_encoding} ||
+ ($c->config->{decode_query_using_global_encoding} ?
+ $c->encoding : 'UTF-8');
+
+ my $decoder = sub {
+ my $str = shift;
+ return $str if $do_not_decode_query;
+ return $str unless $default_query_encoding;
+ return decode( $default_query_encoding, $str);
+ };
my $query_string = exists $env->{QUERY_STRING}
? $env->{QUERY_STRING}
# Check for keywords (no = signs)
# (yes, index() is faster than a regex :))
if ( index( $query_string, '=' ) < 0 ) {
- $c->request->query_keywords($self->unescape_uri($query_string));
+ my $keywords = $self->unescape_uri($query_string);
+ $keywords = $decoder->($keywords);
+ $c->request->query_keywords($keywords);
return;
}
- my %query;
+ $query_string =~ s/\A[&;]+//;
- # replace semi-colons
- $query_string =~ s/;/&/g;
-
- my @params = grep { length $_ } split /&/, $query_string;
-
- for my $item ( @params ) {
-
- my ($param, $value)
- = map { $self->unescape_uri($_) }
- split( /=/, $item, 2 );
-
- $param = $self->unescape_uri($item) unless defined $param;
-
- if ( exists $query{$param} ) {
- if ( ref $query{$param} ) {
- push @{ $query{$param} }, $value;
- }
- else {
- $query{$param} = [ $query{$param}, $value ];
- }
- }
- else {
- $query{$param} = $value;
- }
- }
+ my $p = Hash::MultiValue->new(
+ map { defined $_ ? $decoder->($self->unescape_uri($_)) : $_ }
+ map { ( split /=/, $_, 2 )[0,1] } # slice forces two elements
+ split /[&;]+/, $query_string
+ );
- $c->request->query_parameters(
- $c->request->_use_hash_multivalue ?
- Hash::MultiValue->from_mixed(\%query) :
- \%query);
+ $c->request->query_parameters( $c->request->_use_hash_multivalue ? $p : $p->mixed );
}
=head2 $self->prepare_read($c)
my $request = $c->request;
return unless $request->_body;
+ my $enc = $c->encoding;
my $uploads = $request->_body->upload;
my $parameters = $request->parameters;
foreach my $name (keys %$uploads) {
+ $name = $c->_handle_unicode_decoding($name) if $enc;
my $files = $uploads->{$name};
my @uploads;
for my $upload (ref $files eq 'ARRAY' ? @$files : ($files)) {
my $headers = HTTP::Headers->new( %{ $upload->{headers} } );
+ my $filename = $upload->{filename};
+ $filename = $c->_handle_unicode_decoding($filename) if $enc;
+
my $u = Catalyst::Request::Upload->new
(
size => $upload->{size},
type => scalar $headers->content_type,
+ charset => scalar $headers->content_type_charset,
headers => $headers,
tempname => $upload->{tempname},
- filename => $upload->{filename},
+ filename => $filename,
);
push @uploads, $u;
}
$c->response->write($buffer);
}
+=head2 $self->unencoded_write($c, $buffer)
+
+Writes the buffer to the client without encoding. Necessary for
+already encoded buffers. Used when a $c->write has been done
+followed by $c->res->body.
+
+=cut
+
+sub unencoded_write {
+ my ( $self, $c, $buffer ) = @_;
+
+ $c->response->unencoded_write($buffer);
+}
+
=head2 $self->read($c, [$maxlength])
Reads from the input stream by calling C<< $self->read_chunk >>.