}
if (_httpClient == null)
_httpClient = HTTPClientFactory.getInstance().getHTTPClient();
HTTPClient hc = _httpClient;
// if we are servicing a CONNECT, or operating as a reverse
// proxy with an https:// base URL, negotiate SSL
if (_base != null) {
// There are two certificates involved in a connection: one for the
// requested server, one for the client. First, the actual host must
// be determined from the client (SNI). Next, that host name must be
// taken to the server so it can return an appropriate certificate.
// Finally, the attributes from that server cert (mainly Subject and
// subjectAlternateName) can be copied back to the certificate
// presented to the client.
if (_base.getScheme().equals("https")) {
_logger.fine("Intercepting SSL connection!");
X509Certificate baseCrt = null;
// Connect early so some SSL details can be copied into new cert
URLFetcher uf = (URLFetcher) hc;
try {
uf.connect(_base);
} catch (IOException ioe) {
_logger.severe("Could not connect to remote server "
+ _base.toString() + ": " + ioe);
return;
}
baseCrt = uf.getCertificate();
_logger.log(Level.FINEST, "Certificate: {0}",
baseCrt == null ? "null" :
baseCrt.getSubjectX500Principal().getName());
_sock = negotiateSSL(_sock, _base.getHost(), baseCrt);
_clientIn = _sock.getInputStream();
_clientOut = _sock.getOutputStream();
}
}
// 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
if (_plugins != null) {
for (int i = _plugins.length - 1; i >= 0; i--) {
hc = _plugins[i].getProxyPlugin(hc);
}
}
// do we add an X-Forwarded-For header?
String from = _sock.getInetAddress().getHostAddress();
if (from.equals("127.0.0.1"))
from = null;
// do we keep-alive?
String keepAlive = null;
String version = null;
do {
id = null;
// 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();
_logger.fine("Reading request from the browser");
request.read(_clientIn, _base);
if (request.getMethod() == null || request.getURL() == null) {
return;
}
if (proxyAuth != null) {
request.addHeader("Proxy-Authorization", proxyAuth);
}
}
if (from != null) {
request.addHeader("X-Forwarded-For", from);
}
try {
_logger.fine("Browser requested : " + request.getMethod() + " "
+ request.getURL().toString());
} catch (NullPointerException npe) {
System.out.println("Request is: " + request);
}
// report the request to the listener, and get the allocated ID
id = _proxy.gotRequest(request);
// pass the request for possible modification or analysis
connection.setRequest(request);
connection.setResponse(null);
_proxy.interceptRequest(connection);
request = connection.getRequest();
Response response = connection.getResponse();
if (request == null)
throw new IOException("Request was cancelled");
if (response != null) {
_proxy.failedResponse(id, "Response provided by script");
_proxy = null;
} else {
// pass the request through the plugins, and return the
// response
try {
response = hc.fetchResponse(request);
if (response != null && response.getRequest() != null)
request = response.getRequest();
} catch (IOException ioe) {
_logger
.severe("IOException retrieving the response for "