NOTE:
These slides have not been updated since 2003. They have been superseded by the book
Anders Møller and Michael Schwartzbach, February 2006 |
INTERACTIVE WEB SERVICES WITH JAVA |
Read command-line arguments and open server socket:
import java.net.*; import java.io.*; import java.util.*; public class FileServer { public static void main(String[] args) { // read arguments if (args.length!=2) { System.out.println("Usage: java FileServer <port> <wwwhome>"); System.exit(-1); } int port = Integer.parseInt(args[0]); String wwwhome = args[1]; // open server socket ServerSocket socket = null; try { socket = new ServerSocket(port); } catch (IOException e) { System.err.println("Could not start server: " + e); System.exit(-1); } System.out.println("FileServer accepting connections on port " + port); |
Begin request-response loop:
// request handler loop while (true) { Socket connection = null; try { // wait for request connection = socket.accept(); BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream())); OutputStream out = new BufferedOutputStream(connection.getOutputStream()); PrintStream pout = new PrintStream(out); |
Read first line of request to get file name:
// read first line of request (ignore the rest) String request = in.readLine(); if (request==null) continue; log(connection, request); while (true) { String misc = in.readLine(); if (misc==null || misc.length()==0) break; } |
Process request by checking that the request is well-formed and permitted. For directory requests that do not end in '/', redirect browser. For files, send back the contents:
// parse the line if (!request.startsWith("GET") || request.length()<14 || !(request.endsWith("HTTP/1.0") || request.endsWith("HTTP/1.1"))) { // bad request errorReport(pout, connection, "400", "Bad Request", "Your browser sent a request that " + "this server could not understand."); } else { String req = request.substring(4, request.length()-9).trim(); if (req.indexOf("..")!=-1 || req.indexOf("/.ht")!=-1 || req.endsWith("~")) { // evil hacker trying to read non-wwwhome or secret file errorReport(pout, connection, "403", "Forbidden", "You don't have permission to access the requested URL."); } else { String path = wwwhome + "/" + req; File f = new File(path); if (f.isDirectory() && !path.endsWith("/")) { // redirect browser if referring to directory without final '/' pout.print("HTTP/1.0 301 Moved Permanently\r\n" + "Location: http://" + connection.getLocalAddress().getHostAddress() + ":" + connection.getLocalPort() + "/" + req + "/\r\n\r\n"); log(connection, "301 Moved Permanently"); } else { if (f.isDirectory()) { // if directory, implicitly add 'index.html' path = path + "index.html"; f = new File(path); } try { // send file InputStream file = new FileInputStream(f); pout.print("HTTP/1.0 200 OK\r\n" + "Content-Type: " + guessContentType(path) + "\r\n" + "Date: " + new Date() + "\r\n" + "Server: FileServer 1.0\r\n\r\n"); sendFile(file, out); // send raw file log(connection, "200 OK"); } catch (FileNotFoundException e) { // file not found errorReport(pout, connection, "404", "Not Found", "The requested URL was not found on this server."); } } } } out.flush(); |
Catch exceptions and close connection:
} catch (IOException e) { System.err.println(e); } try { if (connection != null) connection.close(); } catch (IOException e) { System.err.println(e); } } } |
Auxiliary methods for logging and error reporting:
private static void log(Socket connection, String msg) { System.err.println(new Date() + " [" + connection.getInetAddress().getHostAddress() + ":" + connection.getPort() + "] " + msg); } private static void errorReport(PrintStream pout, Socket connection, String code, String title, String msg) { pout.print("HTTP/1.0 " + code + " " + title + "\r\n" + "\r\n" + "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n" + "<TITLE>" + code + " " + title + "</TITLE>\r\n" + "</HEAD><BODY>\r\n" + "<H1>" + title + "</H1>\r\n" + msg + "<P>\r\n" + "<HR><ADDRESS>FileServer 1.0 at " + connection.getLocalAddress().getHostName() + " Port " + connection.getLocalPort() + "</ADDRESS>\r\n" + "</BODY></HTML>\r\n"); log(connection, code + " " + title); } |
Auxiliary methods for guessing MIME type and sending file contents:
private static String guessContentType(String path) { if (path.endsWith(".html") || path.endsWith(".htm")) return "text/html"; else if (path.endsWith(".txt") || path.endsWith(".java")) return "text/plain"; else if (path.endsWith(".gif")) return "image/gif"; else if (path.endsWith(".class")) return "application/octet-stream"; else if (path.endsWith(".jpg") || path.endsWith(".jpeg")) return "image/jpeg"; else return "text/plain"; } private static void sendFile(InputStream file, OutputStream out) { try { byte[] buffer = new byte[1000]; while (file.available()>0) out.write(buffer, 0, file.read(buffer)); } catch (IOException e) { System.err.println(e); } } } |
Obvious extensions:
COPYRIGHT © 2002-2003 ANDERS MØLLER & MICHAEL I. SCHWARTZBACH |