Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 7d5fbd92

Von Moritz Bunkus vor fast 5 Jahren hinzugefügt

  • ID 7d5fbd92062883ddd2f77167d7b91138ef17aee0
  • Vorgänger 5c350994
  • Nachfolger bfe30464

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.

Unterschiede anzeigen:

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