Web Site of Robert John Morton
My Programs: Web Server
A simple non-caching non-proxy HTTP server written in Java as a command-line initiated program.
- runs on any operating system for which there exists a Java or jre resource
- started from operating system's command line or from a script (batch file)
- serves files from the directory specified on the start-up command line
- listens for HTTP requests on designated server port
- supports the HTTP GET method only
- keeps a log of all fulfilled requests (hits) and standard HTTP error returns
- keeps a separate log of all Java Exceptions which may occur
- optionally keeps a trace file of all I/O through session ports
- easily extended to handle caching and proxy operation
- easily adapted to serve SQL and accept all forms of data submissions
Sample 'start-up' command lines:
java starter /home/rob/website
java starter /home/rob/website 81
java starter /home/rob/website 80 -trace
The first example starts up the server to serve files from the absolute directory shown, accepting HTTP request from Port 80 - the default HTTP port. The second example does the same, except that it accepts HTTP requests from Port 81. The third example does the same as the first example, but the server, in addition, copies all data passing in and out of the session port into a file called trace.txt. In the third example, Port 80 has to be specified as the second command line argument as a spacer to make the '-trace' switch the third argument. In any of the examples, the end-user java runtime resource 'jre' can be used instead of the full 'java' runtime resource.
The reason the command 'starter' is used is that the server itself is an abstract class which has to be instantiated before it can be run. The small Java class called starter is simply there to contain the necessary public static method called main() which creates an instance of the server, starts its execution thread, then waits. To stop the server, one simply hits any key when the terminal in which 'starter' is running has input focus. This causes main() to signal the server to stop. The server holds open its port until it has finished any pending HTTP service requests. It then kills its own execution thread. This allows starter's main() method to destroy the server instance and terminate gracefully.
The heart of the server itself is the listen() method. This is looped repeatedly by the server's execution thread. This method listens to the server socket on Port 80 (or whatever port was specified on the command line) until an HTTP service request appears. The method accept() normally blocks until a request appears. However, it was in the run() method set to time out every 60 seconds to check whether the server thread has been terminated. When an HTTP service request arrives, accept() allocates a session port through which details of the request can be received and answered. This is not done through Port 80 because it could block other incoming requests.
A request object is then created for the new request whose details are then sucked in through the newly allocated session port and plonked neatly into the request object. The new request is then validated. If found to be invalid, or if this server is not equipped to fulfil it, an appropriate HTTP Error object is created, filled out as an HTML file, and then sent to from whence the request came. If the request is found to be valid and can be fulfilled, a new response object is created. This, together with the content of the requested file are then barfed down the session port to the user agent which requested it. And so back to await the next request.
Understanding the rest of the source code is respectfully left as an exercise for my esteemed reader, who, upon finding understanding forthcoming, may perhaps be so kind as to point me in the direction of gainful employment. I could then finally relinquish my lasting Fellowship of the Ancient and Noble Order of the Long-Term Unemployed.
© 2000 Robert John Morton