Working with LWP

by Reuven M. Lerner

Most of the time, this column discusses ways in which we can improve or customize the work done by web servers. Whether we are working with CGI programs or mod_perl modules, we are usually looking at things from the server's perspective.

This month, we will look at LWP, the “library for web programming” available for Perl, along with several associated modules. The programs we will write will be web clients, rather than web servers. Server-side programs receive HTTP requests and generate HTTP responses; our programs this month will generate the requests and wait for the responses generated by the server.

As we examine these modules, we will gain a better understanding of how HTTP works, as well as how to use the various modules of LWP to construct all sorts of programs that retrieve and sort information stored on the Web.

Introduction to HTTP

HTTP, the “hypertext transfer protocol”, makes the Web possible. HTTP is one of many protocols used on the Internet and is considered a high-level protocol, alongside SMTP (the simple mail transfer protocol) and FTP (file transfer protocol). These are considered high-level protocols because they sit on a foundation of lower-level protocols that handle the more mundane aspects of networking. HTTP messages don't have to worry about handling dropped packets and routing, because TCP and IP take care of such things for it. If there is a problem, it will be taken care of at a lower level.

Dividing problems up in this way allows you to concentrate on the important issues, without being distracted by the minute details. If you had to think about your car's internals every time you wanted to drive somewhere, you would quickly find yourself concentrating on too many things at once and unable to perform the task at hand. By the same token, HTTP and other high-level protocols can ignore the low-level details of how the network operates, and simply assume the connection between two computers will work as advertised.

HTTP operates on a client-server model, in which the computer making the request is known as the client, and the computer receiving the request and issuing a response is the server. In the world of HTTP, servers never speak before they are spoken to—and they always get the last word. This means a client's request can never depend on the server's response; a client interested in using a previous response to form a new request must open a new connection.

Sending a Request

Given all of that theory, how does HTTP work in practice? You can experiment for yourself, using the simple telnet command. telnet is normally used to access another computer remotely, by typing:

telnet remotehost

That demonstrates the default behavior, in which telnet opens a connection to port 23, the standard port for such access. You can use telnet to connect to other ports as well, and if there is a server running there, you can even communicate with it.

Since HTTP servers typically run on port 80, I can connect to one with the command:

telnet 80

I get the following response on my Linux box:

Connected to
Escape character is '^]'.
Once we have established this connection, it is my turn to talk. I am the client in this context, which means I must issue a request before the server will issue any response. HTTP requests consist, at minimum, of a method, an object on which to apply that method, and an HTTP version number. For instance, we can retrieve the contents of the file at / by typing
GET / HTTP/1.0
This indicates we want the file at / to be returned to us, and that the highest-numbered version of HTTP we can handle is HTTP/1.0. If we were to indicate that we support HTTP/1.1, an advanced server would respond in kind, allowing us to perform all sorts of nifty tricks.

If you pressed return after issuing the above command, you are probably still waiting to receive a response. That's because HTTP/1.0 introduced the idea of “request headers”, additional pieces of information that a client can pass to a server as part of a request. These client headers can include cookies, language preferences, the previous URL this client visited (the “referer”) and many other pieces of information.

Because we will stick with a simple GET request, we press return twice after our one-line command: once to end the first line of our request, and another to indicate we have nothing more to send. As with e-mail messages, a blank line separates the headers—information about the message—from the message itself.

Examining the response




HTTP/1.1 200 OK
Connection: close
Content-Type: text/html

The above lines are typical for a response.














#!/usr/bin/perl --w
use strict;
use diagnostics;
use LWP::Simple;
# Get the contents
my $content = get "";
# Print the contents
print $content, "\n";



#!/usr/bin/perl -w
use strict;
use diagnostics;
use LWP::Simple;
# Get the contents
my $content = get "";
# Print the contents
print scalar reverse $content, "\n";


HTTP::Request and HTTP::Response

There are times, however, when we will want to create more sophisticated applications, which in turn require more sophisticated means of contacting the server. Doing this will require a number of different objects, each with its own task.

