package org.jboss.pitbull.internal.nio.http;
import org.jboss.pitbull.Connection;
import org.jboss.pitbull.RequestHeader;
import org.jboss.pitbull.StatusCode;
import org.jboss.pitbull.internal.logging.Logger;
import org.jboss.pitbull.internal.nio.socket.EventHandler;
import org.jboss.pitbull.internal.nio.socket.ManagedChannel;
import org.jboss.pitbull.internal.nio.websocket.WebSocketEventHandler;
import org.jboss.pitbull.internal.util.registry.NotFoundException;
import org.jboss.pitbull.internal.util.registry.UriRegistry;
import org.jboss.pitbull.server.handlers.WebSocketHandler;
import org.jboss.pitbull.server.handlers.stream.StreamRequestHandler;
import org.jboss.pitbull.server.spi.RequestHandler;
import org.jboss.pitbull.server.spi.RequestInitiator;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.concurrent.ExecutorService;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class HttpEventHandler implements EventHandler
{
public static final int BUFFER_SIZE = 8192;
protected HttpRequestDecoder decoder;
protected ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
protected Connection connection;
protected UriRegistry<Object> registry;
protected ExecutorService executor;
protected static final Logger log = Logger.getLogger(HttpEventHandler.class);
protected long count;
public HttpEventHandler(ExecutorService executor, UriRegistry<Object> registry)
{
this.executor = executor;
this.registry = registry;
}
protected void error(ManagedChannel channel, StatusCode code, HttpRequestHeader requestHeader) throws IOException
{
log.trace("Error returning with code: {0}", code.toString());
ContentInputStream is = ContentInputStream.create(channel, buffer, requestHeader.getHeaders());
if (is != null) is.eat();
log.trace("ate stream");
HttpResponse response = new HttpResponse(code);
byte[] bytes = response.responseBytes();
log.trace("writing error");
channel.writeBlocking(ByteBuffer.wrap(bytes));
log.trace("wrote error");
}
@Override
public void handleRead(ManagedChannel channel)
{
log.trace("handleRead() on channel {0}", channel.getId());
try
{
if (buffer == null) buffer = ByteBuffer.allocate(BUFFER_SIZE);
try
{
buffer.clear();
int c = channel.read(buffer);
if (c == -1)
{
channel.close();
}
else if (c == 0) return;
buffer.flip();
}
catch (IOException e)
{
throw new RuntimeException(e);
}
if (decoder == null) decoder = new HttpRequestDecoder();
if (connection == null)
{
connection = new ConnectionImpl(
channel.getChannel().socket().getLocalSocketAddress(),
channel.getChannel().socket().getRemoteSocketAddress(),
channel.getSslSession() != null);
}
log.trace("decode buffer");
if (!decoder.process(buffer))
{
log.trace("Not enough to decode buffer");
return;
}
log.trace("Http request decoded");
HttpRequestHeader requestHeader = decoder.getRequest();
log.trace("-- Http request: {0}", requestHeader);
decoder = null;
RequestInitiator initiator = null;
RequestHandler requestHandler = null;
try
{
List<Object> matches = registry.match(requestHeader.getUri());
for (Object match : matches)
{
if (match instanceof RequestInitiator)
{
initiator = (RequestInitiator) match;
requestHandler = initiator.begin(connection, requestHeader);
}
else if (match instanceof RequestHandler)
{
requestHandler = (RequestHandler) match;
}
if (requestHandler != null) break;
}
}
catch (NotFoundException e1)
{
}
if (requestHandler == null)
{
log.trace("Could not find a requestHandler, returning 404: {0} ", requestHeader);
try
{
error(channel, StatusCode.NOT_FOUND, requestHeader);
}
catch (Throwable e)
{
log.error("Failed to send error message to client, closing", e);
channel.close();
}
return;
}
if (requestHandler instanceof StreamRequestHandler)
{
ByteBuffer oldBuffer = buffer;
buffer = null;
executeStreamRequestHandler(oldBuffer, channel, requestHeader, (StreamRequestHandler) requestHandler);
}
else if (requestHandler instanceof WebSocketHandler)
{
ByteBuffer oldBuffer = buffer;
buffer = null;
executeWebSocketHandler(oldBuffer, channel, requestHeader, (WebSocketHandler) requestHandler);
}
else
{
log.error("Unsupported requestHandler type: " + requestHandler.getClass().getName());
if (initiator != null)
{
try
{ initiator.illegalHandler(requestHandler); }
catch (Throwable ignored)
{}
}
try
{
error(channel, StatusCode.INTERNAL_SERVER_ERROR, requestHeader);
}
catch (Throwable e)
{
log.error("Failed to send error message to client, closing", e);
channel.close();
}
return;
}
}
finally
{
log.trace("<--- Exit handleRead() channel: {0}", channel.getId());
}
}
protected void executeWebSocketHandler(final ByteBuffer buffer, final ManagedChannel channel, final RequestHeader requestHeader, final WebSocketHandler requestHandler)
{
log.trace("Using WebSocketHandler channel: {0}", channel.getId());
final WebSocketEventHandler webSocketEventHandler = new WebSocketEventHandler(connection, channel, executor, requestHandler);
channel.setHandler(webSocketEventHandler);
channel.suspendReads();
executor.execute(new Runnable()
{
@Override
public void run()
{
try
{
webSocketEventHandler.handshake(requestHeader, buffer);
channel.resumeReads();
}
catch (Exception e)
{
channel.close();
}
}
});
}
protected void executeStreamRequestHandler(ByteBuffer buffer, ManagedChannel channel, HttpRequestHeader requestHeader, StreamRequestHandler requestHandler)
{
log.trace("Using StreamHandler channel: {0}", channel.getId());
channel.suspendReads();
StreamRequestHandler streamHandler = (StreamRequestHandler) requestHandler;
StreamExecutor task = new StreamExecutor(connection, channel, streamHandler, buffer, requestHeader);
executor.execute(task);
}
@Override
public void shutdown()
{
}
}