/** * */ package com.trendrr.strest.server; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.zip.GZIPOutputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jboss.netty.buffer.ChannelBufferFactory; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; import org.jboss.netty.handler.codec.http.DefaultHttpRequest; import org.jboss.netty.handler.codec.http.DefaultHttpResponse; import org.jboss.netty.handler.codec.http.HttpContentCompressor; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpMessage; import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpResponse; import com.trendrr.strest.StrestUtil; /** * @author Dustin Norlander * @created Mar 17, 2011 * */ public class StrestResponseEncoder extends SimpleChannelHandler { protected Log log = LogFactory.getLog(StrestResponseEncoder.class); /** * Minimum number of bytes before we will gzip content. */ public static int GZIP_THRESHOLD = 500; // @Override public void writeRequested(ChannelHandlerContext ctx, MessageEvent e) throws Exception { Object msg = e.getMessage(); if (msg instanceof HttpResponse && ((HttpResponse) msg).getStatus().getCode() == 100) { // 100-continue response must be passed through. ctx.sendDownstream(e); } else if (msg instanceof HttpMessage) { HttpMessage m = (HttpMessage) msg; //make sure content length is set. if (!m.containsHeader(HttpHeaders.Names.CONTENT_LENGTH)) { if (m.getContent() != null && m.getContent().readableBytes() > 0) { m.setHeader(HttpHeaders.Names.CONTENT_LENGTH, m.getContent().readableBytes()); } else { m.setHeader(HttpHeaders.Names.CONTENT_LENGTH, 0); } } } ctx.sendDownstream(e); } /** * Copies a response headers to a new response. does NOT copy the content! * @param request */ public static HttpResponse copyHeaders(HttpResponse response) { HttpResponse copy = new DefaultHttpResponse(response.getProtocolVersion(), response.getStatus()); for (String h : response.getHeaderNames()) { copy.addHeader(h, response.getHeader(h)); } return copy; } /** * GZIPs the response content when accept is gzip. only when content > GZIP_THRESHOLD * * Will make no change if the content is already encoded, or if accept is not gzip * * @param response * @param accept */ public static void compress(HttpResponse response, String accept) { if (accept == null) return; //no acceptable encodings if (response.containsHeader(HttpHeaders.Names.CONTENT_ENCODING)) return; //content is already encoded if (response.getContent() == null || response.getContent().readableBytes() == 0) return; //no content bytes if (accept.indexOf("gzip") >= 0 && response.getContent().readableBytes() > GZIP_THRESHOLD) { //actually gzip it. response.setContent(ChannelBuffers.wrappedBuffer(gzip(response.getContent().array()))); response.setHeader(HttpHeaders.Names.CONTENT_ENCODING, accept); } } public static byte[] gzip(byte[] bytes) { ByteArrayOutputStream stream = null; try { stream = new ByteArrayOutputStream(); GZIPOutputStream gos = new GZIPOutputStream(stream); gos.write(bytes, 0, bytes.length); gos.finish(); return stream.toByteArray(); } catch(IOException e) { throw new IllegalStateException("Exception occurred attempting to encode a payload body", e); } finally { try{ if(stream != null) stream.close(); } catch(IOException e) {/*ignore*/} } } }