Getting the body of an http POST request, using mo

2019-05-21 02:01发布

问题:

I am writing a quick script to munge a submitted file, and return that content to the user.

My test code looks like this:

#!/path/to/bin/perl
use strict;
use warnings;
use utf8;

use Apache2::RequestRec;
use Apache2::RequestIO; 

my ( $xmlin, $accepts ) = (q{}, q{});
my $format = 'json';

# read the posted content
while (
    Apache2::RequestIO::read($xmlin, 1024)
      ) {};

{
  no warnings;
  $accepts = $Apache2::RequestRec::headers_in{'Accepts'};
}
if ($accepts) {
  for ($accepts) {
    /application\/xml/i && do {
      $format = 'xml';
      last;
    };
    /text\/plain/i && do {
      $format = 'text';
      last;
    };
  } ## end for ($accepts)
} ## end if ($accepts)
print "format: $format; xml: $xmlin\n";

This code fails to compile with Undefined subroutine &Apache2::RequestIO::read

If I comment out the while loop, the code runs fine.

Unfortunately the Apache2::RequestIO code is pulled in via Apache2::XSLoader::load __PACKAGE__; so I can't check the actual code.... but I don't understand why this doesn't work

(and yes, I've also tried $r->read(...), to no avail)

回答1:

I think I have a good idea of why your code is not working.

The module Apache2::RequestIO added new functionality to Apache2::RequestRec.

In other words to add new methods/functions to the Apache2::RequestRec namespace.

I would first change Apache2::RequestIO::read to Apache2::RequestRec::read.

If that does not work move use a handler.

I have code that works which does a similar the thing

In your httpd.conf

PerlSwitches -I/path/to/module_dir
PerlLoadModule ModuleName
PerlResponseHandler ModuleName

ModuleName.pm

package ModuleName;
use strict;
use warnings;
use Apache2::RequestIO();
use Apache2::RequestRec();
use Apache2::Const -compile => qw(OK);
sub handler {
    my ($r) = @_;
    {
        use bytes;
        my $content = '';
        my $offset = 0;
        my $cnt = 0;
        do {
            $cnt = $r->read($content,8192,$offset);
            $offset += $cnt;
        } while($cnt == 8192);
    }
   return Apache2::Const::HTTP_OK;
}


回答2:

I also use Apache2::RequestIO to read the body:

sub body {
    my $self =  shift;

    return $self->{ body }   if defined $self->{ body };
    $self->apr->read( $self->{ body }, $self->headers_in->get( 'Content-Length' ) );

    $self->{ body };
}

In this case you should subclass original Apache2::Request. Especially pay attention to our @ISA = qw(Apache2::Request);

I do not know why, but standard body method return me:

$self->body        # {}
$self->body_status # Missing parser

when Content-Type is application/json. So I work around that in such way. Then parse body myself:

sub content {
    my $self =  shift;

    return   $self->{ content }   if defined $self->{ content };

    my $content_type =  $self->headers_in->get('Content-Type');
    $content_type =~ s/^(.*?);.*$/$1/;

    return   unless exists $self->{ $content_type };

    return $self->{ content } =  $self->{ $content_type }( $self->body, $self );
}

where:

use JSON;
sub new {
    my ($proto, $r) = @_;

    my $self = $proto->SUPER::new($r);
    $self->{ 'application/json' } =  sub {
        decode_json shift;
    };
    return $self;
}