/* * Copyright 2009 VoidSearch.com * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.voidsearch.voidbase.http; import org.jboss.netty.handler.codec.http.*; import org.jboss.netty.channel.*; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.voidsearch.voidbase.core.VoidBaseCore; import com.voidsearch.voidbase.core.VoidBaseRequestQueue; import com.voidsearch.voidbase.core.VoidBaseResourceRegister; import com.voidsearch.voidbase.core.HandlerNotRegisteredException; import com.voidsearch.voidbase.module.VoidBaseModuleResponse; import com.voidsearch.voidbase.module.VoidBaseModuleRequest; import com.voidsearch.voidbase.module.VoidBaseModule; import com.voidsearch.voidbase.module.VoidBaseResponseType; import com.voidsearch.voidbase.util.GenericUtil; @ChannelPipelineCoverage("one") public class HttpRequestHandler extends SimpleChannelUpstreamHandler { protected volatile HttpRequest request; protected volatile boolean readingChunks; protected VoidBaseCore core = VoidBaseCore.getInstance(); protected static final Logger logger = LoggerFactory.getLogger(SimpleChannelUpstreamHandler.class.getClass()); public HttpRequestHandler() { } private ChannelBuffer buf= null; private static VoidBaseRequestQueue requestQueue = VoidBaseRequestQueue.getInstance(); private static VoidBaseResourceRegister resourceRegister = VoidBaseResourceRegister.getInstance(); @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { if (!readingChunks) { HttpRequest request = this.request = (HttpRequest) e.getMessage(); if (request.isChunked()) { readingChunks = true; } else { ChannelBuffer content = request.getContent(); if (content.readable()) { // TODO: handle content } try { VoidBaseModuleRequest moduleReq = new VoidBaseModuleRequest(request, content); VoidBaseModule handler = resourceRegister.getHandler(moduleReq.getResource()); if (requestQueue.slotAvailable(handler,moduleReq)) { writeResponse(e, handler.handle(moduleReq)); requestQueue.releaseSlot(handler,moduleReq); } else { requestQueue.enqueue(handler,moduleReq); writeResponse(e, handler.handle(moduleReq)); requestQueue.releaseSlot(handler,moduleReq); } } catch (HandlerNotRegisteredException ex) { writeResponse(e, new VoidBaseModuleResponse("HandlerNotRegistered")); } } } else { HttpChunk chunk = (HttpChunk) e.getMessage(); ChannelBuffer content = request.getContent(); if (chunk.isLast()) { readingChunks = false; writeResponse(e, new VoidBaseModuleResponse("HandlerNotRegistered")); } } } private void writeResponse(MessageEvent e, VoidBaseModuleResponse result) { if(result.isBinary){ buf = ChannelBuffers.copiedBuffer(result.buffer); }else{ buf = ChannelBuffers.copiedBuffer(result.getMessage() + "\n", "UTF-8"); } // decide whether to close the connection or not boolean close = HttpHeaders.Values.CLOSE.equalsIgnoreCase(request.getHeader(HttpHeaders.Names.CONNECTION)) || request.getProtocolVersion().equals(HttpVersion.HTTP_1_0) && !HttpHeaders.Values.KEEP_ALIVE.equalsIgnoreCase(request.getHeader(HttpHeaders.Names.CONNECTION)); // create response object HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, result.status.serializeToHttpResponseStatus()); response.setContent(buf); response.setHeader(HttpHeaders.Names.CONTENT_TYPE, result.type.serializeToHttpContentType()); response.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(buf.readableBytes())); // write the response ChannelFuture future = e.getChannel().write(response); // close the connection after the write operation is done if necessary if (close) { future.addListener(ChannelFutureListener.CLOSE); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) { logger.error("Unexpected exception from downstream: " + e.getCause()); GenericUtil.logException(e.getCause().getMessage(), e.getCause().getStackTrace()); e.getChannel().close(); } public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { readingChunks = false; ctx.sendUpstream(e); } public void channelUnbound(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { readingChunks = false; ctx.sendUpstream(e); } }