inline images and links to other Web pages. HTML consists of text
<html>
<head>
<title>Hello</title>
</head>
<body>
<p>Hello, world!</p>
<p>This is a picture: <img src='some-image.gif'></p>
<p>This is a <a href='another-page.html'>link</a> to another page.</p>
</body>
</html>
Figure 26-1 shows how the browser renders this page.

The browser and server communicate using a protocol called the Hypertext Transfer Protocol (HTTP). While you don't need to worry about the details of the protocol, it's worth understanding that it consists entirely of a sequence of requests initiated by the browser and responses generated by the server. That is, the browser connects to the Web server and sends a request that includes, at the least, the desired URL and the version of HTTP that the browser speaks. The browser can also include data in its request; that's how the browser submits HTML forms to the server.
To reply to a request, the server sends a response made up of a set of headers and a body. The headers contain information about the body, such as what type of data it is (for instance, HTML, plain text, or an image), and the body is the data itself, which is then rendered by the browser. The server can also send an error response telling the browser that its request couldn't be answered for some reason.
And that's pretty much it. Once the browser has received the complete response from the server, there's no communication between the browser and the server until the next time the browser decides to request a page from the server.[281] This is the main constraint of Web programming— there's no way for code running on the server to affect what the user sees in their browser unless the browser issues a new request to the server.[282]
Some Web pages, called
When generating its response to a request, server-side code has four main pieces of information to act on. The first piece of information is the requested URL. Typically, however, the URL is used by the Web server itself to determine
Finally, in order to string together a sequence of individual requests from the same browser, code running in the server can
These are the primitive elements on top of which 99 percent of server-side Web programming is built. The browser sends a request, the server finds some code to handle the request and runs it, and the code uses query parameters and cookies to determine what to do.
You can serve Web content using Common Lisp in a number of ways; there are at least three open-source Web servers written in Common Lisp as well as plug-ins such as mod_lisp[284] and Lisplets[285] that allow the Apache Web server or any Java Servlet container to delegate requests to a Lisp server running in a separate process.
For this chapter, you'll use a version of the open-source Web server AllegroServe, originally written by John Foderaro at Franz Inc.. AllegroServe is included in the version of Allegro available from Franz for use with this book. If you're not using Allegro, you can use PortableAllegroServe, a friendly fork of the AllegroServe code base, which includes an Allegro compatibility layer that allows PortableAllegroServe to run on most Common Lisps. The code you'll write in this chapter and in Chapter 29 should run in both vanilla AllegroServe and PortableAllegroServe.
AllegroServe provides a programming model similar in spirit to Java Servlets—each time a browser requests a page, AllegroServe parses the request and looks up an object, called an
But before I get to that, you need to know how to start AllegroServe and set it up to serve a few files. The first step is to load the AllegroServe code into your Lisp image. In Allegro, you can simply type (require :aserve)
. In other Lisps (or in Allegro), you can load PortableAllegroServe by loading the file INSTALL.lisp
at the top of the portableaserve
directory tree. Loading AllegroServe will create three new packages, NET.ASERVE
, NET.HTML.GENERATOR
, and NET.ASERVE.CLIENT
.[287]
After loading the server, you start it with the function start
in the NET.ASERVE
package. To have easy access to the symbols exported from NET.ASERVE
, from COM.GIGAMONKEYS.HTML
(a package I'll discuss in a moment), and from the rest of Common Lisp, you should create a new package to play in like this:
CL-USER> (defpackage :com.gigamonkeys.web
(:use :cl :net.aserve :com.gigamonkeys.html))
#<The COM.GIGAMONKEYS.WEB package>
Now switch to that package with this IN-PACKAGE
expression:
CL-USER> (in-package :com.gigamonkeys.web)
#<The COM.GIGAMONKEYS.WEB package>
WEB>
Now you can use the exported names from NET.ASERVE
without qualification. The function start
starts the server. It takes quite a number of keyword parameters, but the only one you need to pass is :port
, which specifies the port to listen on. You should probably use a high port such as 2001 instead of the default port for HTTP servers, 80, because on Unix-derived operating systems only the root user can listen on ports below 1024. To run AllegroServe listening on port 80 on Unix, you'd need to start Lisp as root and then use the :setuid
and :setgid
parameters to tell start
to switch its identity after opening the port. You can start a server listening on port 2001 like this:
WEB> (start :port 2001)