use HTTP::Headers;
use Plack::Loader;
use Catalyst::EngineLoader;
-use Encode 2.21 'decode_utf8';
+use Encode 2.21 'decode_utf8', 'encode', 'decode';
use Plack::Request::Upload;
use Hash::MultiValue;
use namespace::clean -except => 'meta';
}
else {
- # Case where body was set afgter calling ->write. We'd prefer not to
+ # 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.
-
- $self->write($c, $body );
+ # views work. Since body has already been encoded, we need to do
+ # an 'unencoded_write' here.
+ $self->unencoded_write( $c, $body );
}
}
sub prepare_query_parameters {
my ($self, $c) = @_;
my $env = $c->request->env;
+ my $do_not_decode_query = $c->config->{do_not_decode_query};
+
+ my $old_encoding;
+ if(my $new = $c->config->{default_query_encoding}) {
+ $old_encoding = $c->encoding;
+ $c->encoding($new);
+ }
+
+ my $check = $c->config->{do_not_check_query_encoding} ? undef :$c->_encode_check;
+ my $decoder = sub {
+ my $str = shift;
+ return $str if $do_not_decode_query;
+ return $c->_handle_param_unicode_decoding($str, $check);
+ };
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 ) {
- my $keywords = $self->unescape_uri($query_string);
- $keywords = decode_utf8 $keywords;
- $c->request->query_keywords($keywords);
- return;
- }
-
$query_string =~ s/\A[&;]+//;
- my $p = Hash::MultiValue->new(
- map { defined $_ ? decode_utf8($self->unescape_uri($_)) : $_ }
- map { ( split /=/, $_, 2 )[0,1] } # slice forces two elements
- split /[&;]+/, $query_string
- );
+ my @unsplit_pairs = split /[&;]+/, $query_string;
+ my $p = Hash::MultiValue->new();
+
+ my $is_first_pair = 1;
+ for my $pair (@unsplit_pairs) {
+ my ($name, $value)
+ = map { defined $_ ? $decoder->($self->unescape_uri($_)) : $_ }
+ ( split /=/, $pair, 2 )[0,1]; # slice forces two elements
+
+ if ($is_first_pair) {
+ # If the first pair has no equal sign, then it means the isindex
+ # flag is set.
+ $c->request->query_keywords($name) unless defined $value;
+
+ $is_first_pair = 0;
+ }
+
+ $p->add( $name => $value );
+ }
+
+ $c->encoding($old_encoding) if $old_encoding;
$c->request->query_parameters( $c->request->_use_hash_multivalue ? $p : $p->mixed );
}
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};
+ $name = $c->_handle_unicode_decoding($name) if $enc;
my @uploads;
for my $upload (ref $files eq 'ARRAY' ? @$files : ($files)) {
my $headers = HTTP::Headers->new( %{ $upload->{headers} } );
$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 >>.