package com.limegroup.gnutella.bootstrap; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.limegroup.gnutella.ErrorService; /** * Simulates a GWebCache HTTP server. Listens on a port, accepts a single * connection, records request and writes result. */ public class TestBootstrapServer { private static final Log LOG = LogFactory.getLog(TestBootstrapServer.class); ServerSocket _ss; List _sockets = new LinkedList(); volatile String _request; volatile String _response; volatile String _responseData=""; boolean _allowConnectionReuse = false; int _numConnections = 0; int _numRequests = 0; /** Starts a single bootstrap server listening on the given port * Call setResponse() to set abnormal HTTP responses. * Call setResponseData() to modify the response data. * @exception IOException this couldn't list on the port */ public TestBootstrapServer(int port) throws IOException { setResponse("HTTP/1.0 200 OK"); _ss=new ServerSocket(); _ss.setReuseAddress(true); _ss.bind(new InetSocketAddress(port)); Thread runner=new RunnerThread(); runner.setName("TBS, Port: " + port); runner.start(); } /** * Returns the number of connection attempts this simple server received. */ public int getConnectionAttempts() { return _numConnections; } /** * Returns the number of requests this simple server recieved. */ public int getRequestAttempts() { return _numRequests; } /** * Sets whether or not this simple server should allow the connection * to be reused for multiple requests. */ public void setAllowConnectionReuse(boolean reuse) { _allowConnectionReuse = reuse; } /** Sets what this should send for any HTTP response, without any newline * characters. Default value: "HTTP/1.0 200 OK".*/ public void setResponse(String httpResponse) { this._response=httpResponse; //add EOL and blank line } /** Sets the data this should send for any HTTP response. Default value: * "". Example value: "18.239.0.144:6346\r\n1.2.3.4\r\n\r\n.*/ public void setResponseData(String data) { this._responseData=data; } /** Returns the request line received, or null if none. */ public String getRequest() { return _request; } /** Frees any resources. */ public void shutdown() { try { _ss.close(); } catch (IOException e) { } for(Iterator i = _sockets.iterator(); i.hasNext(); ) { try { Socket s = (Socket)i.next(); if(s != null ) s.close(); } catch (IOException e) {} } } private class RunnerThread extends Thread { public void run() { try { run2(); } catch (IOException e) { } catch(Throwable e) { ErrorService.error(e); } } public void run2() throws IOException { while(true) { LOG.debug("waiting to accept new connection"); Socket s = _ss.accept(); LOG.debug("accepted new connection"); _numConnections++; _sockets.add(s); BufferedReader in= new BufferedReader( new InputStreamReader(s.getInputStream())); OutputStream out = s.getOutputStream(); while(true) { LOG.debug("reading new request"); _request=in.readLine(); LOG.debug("read: " + _request); if(_request == null) break; // gobble up headers. String restOfLine = _request; while(!restOfLine.equals("")) { restOfLine = in.readLine(); if(restOfLine == null) break; LOG.debug("continued read: " + restOfLine); } LOG.debug("finished reading request."); _numRequests++; out.write((_response + "\r\n\r\n").getBytes()); out.write(_responseData.getBytes()); out.flush(); if(!_allowConnectionReuse) break; } out.close(); if(!_allowConnectionReuse) break; } } } }