| iMatix home page | Xitami home page | << | < | > | >> |
Xitami Version 2.4d7 |
By Robin Dunn Any serious web-based application relies, possibly quite heavily, on
dynamic content. In other words, dynamically generated pages.
To facilitate the need for dynamic content, CGI was invented back in the
dark-ages of the Web (just a few years ago.) While CGI provides the ability
to do dynamic generation of web pages as well as quite an elegant and
flexible interface, it also has a very big wart. It is too slow for
serious work. The basic model that CGI follows is:
Unfortunately, each time the CGI process is started, it can be several
seconds before it is able to even begin processing the request. Depending on
the OS there may be a large amount of overhead in creating a new process.
There may be a Perl or other language interpreter to load and initialize,
followed by loading and parsing the CGI script itself. Database connections
may have to be made, files opened, etc.
Because of the shortcomings of CGI, server extension APIs were created by
the various web server vendors. For example, Netscape provides NSAPI,
Microsoft ISAPI, Apache ASAPI, and even Xitami has WSX. (Isn't it refreshing
to not have "SAPI" at the end?)
While these extension APIs do away with the overhead of process creation
they introduce a few warts of their own:
There have been several alternatives that combine the ease of use and
flexibility of CGI with the efficiency of Server extension APIs. One of the
most popular of these is called FastCGI
developed by Open Market, Inc.
FastCGI or other persistent CGI alternatives are, as the name suggests, a CGI
type of interface that is Faster than CGI. It could potentially be up to 20
times faster, or more, depending on what kind of startup/initialization
overhead the script has. It does this phenomenal feat by allowing the CGI
process to handle more than a single request each time it starts up. The web
server communicates with the running persistent CGI process via a socket and
sends the appropriate data to the persistent CGI process when the reqest is
made. The persistent CGI process does its thing, generates an html page or
other response and sends it back over the socket and then instead of
terminating, it waits for the next request.
Begining with version 2.2a, Xitami includes a persistent CGI extension
called LRWP, (which stands for Long Running Web Process.) LRWP is written as
a WSX agent which implements a simple protocol for communicating with external
processes called Peers. The peer process simply waits for the requests to
come from Xitami and then responds with a valid http response, just like a
CGI program. The main difference is that like other persistent CGI
solutions, the LRWP peer waits around for another HTTP request instead of
terminating.
LRWP is not FastCGI, but it is very similar. The protocol between Xitami
and the LRWP Peer is much simpler than the FastCGI protocol, and therefore
less prone to implementation differences or errors. However, given the right
circumstances it is possible to run the same program as both a LRWP Peer and
a FastCGI Peer with only minor differences in the startup code.
As mentioned above, the communications protocol between the LRWP Peer and
the LRWP Agent within Xitami is quite simple.
If multiple peers connect with the same alias name, then multiple
simultaneous requests will be able to be handled. If there are more
simultaneous requests then there are peers to handle them, then the
LRWP Agent in Xitami will queue up the requests and wait for a peer
to complete its current request.
Each component of the startup string is separated by a character with
an ASCII value of 255.
The content returned to the server will be treated just like the
output from CGI programs, so content-type and other headers are
significant.
There may be situations where this is a highly desirable feature, for
example if you are running a contest and only want to collect 100
entries, the peer could exit after collecting the desired amount and
then Xitami will fall-back to a static document at the same URI that
explains that the contest is now closed.
Another reason to exit is to ensure that any memory leaks in your
program or the interpreter it is built upon are released. In order for
this to be effective you probably will want to have the ability to
automatically restart your peer processes. (UPM is currently being
modified to allow this type of functionality.) For example, I know
people with scripts running in the FastCGI environment that only allow
the processes to handle 50 requests and then they exit and get restarted
by an external process monitor.
LRWP programs receive the same environment variables as a CGI program.
If you're in doubt as to which ones these are, either read this manual again
or run the testcgi program supplied with Xitami.
Included with Xitami is a small library of C functions to assist
in writing LRWP Peers. The source files are lrwplib.h and lrwplib.c and
contain the following functions:
Returns NULL on success and a pointer to an error message otherwise.
Returns 0 on success and -1 otherwise.
Returns 0 on success and -1 otherwise.
Returns 0 on success and -1 otherwise.
Returns 0 on success and -1 otherwise.
Returns 0 on success and -1 otherwise.
Introduction
CGI
Server Extensions
Persistent CGI
LRWP
The LRWP protocol
ENV size
ENV data as a series of name=value pairs
POST size
POST data, if any
LRWP Environment Variables
The LRWP Library
char* lrwp_connect(LRWP* lrwp, /* pointer to UNCONNECTED LRWP object */
char* appname, /* Name or alias of Peer app */
char* host, /* hostname/IP address to connect to */
char* port, /* string containing port number */
char* vhost) /* optional virtual hostname */
Connects to the LRWP agent running in Xitami on host and port. Sends
the given appname to use as the URI alias that will trigger requests to
be sent to this peer. If vhost is given, this peer will only be sent
requests origininating from that virtual host. This function assumes
that the LRWP structure is uninitialized and clears it before use.
int lrwp_accept_request(LRWP* lrwp) /* pointer to CONNECTED LRWP object */
This funation waits for and recieves a request from the LRWP agent, and
populates the LRWP structure with the request data.
int lrwp_send_string(LRWP* lrwp, /* pointer to CONNECTED LRWP object */
char* st) /* an ouput string */
This function appends a string to the response buffer.
lrwp_finish_request() must be called to send the response back to Xitami.
int lrwp_send_data(LRWP* lrwp, /* pointer to CONNECTED LRWP object */
void* data, /* pointer to a data buffer */
size_t len) /* size of the data buffer */
Appends a buffer of (possibly binary) data of the specified size to
the response buffer. lrwp_finish_request() must be called to send the
response back to Xitami.
int lrwp_finish_request(LRWP* lrwp) /* pointer to CONNECTED LRWP object */
Completes the request by sending the response buffer back to Xitami
and prepares the lwrp structure to receive another request.
int lrwp_close(LRWP* lrwp) /* pointer to CONNECTED LRWP object */
Closes the connection to Xitami.
A Simple Example Using C
#include "sfl.h"
#include "lrwplib.h"
void main()
{
LRWP lrwp;
int count = 0;
int err;
char* errMsg;
char buf[256];
sock_init();
errMsg = lrwp_connect(&lrwp, "hello", "localhost", "81", "");
if (errMsg) {
fprintf(stderr, "%s\n", errMsg);
exit(1);
}
/* only handle 5 reqests, then exit */
while (count < 5 && lrwp_accept_request(&lrwp) != -1) {
count += 1;
lrwp_send_string(&lrwp, "Content-type: text/html\r\n\r\n");
lrwp_send_string(&lrwp,
"<HTML><HEAD><TITLE>hello</TITLE></HEAD>\n<BOD
sprintf(buf, "<H2>Hello from LRWP</H2>\nCount = %d", count);
lrwp_send_string(&lrwp, buf);
lrwp_send_string(&lrwp, "\n</BODY></HTML>\n");
lrwp_finish_request(&lrwp);
}
lrwp_close(&lrwp);
sock_term();
}
A Simple Example Using Python
from lrwplib import LRWP
def main():
lrwp = LRWP('hello', 'localhost', 81)
lrwp.connect()
count = 0
while count < 5: # exit after servicing 5 requests
count = count + 1
req = lrwp.acceptRequest()
req.out.write('Content-type: text/html\r\n\r\n')
req.out.write('<HTML><HEAD><TITLE>hello</TITLE><')
req.out.write('</HEAD>\n')
req.out.write('<H2>Hello from LRWP</H2>\nCount = ' + str(count))
req.out.write('\n</BODY></HTML>\n')
req.finish()
lrwp.close()
if __name__ == '__main__':
main()
| << | <
| > | >>
| Welcome To Xitami
| Table Of Contents
| Installing Xitami
| Administration
| Configuration
| Using The Common Gateway Interface (CGI)
| Using SSI and Filters
| Image Maps
| Virtual Hosts
| The FTP Service
| A Beginner's Guide
| Writing Web Server Extension (WSX) Agents
| Extending Xitami with External Peer Processes
| FAQ
| Technical Implementation
| Getting Support
| Release History
| License Agreement
Copyright © 1996-99 iMatix Corporation