| iMatix home page | Xitami home page | << | < | > | >> |
![]() Version 2.4c3 |
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.
ENV size | ENV data as a series of name=value pairs | POST size | POST data, if any |
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:
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.
Returns NULL on success and a pointer to an error message otherwise.
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.
Returns 0 on success and -1 otherwise.
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.
Returns 0 on success and -1 otherwise.
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.
Returns 0 on success and -1 otherwise.
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.
Returns 0 on success and -1 otherwise.
int lrwp_close(LRWP* lrwp) /* pointer to CONNECTED LRWP object */Closes the connection to Xitami.
Returns 0 on success and -1 otherwise.
#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(); }
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 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 |