McWalter.org :: Tiny HTTPd in Java


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:

Limitations:

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){}}}