in http/balancer/src/main/java/org/apache/karaf/cellar/http/balancer/CellarBalancerProxyServlet.java [144:232]
protected void service(HttpServletRequest servletRequest, HttpServletResponse servletResponse)
throws ServletException, IOException {
String location = locations.get(new Random().nextInt(locations.size()));
URI locationUri = URI.create(location);
HttpHost host = URIUtils.extractHost(locationUri);
LOGGER.debug("CELLAR HTTP BALANCER: proxying to");
LOGGER.debug("CELLAR HTTP BALANCER: URI: {}", locationUri);
LOGGER.debug("CELLAR HTTP BALANCER: Host: {}", host);
// Make the Request
//note: we won't transfer the protocol version because I'm not sure it would truly be compatible
String method = servletRequest.getMethod();
LOGGER.debug("CELLAR HTTP BALANCER: Method: {}", method);
String proxyRequestUri = rewriteUrlFromRequest(servletRequest, location);
LOGGER.debug("CELLAR HTTP BALANCER: Proxy Request URI: {}", proxyRequestUri);
HttpRequest proxyRequest;
//spec: RFC 2616, sec 4.3: either of these two headers signal that there is a message body.
if (servletRequest.getHeader(HttpHeaders.CONTENT_LENGTH) != null ||
servletRequest.getHeader(HttpHeaders.TRANSFER_ENCODING) != null) {
HttpEntityEnclosingRequest eProxyRequest = new BasicHttpEntityEnclosingRequest(method, proxyRequestUri);
// Add the input entity (streamed)
// note: we don't bother ensuring we close the servletInputStream since the container handles it
eProxyRequest.setEntity(new InputStreamEntity(servletRequest.getInputStream(), servletRequest.getContentLength()));
proxyRequest = eProxyRequest;
} else
proxyRequest = new BasicHttpRequest(method, proxyRequestUri);
LOGGER.debug("CELLAR HTTP BALANCER: copying request headers");
copyRequestHeaders(servletRequest, proxyRequest, host);
LOGGER.debug("CELLAR HTTP BALANCER: set X-Forwarded header");
setXForwardedForHeader(servletRequest, proxyRequest);
HttpResponse proxyResponse = null;
try {
// Execute the request
LOGGER.debug("CELLAR HTTP BALANCER: executing proxy request");
proxyResponse = proxyClient.execute(host, proxyRequest);
// Process the response
int statusCode = proxyResponse.getStatusLine().getStatusCode();
LOGGER.debug("CELLAR HTTP BALANCER: status code: {}", statusCode);
// copying response headers to make sure SESSIONID or other Cookie which comes from remote server
// will be saved in client when the proxied url was redirected to another one.
// see issue [#51](https://github.com/mitre/HTTP-Proxy-Servlet/issues/51)
LOGGER.debug("CELLAR HTTP BALANCER: copying response headers");
copyResponseHeaders(proxyResponse, servletRequest, servletResponse);
if (doResponseRedirectOrNotModifiedLogic(servletRequest, servletResponse, proxyResponse, statusCode, location)) {
//the response is already "committed" now without any body to send
return;
}
// Pass the response code. This method with the "reason phrase" is deprecated but it's the only way to pass the
// reason along too.
//noinspection deprecation
LOGGER.debug("CELLAR HTTP BALANCER: set response status code");
servletResponse.setStatus(statusCode, proxyResponse.getStatusLine().getReasonPhrase());
// Send the content to the client
LOGGER.debug("CELLAR HTTP BALANCER: copying response entity");
copyResponseEntity(proxyResponse, servletResponse);
} catch (Exception e) {
//abort request, according to best practice with HttpClient
if (proxyRequest instanceof AbortableHttpRequest) {
AbortableHttpRequest abortableHttpRequest = (AbortableHttpRequest) proxyRequest;
abortableHttpRequest.abort();
}
if (e instanceof RuntimeException)
throw (RuntimeException) e;
if (e instanceof ServletException)
throw (ServletException) e;
//noinspection ConstantConditions
if (e instanceof IOException)
throw (IOException) e;
throw new RuntimeException(e);
} finally {
// make sure the entire entity was consumed, so the connection is released
if (proxyResponse != null)
consumeQuietly(proxyResponse.getEntity());
//Note: Don't need to close servlet outputStream:
// http://stackoverflow.com/questions/1159168/should-one-call-close-on-httpservletresponse-getoutputstream-getwriter
}
}