Mainline for the HTTP tracer tool
/** * Copyright (c) 2002 by Phil Hanna * All rights reserved. * * You may study, use, modify, and distribute this * software for any purpose provided that this * copyright notice appears in all copies. * * This software is provided without warranty * either expressed or implied. */ import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.io.Writer; import java.net.ServerSocket; import java.net.Socket; /** * Mainline for the HTTP tracer tool */ public class MainHTTPTracerTool { public static void main(String[] args) throws IOException { String opt_host = null; String opt_port = null; String opt_tracerPort = null; String opt_log = null; try { // Parse command line arguments for (int i = 0, n = args.length; i < n; i++) { String arg = args[i]; if (arg.equals("-h")) { showUsage(); return; } if (arg.equals("-host") && (i + 1 < n)) opt_host = args[++i]; else if (arg.equals("-port") && (i + 1 < n)) opt_port = args[++i]; else if (arg.equals("-tracerPort") && (i + 1 < n)) opt_tracerPort = args[++i]; else if (arg.equals("-log") && (i + 1 < n)) opt_log = args[++i]; else throw new IllegalArgumentException("Unrecognized option " + arg); } // Verify that there is no port conflict int testTracerPort = (opt_tracerPort == null) ? Tracer.DEFAULT_PORT : Integer.parseInt(opt_tracerPort); int testHostPort = (opt_port == null) ? RequestHandler.DEFAULT_PORT : Integer.parseInt(opt_port); if (testTracerPort == testHostPort) throw new IllegalArgumentException( "Cannot assign port and tracerPort both to " + testHostPort); } catch (IllegalArgumentException e) { System.err.println(e.getMessage()); return; } // Create the tracer and set its properties Tracer tracer = new Tracer(); if (opt_host != null) tracer.setHost(opt_host); if (opt_port != null) tracer.setPort(Integer.parseInt(opt_port)); if (opt_tracerPort != null) tracer.setTracerPort(Integer.parseInt(opt_tracerPort)); if (opt_log != null) tracer.setLogWriter(new FileWriter(opt_log)); // Start it running tracer.start(); } public static final void showUsage() { String[] text = { "", "usage: java -jar tracer.jar [options]", "", "where options are:", "", "-host <hostName> (default is localhost)", "-port <hostPort> (default is 80)", "-tracerPort <localPort> (default is 8601)", "-log <fileName> (default is stdout)", }; for (int i = 0; i < text.length; i++) System.out.println(text[i]); } } /** * Copyright (c) 2002 by Phil Hanna All rights reserved. * * You may study, use, modify, and distribute this software for any purpose * provided that this copyright notice appears in all copies. * * This software is provided without warranty either expressed or implied. */ /** * Acts as a proxy web server, capturing requests and responses and echoing the * headers to a log stream. */ class Tracer extends Thread implements Logger { public static final int DEFAULT_PORT = 8601; private String host; private int port; private int tracerPort; private PrintWriter logWriter; public void run() { // Set defaults if not otherwise specified if (tracerPort == 0) tracerPort = DEFAULT_PORT; if (logWriter == null) logWriter = new PrintWriter(System.out); // Start proxy server try { log("M: Opening tracer server on tracerPort " + tracerPort); ServerSocket server = new ServerSocket(tracerPort); // Loop forever while (true) { // Wait for connection log("M: Waiting for connections"); Socket client = server.accept(); log("M: Connection received from " + client); // Dispatch it to a request handler thread RequestHandler rh = new RequestHandler(client); rh.setLogger(this); if (host != null) rh.setHost(host); if (port != 0) rh.setPort(port); rh.start(); } } catch (IOException e) { e.printStackTrace(); } } // =========================================== // Implementation of Logger // =========================================== /** * Writes a message to the log * * @param message * the message */ public synchronized void log(String message) { logWriter.println(message); logWriter.flush(); } // =========================================== // Property setters // =========================================== /** * Sets the host. * * @param host * the host. */ public void setHost(String host) { this.host = host; } /** * Sets the port. * * @param port * the port. */ public void setPort(int port) { this.port = port; } /** * Sets the tracerPort. * * @param tracerPort * the tracerPort. */ public void setTracerPort(int tracerPort) { this.tracerPort = tracerPort; } /** * Sets the logWriter. * * @param logWriter * the logWriter. */ public void setLogWriter(Writer logWriter) throws IOException { this.logWriter = new PrintWriter(logWriter); } } /** * Copyright (c) 2002 by Phil Hanna All rights reserved. * * You may study, use, modify, and distribute this software for any purpose * provided that this copyright notice appears in all copies. * * This software is provided without warranty either expressed or implied. */ /** * A proxy HTTP server that handles a single request */ class RequestHandler extends Thread { public static final String DEFAULT_HOST = "localhost"; public static final int DEFAULT_PORT = 80; private Socket client; private Logger logger; private String host; private int port; // =========================================== // Constructors // =========================================== /** * Creates a new <code>RequestHandler</code> for the specified client */ public RequestHandler(Socket client) { this.client = client; } // =========================================== // Instance methods // =========================================== /** * Copies the request from the client to the server and copies the response * back to the client. */ public void run() { try { // Open a socket to the web server if (host == null) host = DEFAULT_HOST; if (port <= 0) port = DEFAULT_PORT; Socket server = new Socket(host, port); // Open I/O streams to the client InputStream cin = new BufferedInputStream(client.getInputStream()); OutputStream cout = new BufferedOutputStream(client .getOutputStream()); // Open I/O streams to the server InputStream sin = new BufferedInputStream(server.getInputStream()); OutputStream sout = new BufferedOutputStream(server .getOutputStream()); // Copy request line and headers from client to server, // echoing to logger if specified. Stop after the // first empty line (end of headers) int contentLength = 0; StringBuffer sb = new StringBuffer(); for (;;) { // Read a byte from client // and copy it to server int c = cin.read(); sout.write(c); // Ignore CR at end of line if (c == '\r') continue; // If LF, process the line if (c == '\n') { String line = sb.toString(); sb = new StringBuffer(); // Log the line logger.log("C: " + line); // If this is an empty line, // there are no more headers if (line.length() == 0) break; // If it is a content length header, // save the content length int p = line.indexOf(":"); if (p != -1) { String key = line.substring(0, p).trim(); String value = line.substring(p + 1).trim(); if (key.equalsIgnoreCase("content-length")) contentLength = Integer.parseInt(value); } } // Otherwise, append char to string buffer else sb.append((char) c); } sout.flush(); // If content length was specified, read input stream // and copy to server if (contentLength > 0) { for (int i = 0; i < contentLength; i++) { int c = cin.read(); sout.write(c); } sout.flush(); } // Echo the response back to the client sb = new StringBuffer(); while (true) { // Read a byte from server // and copy it to client int c = sin.read(); cout.write(c); // Ignore CR at end of line if (c == '\r') continue; // If LF, process the line if (c == '\n') { String line = sb.toString(); sb = new StringBuffer(); // Log the line logger.log("S: " + line); // If this is an empty line, // there are no more headers if (line.length() == 0) break; } // Otherwise, append char to string buffer else sb.append((char) c); } cout.flush(); // Copy remaining bytes to client int bytesCopied = 0; while (true) { int c = sin.read(); if (c == -1) break; cout.write(c); bytesCopied++; } if (bytesCopied > 0) cout.flush(); // Close streams and sockets cin.close(); cout.close(); client.close(); sin.close(); sout.close(); server.close(); } catch (IOException e) { e.printStackTrace(); } } // =========================================== // Property setters // =========================================== /** * Sets the logger. * * @param logger * the logger. */ public void setLogger(Logger logger) { this.logger = logger; } /** * Sets the host. * * @param host * the host. */ public void setHost(String host) { this.host = host; } /** * Sets the port. * * @param port * the port. */ public void setPort(int port) { this.port = port; } } /** * Copyright (c) 2002 by Phil Hanna All rights reserved. * * You may study, use, modify, and distribute this software for any purpose * provided that this copyright notice appears in all copies. * * This software is provided without warranty either expressed or implied. */ /** * The set of methods that must be implemented by a class that logs message */ interface Logger { /** * Logs a message */ public void log(String s); }
1. | HTTP Echo For testing | ||
2. | A command-line interface to a Web server |