tags:

views:

374

answers:

4

Assume a system that contains only the basic Perl installation without any extra CPAN modules (LWP is hence NOT installed). Some of my target environments have limited space and I cannot increase my footprint at all (otherwise I would use LWP).

What is the most portable and reliable way to issue a HTTP POST request from such a system, and then retrieve the response?

+11  A: 

Consider this. HTTP POSTs are not trivial. You need to assemble the data into a MIME blob, encode it properly, then open a Socket connection, send the data, then read any response headers from the socket to make sure it worked.

You'll be doing a lot of work to duplicate what LWP already does, and then you'll take all that work and put it in your environment that doesn't have LWP.

At that point, you will ask yourself, "gee, if I can put my own Perl code on this environment, why can't I just put LWP there?"

Never fear, for I am here to save you three months of useless work.

How to install Perl modules locally

If you can't do that, then

How to use PAR to package and distribute dependencies

Good luck, and don't duplicate code.

friedo
+16  A: 

HTTP::Lite is pure-Perl, so you can just bundle it along with your existing code.

Charles
+2  A: 

I just do HTTP Post like this without using any library,

sub post {
    local($host,$port,$request,$data) = @_;
    ($fqdn, $aliases, $type, $len, $thataddr) = gethostbyname($host);
    $that = pack($sockaddr, &AF_INET, $port, $thataddr);
    socket(FS, &AF_INET, &SOCK_STREAM, $proto) || return undef;
    bind(FS, $thissock) || return undef;
    local($/);
    unless (eval q!
        $SIG{'ALRM'} = "timeout";
        alarm($timeout);
        connect(FS, $that) || return undef;
        select(FS); $| = 1; select(STDOUT);

        print FS "POST $request HTTP/1.0\r\n$referer";
        print FS "$useragent";
        print FS "Host: $host:$port\r\n$mimeaccept";
        print FS "$cnt_type";
        $len = length($data);
        print FS "Content-length: $len\r\n\r\n$data\r\n";
        undef($page);
        $/ = "\n";
        $_ = <FS>;
        if (m:HTTP/1.0\s+\d+\s+:) { #HTTP/1.0
          while(<FS>) {
            last if /^[\r\n]+$/; # end of header
          }
          undef($/);
          $page = <FS>;
        }
        else {    # old style server reply
          undef($/);
          $page = $_;
          $_ = <FS>;            
          $page .= $_;
        }
        $SIG{'ALRM'} = "IGNORE";
        !) {
            return undef;
        }
    close(FS);
    $page;
}

I use this with a real old server (first generation Apache httpd). It doesn't support HTTP/1.1, chunked encoding etc but you get the idea.

ZZ Coder
This won't work with use strict. Your timeout handling is broken. Who will do the encoding?
innaM
Why are you using eval STRING instead of eval BLOCK?
ysth
ysth: This is Perl 4 code and maybe block eval did not existed that time.
Alexandr Ciornii
This code was written in 1996. That was my most current Perl knowledge so I don't know what you guys are talking about. This was part of my home automation software developed in Perl on a Slackware Linux. Due to the special interface card, I can't upgrade the 486 PC. So I am stuck with the old Linux, Perl etc. It works perfectly fine so I have no reason to use the new fancy features either.
ZZ Coder
"my" already existed in 1996. You should use it for declaring variables instead of "local".
Alexandr Ciornii
+2  A: 

Are there any other programs available that you could call to perform the post? curl? wget? lynx? Java?

Kenster
I second this. If space is really tight, using an external program (possibly compiled without ssl support to reduce dependencies) can be a good way to go.
ysth