Below is a tiny HTTP server - it's almost as small as one can make an HTTP server in java (I think - please prove me wrong!), except that it's got a couple of features (proper DOS vs UNIX / \ handling, index.html generation) that make it actually (slightly) useful.
This server is totally unsuited to any kind of public or production use - it has some serious security problems, including that it doesn't confine requests to a given subdirectory (e.g. htdocs) and so can be used to relay any file that can be read by the user running the server.
It also doesn't perform any of the sanity checks on the pathname that a mature server would and so may have worse security problems even than noted above.
Equally, there is no attempt to resist deliberate or accidental denial-of-service, and in particular doesn't scale well due to its spawning a new java thread for every received query.
Features:
- To run it, just type
java h - it doesn't take any parameters. - works correctly on win32 or unix.
- if URL ends with "/", httpd appends "index.html".
- will send files of any length.
- binary files, such as images, are supported.
- the server is multi-threaded - a new java thread is spawned to handle each incoming HTTP GET request (up to the number of threads your java runtime will allow you to spawn - performance will probably get very slow long before that point.
- runs ok under MS-IE5's jview runtime, JDK 1.1.x and all Java2 platforms.
- doesn't use any deprecated APIs.
Limitations:
- hardwired to listen on port 8181 - if you want it to listen on a different port, change the 8181 on the fourth line to your chosen value.
- only handles the HTTP 1.0 GET request. Let's face it - that's all that lots of webpages ever need.
- document base is current directory.
- isn't smart enough to notice that the URL you've supplied is a directory - so it doesn't append "index.html" in those cases. This also means there's no kind of directory-index generation.
- doesn't set MIME type in HTTP return header.
- very basic error handling - sends a very basic http 404 response to anything that might even slightly resemble an error.
Portable version sourcecode:
// h.java (c)1999-2003 W.Finlay McWalter. Licence: GPLv2.0
// v1: initial version
// v2: squished down by four lines
// v3: Jonathan Headland removed a couple of redundant checks
// v4: Engelbert Gruber changed input stream to a BufferedReader
// v5: small speedup/codesize-reduction in writeBytes length code
//-----------------------------------------------------------------
import java.net.*;import java.io.*;import java.util.*;public class
h extends Thread{Socket c;public h(Socket s){c=s;start();}public
static void main(String[]a){try{ServerSocket s=new ServerSocket(
8181);while(true){new h(s.accept());}}catch(Exception e){}}public
void run(){try{BufferedReader i=new BufferedReader(new
InputStreamReader(c.getInputStream()));DataOutputStream o=new
DataOutputStream(c.getOutputStream());try{while(true){String s=i.
readLine();if(s.length()<1)break;if(s.startsWith("GET")){
StringTokenizer t=new StringTokenizer(s," ");t.nextToken();String p
=t.nextToken();p=(".".concat(((p.endsWith("/"))?p.concat(
"index.html"):p))).replace('/',File.separatorChar);int l=(int)new
File(p).length();byte[]b=new byte[l];FileInputStream f=new
FileInputStream(p);f.read(b);o.writeBytes("HTTP/1.0 200 OK\nConten"
+"t-Length:"+l+"\n\n");o.write(b,0,l);}}}catch(Exception e){o.
writeBytes("HTTP/1.0 404 ERROR\n\n\n");}o.close();}catch(Exception
e){}}}
Here's a smaller version, incorporating some improvements using String.split to replace Stringtokenizer (kindly submitted by Luke). As String.split was introduced with JDK1.4, versions with this change won't work on earlier runtimes. Here's the sourcecode for it:
// h.java (c)1999-2004 W.Finlay McWalter. Licence: GPLv2.0
// v1: me: initial version
// v2: me: squished down by four lines
// v3: Jonathan Headland: removed a couple of redundant checks
// v4: Engelbert Gruber: changed input stream to a BufferedReader
// v5: me: small speedup/codesize-reduction in writeBytes length code
// v6: Luke: replaced StringTokenizer with split, saving two lines
// v7: Luke: made FileInputStream anon me: GET->GE
//-----------------------------------------------------------------
import java.net.*;import java.io.*;public class h extends Thread{
Socket c;public h(Socket s){c=s;start();}public static void main(
String[]a){try{ServerSocket s=new ServerSocket(8181);for(;;){new h(
s.accept());}}catch(Exception e){}}public void run(){try{
BufferedReader i=new BufferedReader(new InputStreamReader(c.
getInputStream()));DataOutputStream o=new DataOutputStream(c.
getOutputStream());try{String s,p;while((s=i.readLine()).length()>0
){if(s.startsWith("GE")){p=(s.split(" "))[1];p=("."+(p.endsWith("/"
)?p+"index.html":p)).replace('/',File.separatorChar);int l=(int)new
File(p).length();byte[]b=new byte[l];new FileInputStream(p).read(b)
;o.writeBytes("HTTP/1.0 200 OK\nContent-Length:"+l+"\n\n");o.write(
b,0,l);}}}catch(Exception e){o.writeBytes("HTTP/1.0 404 ERROR\n\n")
;}o.close();}catch(Exception e){}}}