package com.neverwinterdp.command.server;
import java.io.IOException;
import java.net.URI;
import java.nio.ByteBuffer;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.concurrent.TimeUnit;
import javax.servlet.AsyncContext;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.api.Result;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.proxy.ProxyServlet;
import org.eclipse.jetty.util.Callback;
import com.neverwinterdp.registry.Registry;
import com.neverwinterdp.registry.RegistryConfig;
import com.neverwinterdp.registry.RegistryException;
import com.neverwinterdp.registry.zk.RegistryImpl;
@SuppressWarnings("serial")
public class CommandProxyServlet extends ProxyServlet {
private String forwardingUrl;
private Registry registry;
private String registryPathToCommandHost;
@Override
public void init() throws ServletException {
super.init();
ServletConfig conf = this.getServletConfig();
RegistryConfig regConf = new RegistryConfig();
//Get config from web.xml
registryPathToCommandHost = conf.getInitParameter("registryPathToCommandHost");
regConf.setConnect(conf.getInitParameter("registryhost"));
regConf.setDbDomain(conf.getInitParameter("dbdomain"));
registry = new RegistryImpl(regConf);
try {
registry.connect();
} catch (RegistryException e) {
e.printStackTrace();
}
this.setForwardingUrl();
}
@Override
protected URI rewriteURI(HttpServletRequest request) {
return URI.create(this.forwardingUrl);
}
@Override
protected void onResponseFailure(HttpServletRequest request, HttpServletResponse response,
Response proxyResponse, Throwable failure){
//System.err.println("Response Failure!");
this.setForwardingUrl();
HttpClient c = null;
try {
c = this.createHttpClient();
} catch (ServletException e1) {
e1.printStackTrace();
}
final Request proxyRequest = c.newRequest(this.forwardingUrl)
.method(request.getMethod())
.version(HttpVersion.fromString(request.getProtocol()));
boolean hasContent = request.getContentLength() > 0 || request.getContentType() != null;
for (Enumeration<String> headerNames = request.getHeaderNames(); headerNames.hasMoreElements();){
String headerName = headerNames.nextElement();
if (HttpHeader.TRANSFER_ENCODING.is(headerName))
hasContent = true;
for (Enumeration<String> headerValues = request.getHeaders(headerName); headerValues.hasMoreElements();){
String headerValue = headerValues.nextElement();
if (headerValue != null)
proxyRequest.header(headerName, headerValue);
}
}
// Add proxy headers
addViaHeader(proxyRequest);
addXForwardedHeaders(proxyRequest, request);
final AsyncContext asyncContext = request.getAsyncContext();
// We do not timeout the continuation, but the proxy request
asyncContext.setTimeout(0);
proxyRequest.timeout(getTimeout(), TimeUnit.MILLISECONDS);
if (hasContent)
try {
proxyRequest.content(proxyRequestContent(proxyRequest, request));
} catch (IOException e) {
e.printStackTrace();
}
customizeProxyRequest(proxyRequest, request);
proxyRequest.send(new ProxyResponseListener(request, response));
}
private void setForwardingUrl(){
//System.err.println("SettingForwardingUrl");
try {
this.forwardingUrl = new String(this.registry.getData(this.registryPathToCommandHost));
//System.err.println(this.forwardingUrl);
} catch (RegistryException e) {
e.printStackTrace();
}
}
/**
* Shamelessly stolen from the parent class because they were cruel and made it private
*/
private class ProxyResponseListener extends Response.Listener.Adapter
{
private final HttpServletRequest request;
private final HttpServletResponse response;
public ProxyResponseListener(HttpServletRequest request, HttpServletResponse response){
this.request = request;
this.response = response;
}
@Override
public void onBegin(Response proxyResponse){
response.setStatus(proxyResponse.getStatus());
}
@Override
public void onHeaders(Response proxyResponse){
onResponseHeaders(request, response, proxyResponse);
if (_log.isDebugEnabled())
{
StringBuilder builder = new StringBuilder("\r\n");
builder.append(request.getProtocol()).append(" ").append(response.getStatus()).append(" ").append(proxyResponse.getReason()).append("\r\n");
for (String headerName : response.getHeaderNames())
{
builder.append(headerName).append(": ");
for (Iterator<String> headerValues = response.getHeaders(headerName).iterator(); headerValues.hasNext();)
{
String headerValue = headerValues.next();
if (headerValue != null)
builder.append(headerValue);
if (headerValues.hasNext())
builder.append(",");
}
builder.append("\r\n");
}
_log.debug("{} proxying to downstream:{}{}{}{}{}",
getRequestId(request),
System.lineSeparator(),
proxyResponse,
System.lineSeparator(),
proxyResponse.getHeaders().toString().trim(),
System.lineSeparator(),
builder);
}
}
@Override
public void onContent(final Response proxyResponse, ByteBuffer content, final Callback callback){
byte[] buffer;
int offset;
int length = content.remaining();
if (content.hasArray())
{
buffer = content.array();
offset = content.arrayOffset();
}
else
{
buffer = new byte[length];
content.get(buffer);
offset = 0;
}
onResponseContent(request, response, proxyResponse, buffer, offset, length, new Callback(){
@Override
public void succeeded()
{
callback.succeeded();
}
@Override
public void failed(Throwable x)
{
callback.failed(x);
proxyResponse.abort(x);
}
});
}
@Override
public void onComplete(Result result){
if (result.isSucceeded())
onResponseSuccess(request, response, result.getResponse());
else
onResponseFailure(request, response, result.getResponse(), result.getFailure());
_log.debug("{} proxying complete", getRequestId(request));
}
}
}