Revision 7d5fbd92
Von Moritz Bunkus vor fast 5 Jahren hinzugefügt
SL/Request.pm | ||
---|---|---|
10 | 10 |
use Exporter qw(import); |
11 | 11 |
|
12 | 12 |
use SL::Common; |
13 |
use SL::JSON; |
|
13 | 14 |
use SL::MoreCommon qw(uri_encode uri_decode); |
14 | 15 |
use SL::Layout::None; |
15 | 16 |
use SL::Presenter; |
16 | 17 |
|
17 |
our @EXPORT_OK = qw(flatten unflatten read_cgi_input);
|
|
18 |
our @EXPORT_OK = qw(flatten unflatten); |
|
18 | 19 |
|
19 | 20 |
use Rose::Object::MakeMethods::Generic |
20 | 21 |
( |
21 |
scalar => [ qw(applying_database_upgrades) ], |
|
22 |
scalar => [ qw(applying_database_upgrades post_data) ],
|
|
22 | 23 |
'scalar --get_set_init' => [ qw(cgi layout presenter is_ajax type) ], |
23 | 24 |
); |
24 | 25 |
|
... | ... | |
232 | 233 |
$::lxdebug->leave_sub(2); |
233 | 234 |
} |
234 | 235 |
|
236 |
sub _parse_json_formdata { |
|
237 |
my ($content) = @_; |
|
238 |
|
|
239 |
return $content ? SL::JSON::decode_json($content) : undef; |
|
240 |
} |
|
241 |
|
|
235 | 242 |
sub _recode_recursively { |
236 | 243 |
$::lxdebug->enter_sub; |
237 | 244 |
my ($iconv, $from, $to) = @_; |
... | ... | |
270 | 277 |
sub read_cgi_input { |
271 | 278 |
$::lxdebug->enter_sub; |
272 | 279 |
|
273 |
my ($target) = @_; |
|
280 |
my ($self, $target) = @_;
|
|
274 | 281 |
|
275 | 282 |
# yes i know, copying all those values around isn't terribly efficient, but |
276 | 283 |
# the old version of dumping everything into form and then launching a |
... | ... | |
279 | 286 |
# this way the data can at least be recoded on the fly as soon as we get to |
280 | 287 |
# know the source encoding and only in the cases where encoding may be hidden |
281 | 288 |
# among the payload we take the hit of copying the request around |
282 |
my $temp_target = { }; |
|
289 |
$self->post_data(undef); |
|
290 |
my $data_to_decode = { }; |
|
291 |
my $iconv = SL::Iconv->new('UTF-8', 'UTF-8'); |
|
283 | 292 |
|
284 |
# since both of these can potentially bring their encoding in INPUT_ENCODING |
|
285 |
# they get dumped into temp_target |
|
286 |
_input_to_hash($temp_target, $ENV{QUERY_STRING}, 1) if $ENV{QUERY_STRING}; |
|
287 |
_input_to_hash($temp_target, $ARGV[0], 1) if @ARGV && $ARGV[0]; |
|
293 |
_input_to_hash($data_to_decode, $ENV{QUERY_STRING}, 1) if $ENV{QUERY_STRING}; |
|
294 |
_input_to_hash($data_to_decode, $ARGV[0], 1) if @ARGV && $ARGV[0]; |
|
288 | 295 |
|
289 | 296 |
if ($ENV{CONTENT_LENGTH}) { |
290 | 297 |
my $content; |
291 | 298 |
read STDIN, $content, $ENV{CONTENT_LENGTH}; |
299 |
|
|
292 | 300 |
if ($ENV{'CONTENT_TYPE'} && $ENV{'CONTENT_TYPE'} =~ /multipart\/form-data/) { |
301 |
$self->post_data({}); |
|
302 |
my $post_data_to_decode = { }; |
|
303 |
|
|
293 | 304 |
# multipart formdata can bring it's own encoding, so give it both |
294 | 305 |
# and let it decide on it's own |
295 |
_parse_multipart_formdata($target, $temp_target, $content, 1); |
|
306 |
_parse_multipart_formdata($self->post_data, $post_data_to_decode, $content, 1); |
|
307 |
_recode_recursively($iconv, $post_data_to_decode, $self->post_data) if keys %$post_data_to_decode; |
|
308 |
|
|
309 |
$target->{$_} = $self->post_data->{$_} for keys %{ $self->post_data }; |
|
310 |
|
|
311 |
} elsif (($ENV{CONTENT_TYPE} // '') eq 'application/json') { |
|
312 |
$self->post_data(_parse_json_formdata($content)); |
|
313 |
|
|
296 | 314 |
} else { |
297 | 315 |
# normal encoding must be recoded |
298 |
_input_to_hash($temp_target, $content, 1);
|
|
316 |
_input_to_hash($data_to_decode, $content, 1);
|
|
299 | 317 |
} |
300 | 318 |
} |
301 | 319 |
|
302 |
my $encoding = delete $temp_target->{INPUT_ENCODING} || 'UTF-8'; |
|
303 |
|
|
304 |
_recode_recursively(SL::Iconv->new($encoding, 'UTF-8'), $temp_target => $target) if keys %$temp_target; |
|
320 |
_recode_recursively($iconv, $data_to_decode, $target) if keys %$data_to_decode; |
|
305 | 321 |
|
306 | 322 |
if ($target->{RESTORE_FORM_FROM_SESSION_ID}) { |
307 | 323 |
my %temp_form; |
... | ... | |
381 | 397 |
information about the request, such as whether or not it was done via AJAX, |
382 | 398 |
or the requested content type. |
383 | 399 |
|
384 |
use SL::Request qw(read_cgi_input);
|
|
400 |
use SL::Request; |
|
385 | 401 |
|
386 | 402 |
# read cgi input depending on request type, unflatten and recode |
387 |
read_cgi_input($target_hash_ref); |
|
403 |
$::request->read_cgi_input($target_hash_ref);
|
|
388 | 404 |
|
389 | 405 |
# $hashref and $new_hashref should be identical |
390 | 406 |
my $new_arrayref = flatten($hashref); |
... | ... | |
564 | 580 |
|
565 | 581 |
Returns the cached item. |
566 | 582 |
|
583 |
=item C<post_data> |
|
584 |
|
|
585 |
If the client sends data in the request body with the content type of |
|
586 |
either C<application/json> or C<multipart/form-data>, the content will |
|
587 |
be stored in the global request object, too. It can be retrieved via |
|
588 |
the C<post_data> function. |
|
589 |
|
|
590 |
For content type C<multipart/form-data> the same data is additionally |
|
591 |
stored in the global C<$::form> instance, potentially overwriting |
|
592 |
parameters given in the URL. This is done primarily for compatibility |
|
593 |
purposes with existing code that expects all parameters to be present |
|
594 |
in C<$::form>. |
|
595 |
|
|
596 |
For content type C<application/json> the data is only available in |
|
597 |
C<$::request>. The reason is that the top-level data in a JSON |
|
598 |
documents doesn't have to be an object which could be mapped to the |
|
599 |
hash C<$::form>. Instead, the top-level data can also be an |
|
600 |
array. Additionally keeping the namespaces of URL and POST parameters |
|
601 |
separate is cleaner and allows for fewer accidental conflicts. |
|
602 |
|
|
567 | 603 |
=back |
568 | 604 |
|
569 | 605 |
=head1 SPECIAL FUNCTIONS |
Auch abrufbar als: Unified diff
Unterstützung für JSON-encodierte POST-Daten
Mit diesem Patch werden nun alle POST-Daten in $::request->post_data
gespeichert. Wie bisher auch werden Daten mit Content-Type
»multipart/form-data« zusätzlich in $::form gespeichert.
Will man aber JSON-encodierte Daten hochladen, so werden die
ausschließlich in $::request->post_data gespeichert, nicht in
$::form. Hintergrund ist, dass JSON-Dokumente auch aus Arrays bestehen
können, $::form aber halt immer ein Hash ist. Weiterhin ist es
sinnvoll, die Namensräume der übertragenen Parameter sauber
voneinander zu trennen.