http://www.perlmonks.org?node_id=609635


in reply to REST Webservices and CGI.pm

CGI can still help you. You just need to make sure that the incoming data isn't regular form data:
HANDLING NON-URLENCODED ARGUMENTS If POSTed data is not of type application/x-www-form-urlencoded or multipart/form-data, then the POSTed data will not be processed, but instead be returned as-is in a parameter named POSTDATA. To retrieve it, use code like this: my $data = $query->param('POSTDATA'); (If you don't know what the preceding means, don't worry about it. It only affects people trying to use CGI for XML processing and other specialized tasks.)
I've used this successfully in a CGI::Application-based REST app -- at least for text/xml POST requests (I didn't test PUT yet, but I expect it to work the same way). I can heartily recommend CGI::Application::Dispatch, as it makes building RESTy APIs easier.

I simply added a wrapper method in my base class:

sub get_request_body { my $self = shift; return $self->query->param('POSTDATA'); }
My code can then choose to inflate that in any way it wants.

Replies are listed 'Best First'.
Re^2: REST Webservices
by derby (Abbot) on Apr 12, 2007 at 12:28 UTC

    Thanks rhesa but CGI is not going to handle the PUT data. From CGI where POSTDATA is set:

    if ($meth eq 'POST' && defined($ENV{'CONTENT_TYPE'}) && $ENV{'CONTENT_TYPE'} !~ m|^application/x-www-form-urlencoded| && $ENV{'CONTENT_TYPE'} !~ m|^multipart/form-data| ) { my($param) = 'POSTDATA' ;
    and further down in the comments:
    # If $meth is not of GET, POST or HEAD, assume we're being debugged of +fline. # Check the command line and then the standard input for data. # We use the shellwords package in order to behave the way that # UN*X programmers expect.
    So I still would have need to patch CGI to handle PUT and when it comes down to it the foo magic is much higher in CGI than it is in CGI::Simple. That being said, I think I should rework my code to the POST and PUT data in the PARAMs under POSTDATA and PUTDATA.

    -derby
      Thanks for digging deeper. I didn't have a need for PUT or DELETE yet (but I reckon I will in the future), so I hadn't realised the support was this limited.

      I agree that a patch to CGI is in order. Even if most web browsers don't support them, PUT and DELETE are still valid HTTP verbs, and I feel that the various CGI modules ought to support them.

      At first blush, a patch to either CGI or CGI::Simple doesn't look so difficult. I think DELETE could be handled pretty much the same way as GET, and PUT is pretty similar to POST. I may be overly optimistic, but it shouldn't take more than changing a couple of if()s ;-)

        As I make this post, CGI is at version 3.48, and it will handle GET|POST|PUT but not DELETE.

        I discovered this trying to make a REST dispatch in a .cgi script. I believe you're right -- that DELETE can be handled just like GET. On my system, I made the following change to CGI.pm, and DELETE started to work (I got query string parameters back).

        --- /usr/local/share/perl/5.10.0/CGI.pm.bak 2009-11-05 15:26:07.00 +0000000 -0700 +++ /usr/local/share/perl/5.10.0/CGI.pm 2009-11-05 15:23:05.000000000 +-0700 @@ -649,7 +649,7 @@ sub init { # If method is GET or HEAD, fetch the query from # the environment. - if ($is_xforms || $meth=~/^(GET|HEAD)$/) { + if ($is_xforms || $meth=~/^(GET|HEAD|DELETE)$/) { if ($MOD_PERL) { $query_string = $self->r->args; } else {

        This is a pretty minor modification, and you get decent functionality out of the DELETE verb (i.e. parameters). I'd love to see at least this much provided by CGI.pm.

        A blog among millions.

      There might be a work around, but I'm not sure, as I'm not in a position to test it right now. Try each of the following:

      • call CGI with ':no_debug' (to keep from entering the block that calls read_from_cmdline)
      • define the function 'CGI::read_from_cmdline' that doesn't actually read anything from the command line. (or put a wrapper around CGI, and put it in there)