}     if (_pf != null) { Response resp = _pf.getResponse(); if (resp != null) { response = resp; } else { _logger.severe("Submitting the original, (possibly) modified response to the server"); }
    public void run() {        if (_sock != null) {            try {                _clientIn = _sock.getInputStream();                _clientOut = _sock.getOutputStream();                if (_simulator != null) {                    _clientIn = _simulator.wrapInputStream(_clientIn);                    _clientOut = _simulator.wrapOutputStream(_clientOut);                }            } catch (IOException ioe) {                _logger.severe("Error getting socket input and output streams! " + ioe);                return;            }        }        try {            Request request = null;            // if we do not already have a base URL (i.e. we operate as a normal             // proxy rather than a reverse proxy), check for a CONNECT            if (_base == null) {                try {                    request = new Request();                    request.read(_clientIn);                } catch (IOException ioe) {                    _logger.severe("Error reading the initial request" + ioe);                    return;                }            }            // if we are a normal proxy (because request is not null)            // and the request is a CONNECT, get the base URL from the request            // and send the OK back. We set request to null so we read a new            // one from the SSL socket            // If it exists, we pull the ProxyAuthorization header from the CONNECT            // so that we can use it upstream.            String proxyAuth = null;            if (request != null) {                String method = request.getMethod();                if (method == null) {                    return;                } else if (method.equals("CONNECT")) {                    if (_clientOut != null) {                        try {                            _clientOut.write(("HTTP/1.0 200 Ok\r\n\r\n").getBytes());                            _clientOut.flush();                        } catch (IOException ioe) {                            _logger.severe("IOException writing the CONNECT OK Response to the browser " + ioe);                            return;                        }                    }                    _base = request.getURL().toString();                    proxyAuth = request.getHeader("Proxy-Authorization");                    request = null;                }            }            // if we are servicing a CONNECT, or operating as a reverse            // proxy with an https:// base URL, negotiate SSL            if (_base != null) {                if (_base.startsWith("https://") && _sock != null) {                    _logger.fine("Intercepting SSL connection!");                    _sock = negotiateSSL(_sock);                    _clientIn = _sock.getInputStream();                    _clientOut = _sock.getOutputStream();                    if (_simulator != null) {                        _clientIn = _simulator.wrapInputStream(_clientIn);                        _clientOut = _simulator.wrapOutputStream(_clientOut);                    }                }                // make sure that the base does not end with a "/"                while (_base.endsWith("/")) {                    _base = _base.substring(0,_base.length()-1);                }            }                        HTTPClient hc = _uf;                        // Maybe set SSL ProxyAuthorization here at a connection level?            // I prefer it in the Request itself, since it gets archived, and            // can be replayed trivially using netcat                        // layer the proxy plugins onto the recorder. We do this            // in reverse order so that they operate intuitively            // the first plugin in the array gets the first chance to modify            // the request, and the last chance to modify the response            for (int i=_plugins.length-1; i>=0; i--) {                hc = _plugins[i].getProxyPlugin(hc);            }                        // do we keep-alive?            String connection = null;            String version = null;            do {                // if we are reading the first from a reverse proxy, or the                // continuation of a CONNECT from a normal proxy                // read the request, otherwise we already have it.                if (request == null) {                    request = new Request();                    if (_base != null) request.setBaseURL(_base);                    _logger.fine("Reading request from the browser");                    request.read(_clientIn);                    if (request.getMethod() == null) {                        return;                    }                    if (proxyAuth != null) {                        request.addHeader("Proxy-Authorization",proxyAuth);                    }                }                if (_sock != null) {                    request.addHeader("X-Forwarded-For",_sock.getInetAddress().getHostAddress());                }                _logger.info("Browser requested : " + request.getMethod() + " " + request.getURL().toString());                                // start a thread reading the copy of the server's response                if (_pf != null) {                    _pf.readResponse(request);                    _logger.fine("Started the parallel fetch");                }                // pass the request through the plugins, and return the response                Response response = null;                try {                    response = hc.fetchResponse(request);                } catch (IOException ioe) {                    _logger.severe("IOException retrieving the response for " + request.getURL() + " : " + ioe);                    response = errorResponse(request, "IOException retrieving the response: " + ioe);                    // prevent the conversation from being submitted/recorded                    _pf = null;                    _plug = null;                }                if (response == null) {                    _logger.severe("Got a null response from the fetcher");                    return;                }                _logger.info("Response : " + response.getStatusLine());                try {                     if (_clientOut != null) {                        _logger.fine("Writing the response to the browser");                        response.write(_clientOut);                        _logger.fine("Finished writing the response to the browser");                    }                } catch (IOException ioe) {                    _logger.severe("Error writing back to the browser : " + ioe);                } finally {                    response.flushContentStream(); // this simply flushes the content from the server                }                // Now we read the response from the copy of the server input stream                // so that we avoid any possible changes made by the proxy plugins                // if there is an error, we submit the possibly modified response                // to the model                if (_pf != null) {                    Response resp = _pf.getResponse();                    if (resp != null) {                         response = resp;                    } else {                        _logger.severe("Submitting the original, (possibly) modified response to the server");                    }                }                if (_plug != null && request != null && !request.getMethod().equals("CONNECT") && response != null) {                    _plug.addConversation("Proxy", request, response);                }                                connection = response.getHeader("Connection");                version = response.getVersion();                                request = null;                                _logger.fine("Version: " + version + " Connection: " + connection);            } while ((version.equals("HTTP/1.0") && "keep-alive".equalsIgnoreCase(connection)) ||                      (version.equals("HTTP/1.1") && !"close".equalsIgnoreCase(connection)));            _logger.fine("Finished handling connection");        } catch (Exception e) {            _logger.severe("ConnectionHandler got an error : " + e);            e.printStackTrace();        } finally {            try {                if (_clientIn != null) _clientIn.close();                if (_clientOut != null) _clientOut.close();                if (_sock != null) _sock.close();            } catch (IOException ioe) {                _logger.warning("Error closing client socket : " + ioe);            }        }    }