First and foremost, we will have to create an HTTP::Request object. This object, as you can guess from its name, handles everything having to do with an HTTP request. We can create it most easily by saying:

use HTTP::Request;
my $request = new HTTP::Request("GET",

where the first argument indicates the request method we wish to use, and the second argument indicates the target URL.

Once we have created an HTTP request, we need to send it to the server. We do this with a “useragent” object, which acts as a go-between in this exchange. We have already looked at the LWP::Simple useragent in our example programs above.

Normally, a useragent takes an HTTP::Request object as an argument, and returns an HTTP::Response object. In other words, given $request as defined above, our next two steps would be the following:

my $ua = new LWP::UserAgent;

After we have created an HTTP::Response and assigned it to $response, we can perform all sorts of tests and operations.

For starters, we probably want to know the response code we received as part of the response, to ensure that our request was successful. We can get the response code and the accompanying text message with the code and message methods:

my $response_code = $response->code;
my $response_message = $response->message;

If we then say:

print qq{Code: "$code"\n};
print qq{Message: "$message"\n};
we will get the output:
Code: "200"
Message: "OK"
This is well and good, but it presents a bit of a problem: How do we know how to react to different response codes? We know that 200 means everything was fine, but we must build up a table of values in order to know which response codes mean we can continue, and which mean the program should exit and signal an error.

The is_success method for HTTP::Response handles this for us. With it, we can easily check to see if our request went through and if we received a response:

if (!$response->is_success)
   {print "Success. \n";}

The status_line method combines the output from code and message to produce a numeric response code and its printed description.

We can examine the response headers with the headers method. This returns an instance of HTTP::Headers, which offers many convenient methods that allow us to retrieve individual header values:

my $headers = $response->headers;
print "Content-type:", $headers->content_type,
print "Content—length:",
   $headers->content_length, "\n";
print "Date:", $headers->date, "\n
print "Server:", $headers->server, "\n";
Working with the Content

Of course, the Web is not very useful without the contents of the documents we retrieve. HTTP::Response has only one method for retrieving the content of the response, unsurprisingly named content. We can thus say:

my $content = $response->content;

At this point, we are back to where we were with our LWP::Simple example earlier: We have the content of the document inside of $content, which stores the text as a normal string.

Listing 1

If we were interested in using HTTP::Request and HTTP::Response to reverse a document, we could do it as shown in Listing 1. If you were really interested in producing a program like this one, you would probably stick with LWP::Simple and use the get method described there. There is no point in weighing down your program, as well as adding all sorts of method calls, if the object is simply to retrieve the contents from a URL.

The advantage of using a more sophisticated user agent is the additional flexibility it offers. Whether that flexibility is worth the tradeoff in complexity will depend on your needs.

For example, many sites have a robots.txt in their root directory. Such a file tells “robots”, or software-controlled web clients, which sections of the site should be considered out of bounds. These files are a matter of convention, but are a long-standing tradition which should be followed. Luckily, LWP includes the object LWP::RobotUA, which is a user agent that automatically checks the robots.txt file before retrieving a file from a web site. If a file is excluded by robots.txt, LWP::RobotUA will not retrieve it.

LWP::RobotUA also differs from LWP::UserAgent in its attempt to be gentle to servers, by sending only one request per minute. We can change this with the delay method, although doing so is advisable only when you are familiar with the site and its ability to handle a large number of automatically generated requests.

Extracting Tags




For example, given the HTML

<input type="text" value="Reuven"
     name="first_name" size="5">


Listing 2







use URI::URL;




Listing 3

A Small Demonstration


Listing 4







Our whirlwind tour of HTTP and LWP stops here. As you can see, there is not very much to learn about either of them; the trick is to use them to create interesting applications and avoid the pitfalls when working with them. LWP is a package I do not often need, but when I do need it, I find it indispensable.


Reuven M. Lerner is an Internet and Web consultant living in Haifa, Israel. His book Core Perl will be published by Prentice-Hall later this year. Reuven can be reached at The ATF home page is at
Load Disqus comments