Home | Libraries | People | FAQ | More |
Tip | |
---|---|
If you are familiar with the CGI protocol, you can skip straight to the 10 Minute Intro. |
CGI is a simple protocol for writing dynamic web-enabled applications. The protocol's simplicity is key to its success, but the simplicity brings with it some limitations.
By far the most significant limitation is that a CGI program handles one request before exiting. If handling a request involves resources that are expensive to initialise (eg. opening a database), then CGI may not scale as well as you would like. For true scalability, you may want FastCGI.
The following example is generated from the linked source file.
#include <boost/cgi/cgi.hpp> namespace cgi = boost::cgi; int handle_request(cgi::request& req, cgi::response& resp) { if (req.cookies.count("user_name")) { if (req.get.pick<std::string>("reset", "") == "1") { resp<< cgi::cookie("user_name") << cgi::redirect(req, req.script_name()) << cgi::content_type("text/plain"); } else { std::string user_name( req.cookies["user_name"] ); if (!user_name.empty()) { resp<< cgi::content_type("text/html") << "<p>Hello there, " << req.cookies["user_name"] << ". How are you?</p>" << "<a href=\"" << req.script_name() << "?reset=1\">Reset</a>"; } } } else if (req.form.count("user_name")) { std::string user_name (req.form["user_name"]); resp<< cgi::cookie("user_name", user_name) << cgi::header("Date", "Tue, 15 Nov 1994 08:12:31 GMT") << cgi::content_type("text/html") << "Hello there, " << user_name << ". You're new around here." << "user_name.length() = " << user_name.length() ; } else { resp<< cgi::content_type("text/html") << "Hello there. What's your name?" "<p />" "<form method='POST'>" "<input type='text' name='user_name' />" "<input type='submit' />"; } return cgi::commit(req, resp); } int main(int, char**) { cgi::request req; cgi::response resp; return handle_request(req, resp); }
A catch-all header is available which includes all of the headers you should need for CGI.
For the sake of clarity we alias the
|
||||||||||||||||||||||
The first thing to do is write a handler function which takes a request and a response and does all request-specific work. Later, we will look at writing the code that calls this function.
|
||||||||||||||||||||||
In our request handler, we will assume that the request has been fully-parsed
and we can access all of the request data. The request data is available
using public members of a
A CGI request has several types of variables available. These are listed
in the table below, assuming that
Let's assume you now want to check if the user has a cookie, "user_name", set. We can check if a user has a cookie set like this:
|
||||||||||||||||||||||
First, we need to be able to clear the cookie we are setting. We will reset
the cookie if the user navigates to
The
One of them is The default value can be any type that supports Boost.Lexical_cast. If the key isn't found in the map, or the value cannot be cast to the type of the default value, the default is returned.
|
||||||||||||||||||||||
Set a cookie with no value to delete it.
|
||||||||||||||||||||||
The
|
||||||||||||||||||||||
Looking up a request cookie in The lookup is case-insensitive, so "USER_NAME" and "User_Name" would be equivalent lookup keys. If the cookie is set, we'll be polite and say hello before quitting.
|
||||||||||||||||||||||
That's all we want to say for now, so we can return.
If you are familiar with CGI programming, you will notice the lack of any
HTTP headers in the response. A
If you don't explicitly set any response headers, a default header
|
||||||||||||||||||||||
If the cookie isn't set, we will check if the user has posted a
|
||||||||||||||||||||||
If they have told us their name, we should set a cookie so we remember it next time. Then we can say hello and exit.
There are two ways to set a cookie: either directly using
Again, the request object isn't buffered, so we are going to keep using
the This time, we shall send a Date header. If we do this (ie. send a header ourselves), we must also set the Content-type header, like below.
|
||||||||||||||||||||||
Now, if we have no idea who they are, we'll send a form asking them for
their name. As the default
|
||||||||||||||||||||||
A CGI program will handle one request each time it is invoked. Returning a non-zero status to the OS indicates an error handling the request. I don't know that HTTP servers treat non-zero exit codes specially. [3]
To send the response back to the request, use
|
||||||||||||||||||||||
We now have a request handler in all of it's contrived glory.
The program's
|
||||||||||||||||||||||
At this point, the environment variables are accessible. This includes
cookie and form variables too, which are all parsed by default-constructing
a
|
||||||||||||||||||||||
The
Writing to a
Not only does buffering avoid network latency issues, but being able to
cancel the response and send another is much cleaner than sending half
a response, followed by "...Ooops". A When sending a response that is large relative to the amount of memory available to the program, you may want to write unbuffered.
|