package org.langke.common.server; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; import org.jboss.netty.handler.codec.http.DefaultHttpResponse; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpMethod; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpResponseStatus; import org.jboss.netty.handler.codec.http.HttpVersion; import org.langke.common.Config; import org.langke.common.CostTime; import org.langke.common.server.resp.ErrorResp; import org.langke.common.server.resp.Resp; import org.langke.util.logging.ESLogger; import org.langke.util.logging.Loggers; import com.alibaba.fastjson.JSONException; public class RestChannelHandler extends SimpleChannelHandler { private static ESLogger log = Loggers.getLogger(RestChannelHandler.class); private static final String CONTENT_TYPE = "application/json;charset=utf-8"; private final PathTrie<Handler> getHandlers = new PathTrie<Handler>(); private final PathTrie<Handler> postHandlers = new PathTrie<Handler>(); private final PathTrie<Handler> putHandlers = new PathTrie<Handler>(); private final PathTrie<Handler> deleteHandlers = new PathTrie<Handler>(); public RestChannelHandler(){ } public void messageReceived(ChannelHandlerContext ctx, final MessageEvent me) throws Exception { CostTime cost = new CostTime(); cost.start(); final HttpRequest httpRequest = (HttpRequest) me.getMessage(); NettyHttpRequest request = new NettyHttpRequest(httpRequest); Channel channel = me.getChannel(); final Handler handler = getHandler(request); Resp response = null; int code = 200,content_length; if (handler == null) { code = 404; response = new ErrorResp("No handler found for uri ["+ request.uri() + "] and method [" + request.method() + "]",code); content_length = sendResponse(request, response, httpRequest, channel,cost); }else{ try { response = handler.handleRequest(request); } catch (JSONException e){ code = 400; response = new ErrorResp(e, 400); } catch (Exception e) { code = 500; response = new ErrorResp(e); }finally{ content_length = sendResponse(request, response, httpRequest, channel,cost); } } String referer = request.header("Referer"); String userAgent = request.header("User-Agent"); String content = request.contentAsString(); if(content!=null && content.length()>0 && content.indexOf('\n')!=-1) content = content.replace("\n", ""); StringBuffer sb = new StringBuffer(); sb.append(userAgent==null?"":userAgent).append(','); sb.append(referer==null?"":referer).append(','); sb.append(content); if(cost.cost()>100) log.warn("{} {} {} {} {} {} {}",channel.getRemoteAddress().toString(),httpRequest.getMethod().getName(),httpRequest.getUri(),code,content_length,"\""+sb.toString()+"\"",cost.cost()); else log.info("{} {} {} {} {} {} {}",channel.getRemoteAddress().toString(),httpRequest.getMethod().getName(),httpRequest.getUri(),code,content_length,"\""+sb.toString()+"\"",cost.cost()); } @SuppressWarnings("unused") public int sendResponse(NettyHttpRequest nettyRequest, Resp response, HttpRequest httpRequest, Channel channel,CostTime cost){ // Decide whether to close the connection or not. boolean http10 = httpRequest.getProtocolVersion().equals(HttpVersion.HTTP_1_0); boolean close = HttpHeaders.Values.CLOSE.equalsIgnoreCase(httpRequest.getHeader(HttpHeaders.Names.CONNECTION)) || (http10 && !HttpHeaders.Values.KEEP_ALIVE.equalsIgnoreCase(httpRequest.getHeader(HttpHeaders.Names.CONNECTION))); // Build the response object. HttpResponseStatus status = getStatus(response.getRespData().getCode()); org.jboss.netty.handler.codec.http.HttpResponse resp; if (http10) { resp = new DefaultHttpResponse(HttpVersion.HTTP_1_0, status); if (!close) { resp.addHeader(HttpHeaders.Names.CONNECTION, "Keep-Alive"); } } else { resp = new DefaultHttpResponse(HttpVersion.HTTP_1_1, status); } response.getRespData().setTime(cost.cost()); // Convert the response content to a ChannelBuffer. ChannelFutureListener releaseContentListener = null; ChannelBuffer buf = response.toJson(); resp.setContent(buf); resp.setHeader(HttpHeaders.Names.CONTENT_TYPE, CONTENT_TYPE); int content_length = buf.readableBytes(); resp.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(content_length)); resp.setHeader(HttpHeaders.Names.SERVER,Config.get().get("server.name", "rest-netty-server")); resp.setHeader("Via", NetworkUtils.getLocalAddress().getHostAddress()); // Write the response. ChannelFuture future = channel.write(resp); if (releaseContentListener != null) { future.addListener(releaseContentListener); } // Close the connection after the write operation is done if necessary. if (close) { future.addListener(ChannelFutureListener.CLOSE); } return content_length; } private HttpResponseStatus getStatus(int status) { switch (status) { case 100: return HttpResponseStatus.CONTINUE; case 101: return HttpResponseStatus.SWITCHING_PROTOCOLS; case 200: return HttpResponseStatus.OK; case 201: return HttpResponseStatus.CREATED; case 202: return HttpResponseStatus.ACCEPTED; case 203: return HttpResponseStatus.NON_AUTHORITATIVE_INFORMATION; case 204: return HttpResponseStatus.NO_CONTENT; case 205: return HttpResponseStatus.RESET_CONTENT; case 206: return HttpResponseStatus.PARTIAL_CONTENT; case 207: // no status for this?? return HttpResponseStatus.INTERNAL_SERVER_ERROR; case 300: return HttpResponseStatus.MULTIPLE_CHOICES; case 301: return HttpResponseStatus.MOVED_PERMANENTLY; case 302: return HttpResponseStatus.FOUND; case 303: return HttpResponseStatus.SEE_OTHER; case 304: return HttpResponseStatus.NOT_MODIFIED; case 305: return HttpResponseStatus.USE_PROXY; case 307: return HttpResponseStatus.TEMPORARY_REDIRECT; case 400: return HttpResponseStatus.BAD_REQUEST; case 401: return HttpResponseStatus.UNAUTHORIZED; case 402: return HttpResponseStatus.PAYMENT_REQUIRED; case 403: return HttpResponseStatus.FORBIDDEN; case 404: return HttpResponseStatus.NOT_FOUND; case 405: return HttpResponseStatus.METHOD_NOT_ALLOWED; case 406: return HttpResponseStatus.NOT_ACCEPTABLE; case 407: return HttpResponseStatus.PROXY_AUTHENTICATION_REQUIRED; case 408: return HttpResponseStatus.REQUEST_TIMEOUT; case 409: return HttpResponseStatus.CONFLICT; case 410: return HttpResponseStatus.GONE; case 411: return HttpResponseStatus.LENGTH_REQUIRED; case 412: return HttpResponseStatus.PRECONDITION_FAILED; case 413: return HttpResponseStatus.REQUEST_ENTITY_TOO_LARGE; case 414: return HttpResponseStatus.REQUEST_URI_TOO_LONG; case 415: return HttpResponseStatus.UNSUPPORTED_MEDIA_TYPE; case 416: return HttpResponseStatus.REQUESTED_RANGE_NOT_SATISFIABLE; case 417: return HttpResponseStatus.EXPECTATION_FAILED; case 422: return HttpResponseStatus.BAD_REQUEST; case 423: return HttpResponseStatus.BAD_REQUEST; case 424: return HttpResponseStatus.BAD_REQUEST; case 500: return HttpResponseStatus.INTERNAL_SERVER_ERROR; case 501: return HttpResponseStatus.NOT_IMPLEMENTED; case 502: return HttpResponseStatus.BAD_GATEWAY; case 503: return HttpResponseStatus.SERVICE_UNAVAILABLE; case 504: return HttpResponseStatus.GATEWAY_TIMEOUT; case 505: return HttpResponseStatus.HTTP_VERSION_NOT_SUPPORTED; default: return HttpResponseStatus.INTERNAL_SERVER_ERROR; } } public void registerHandler(HttpMethod method, String path, Handler handler) { if (method == HttpMethod.GET) { getHandlers.insert(path, handler); } else if (method == HttpMethod.POST) { postHandlers.insert(path, handler); } else if (method == HttpMethod.PUT) { putHandlers.insert(path, handler); } else if (method == HttpMethod.DELETE) { deleteHandlers.insert(path, handler); } else { throw new RuntimeException("HttpMethod is not supported"); } } private Handler getHandler(NettyHttpRequest request) { String path = request.path(); HttpMethod method = request.method(); if (method == HttpMethod.GET) { return getHandlers.retrieve(path, request.params()); } else if (method == HttpMethod.POST) { return postHandlers.retrieve(path, request.params()); } else if (method == HttpMethod.PUT) { return putHandlers.retrieve(path, request.params()); } else if (method == HttpMethod.DELETE) { return deleteHandlers.retrieve(path, request.params()); } else { return null; } } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { if (log.isTraceEnabled()) log.trace("Connection exceptionCaught:{}", e.getCause().toString()); e.getChannel().close(); } }