5

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?

12
  • 3
    Why would you possibly be in this situation? Commented Sep 5, 2009 at 19:08
  • Ether: I'm not in control of the target environment. Commented Sep 5, 2009 at 19:13
  • 1
    Package LWP with your code and don't be ridiculous Commented Sep 5, 2009 at 19:40
  • 2
    @knorv, the whole point is that you DON'T have to install LWP if you package it with your code, e.g. using PAR Commented Sep 5, 2009 at 19:50
  • 3
    friedo: LWP+dependencies does not even FIT in some of the environments targeted. If packaging and/or installing LWP was an option I would not have asked this question. Commented Sep 5, 2009 at 19:53

5 Answers 5

17

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

Sign up to request clarification or add additional context in comments.

2 Comments

Or HTTP::Tiny, which supersedes HTTP::Lite
Both libraries still include MUCH more functionality (=code=ballast) than the poster probably needs. On embedded systems, every byte is scarce. I also prefer coding only the necessary functions by hand if I only need 10% of what libraries provide.
12

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.

Comments

3

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.

5 Comments

This won't work with use strict. Your timeout handling is broken. Who will do the encoding?
Why are you using eval STRING instead of eval BLOCK?
ysth: This is Perl 4 code and maybe block eval did not existed that time.
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.
"my" already existed in 1996. You should use it for declaring variables instead of "local".
3

See if there are any other programs available that you could call to perform the post. curl, wget, lynx, or Java for example.

1 Comment

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.
0

HTTP POST is really trivial if you only want to post plain text, which should suffice for most applications.

I use this code which requires only IO::Socket (running on my NAS with perl 5.8.8) to post sensor data (acquired on my LAN via UDP, also via another IO::Socket) to an influxdb server on the internet:

my $REMOTE = new IO::Socket::INET (PeerAddr => 'yourhostname.com', PeerPort => '8086',
                                   Proto => 'tcp', Timeout => '1', Blocking => '0')                 
   or die "can't connect - connection busy?";                                                       
$REMOTE->autoflush(1);                                                                              
                                                                                                    
my $data = "POOL ph=$ph,orp=$orp";                                                                
my $len = length($data);                                                                          
print $REMOTE "POST /write?db=esp-sensors HTTP/1.1\n",                              
              "Host: yourhostname.com\n",                                                    
              "Connection: close\n",                                                
              "Content-Type: application/x-www-form-urlencoded\n",                  
              "Content-Length: $len\n\n",                                           
              "$data\n";                                                            
close($REMOTE);      

Granted, I don't check the result. But I assume it would be possible. Since there is nothing I could do about any failure anyway, I don't care if it fails, someday I'll see data missing in the graph and check whats up.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.