Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Re^3: Does CGI::Application expose a HTTP::Request object?

by jaldhar (Vicar)
on Aug 11, 2010 at 03:52 UTC ( #854210=note: print w/ replies, xml ) Need Help??


in reply to Re^2: Does CGI::Application expose a HTTP::Request object?
in thread Does CGI::Application expose a HTTP::Request object?

The value of $header doesn't seem to work for HTTP::Request, it complains with "Bad header argument". Further, it doesn't seem to hold the headers of the request, but of the response CGI::Application is about to deliver, for example in my test it held a "Content-Type: text/html" header.

That should have been @{ $self->header_props } because HTTP::Request wants a reference to an array of key-value pairs but in any case it wouldn't work because as you pointed out, it gives outgoing headers not incoming.

You would have to get the special HTTP envvars out of the environment and make them into headers.

Your elaborate attempts to get the $content *of the request* do not seem to work. None of my tests showed the request content getting through. my @params = $q->param should return all parameters but is empty except for those keys passed in $ENV{QUERY_STRING}, no PUTDATA etc. there. Is a CGI::Fast + CGI::Application based script aware of request data which is not coming from POST requests - at all?

As I alluded to in my last reply, I think the problem is POSTDATA and PUTDATA don't get set in some cases. (They are not real params but specially set up by CGI.pm) I think this happens if the MIME type is application/x-www-form-urlencoded or multipart/form-data which is usual for an HTML form. So in this case or if we can't get the them for any other reason, we should read from standard input based on the Content-Length header (which doesn't seem to have CGI.pm method I don't know why.)

Try this. Again untested I'm afraid.

sub request_from_cgi { my ($self) = @_; my $q = $self->query; my $uri = $q->url; my $method = uc $q->request_method; # probably not an exhaustive list. my @http_envvars = qw/ DOCUMENT_ROOT HTTP_COOKIE HTTP_REFERER HTTP_USER_AGENT HTTPS PATH QUERY_STRING REMOTE_ADDR REMOTE_HOST REMOTE_PORT REMOTE_USER REQUEST_METHOD REQUEST_URI SCRIPT_FILENAME SCRIPT_NAME SERVER_ADMIN SERVER_NAME SERVER_PORT SERVER_SOFTWARE /; my $headers = {}; foreach my $var (@http_envvars) { if (exists $ENV{$var}) { $headers->{$var} = $ENV{$var}; } } my $content = undef; if ($method eq 'POST') { $content = $q->param('POSTDATA'); } elsif ($method eq 'PUT') { $content = $q->param('PUTDATA'); } if (!defined $content) { my $len = $ENV{CONTENT_LENGTH} || 0; read STDIN, $content, $len; } return HTTP::Request->new( $method, $uri, HTTP::Headers->new($headers), $content, ); }

--
જલધર


Comment on Re^3: Does CGI::Application expose a HTTP::Request object?
Download Code
Re^4: Does CGI::Application expose a HTTP::Request object?
by isync (Hermit) on Aug 11, 2010 at 11:34 UTC
    1. Error on a first pass: "Can't call method "clone" on unblessed reference at /usr/share/perl5/HTTP/Message.pm line 32."

    2. Shouldn't the %ENV variable names be mapped to the a-bit-different HTTP Header names?

    3. And we are passing a hashref to the HTTP::Request constructor, but it expects an arrayref (solved via this node).

    Changed code:
    my %env_to_httpheader = ( 'HTTP_USER_AGENT' => 'User-Agent', 'HTTP_HOST' => 'Host', 'HTTP_TE' => 'Accept-Encoding', 'CONTENT_LENGTH' => 'Content-Length', # from here on blurry from memory: (and probably more to inclu +de as well..) 'CONTENT_ENCODING' => 'Content-Encoding', 'CONTENT_TYPE' => 'Content-Type', ); my $headers; foreach my $key (keys %env_to_httpheader) { if (exists $ENV{$key}) { # $headers->{ $env_to_httpheader{$key} } = $ENV{$key}; # "The optional $header argument should be a reference + to an HTTP::Headers object or a plain array reference of key/value p +airs." push(@{ $headers }, $env_to_httpheader{$key}); push(@{ $headers }, $ENV{$key}); } }

    Result: After changing this, it works!

    Any leftovers, hints, tweaks for this piece of code before I move it to production code? For example, a module for the ENV to HTTP Header translation, or similar improvements?

    2c: A lengthy hack, isn't it? Just to get a HTTP::Response out of CGI.pm/CGI::Fast. Once more, I dislike this CGI.pm-behemoth..

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://854210]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (5)
As of 2014-07-12 12:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    When choosing user names for websites, I prefer to use:








    Results (239 votes), past polls