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
|
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.