Permalink
Browse files

[#1594] Allow users to customize the Netty pipeline and thus add comp…

…ression
  • Loading branch information...
1 parent 2d6962c commit a46abe5824d83bdb66479d43004f645c808f7d39 @pepite pepite committed Dec 29, 2012
@@ -51,7 +51,7 @@ require: &allDependencies
- org.hibernate -> jboss-transaction-api_1.1_spec 1.0.0.Final
- org.hibernate.javax.persistence -> hibernate-jpa-2.0-api 1.0.1.Final
- org.javassist -> javassist 3.15.0.GA
- - org.jboss.netty -> netty 3.4.2.Final
+ - org.jboss.netty -> netty 3.6.0.Final
- org.postgresql -> postgresql 9.0
- org.slf4j -> slf4j-api 1.6.1
- org.slf4j -> slf4j-log4j12 1.6.1
Binary file not shown.
Binary file not shown.
@@ -1,31 +1,71 @@
- package play.server;
+package play.server;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.handler.codec.http.HttpChunkAggregator;
import org.jboss.netty.handler.codec.http.HttpRequestDecoder;
import org.jboss.netty.handler.codec.http.HttpResponseEncoder;
+import org.jboss.netty.channel.ChannelHandler;
import play.Play;
+import play.Logger;
+import java.util.Map;
+import java.util.HashMap;
import static org.jboss.netty.channel.Channels.pipeline;
public class HttpServerPipelineFactory implements ChannelPipelineFactory {
+ private String pipelineConfig = Play.configuration.getProperty("play.netty.pipeline", "play.server.FlashPolicyHandler,org.jboss.netty.handler.codec.http.HttpRequestDecoder,play.server.StreamChunkAggregator,org.jboss.netty.handler.codec.http.HttpResponseEncoder,org.jboss.netty.handler.stream.ChunkedWriteHandler,play.server.PlayHandler");
+
+ protected static Map<String, Class> classes = new HashMap<String, Class>();
+
public ChannelPipeline getPipeline() throws Exception {
- Integer max = Integer.valueOf(Play.configuration.getProperty("play.netty.maxContentLength", "-1"));
-
ChannelPipeline pipeline = pipeline();
- PlayHandler playHandler = new PlayHandler();
-
- pipeline.addLast("flashPolicy", new FlashPolicyHandler());
- pipeline.addLast("decoder", new HttpRequestDecoder());
- pipeline.addLast("aggregator", new StreamChunkAggregator(max));
- pipeline.addLast("encoder", new HttpResponseEncoder());
- pipeline.addLast("chunkedWriter", playHandler.chunkedWriteHandler);
- pipeline.addLast("handler", playHandler);
+ // Get all the pipeline. Give the user the opportunity to add their own
+ String[] handlers = pipelineConfig.split(",");
+ for (int i = 0; i < handlers.length - 1; i++) {
+ String handler = handlers[i];
+ try {
+ String name = getName(handler.trim());
+ ChannelHandler instance = getInstance(handler);
+ if (instance != null) {
+ pipeline.addLast(name, instance);
+ Server.pipelines.put(name, instance);
+ }
+ } catch(Throwable e) {
+ Logger.error(" error adding " + handler, e);
+ }
+ }
+
+ // The last one is always the play handler
+ String handler = handlers[handlers.length - 1];
+ ChannelHandler instance = getInstance(handler);
+ if (instance != null) {
+ pipeline.addLast("handler", instance);
+ Server.pipelines.put("handler", instance);
+ }
+
return pipeline;
}
+
+ protected String getName(String name) {
+ if (name.lastIndexOf(".") > 0)
+ return name.substring(name.lastIndexOf(".") + 1);
+ return name;
+ }
+
+ protected ChannelHandler getInstance(String name) throws Exception {
+
+ Class clazz = classes.get(name);
+ if (clazz == null) {
+ clazz = Class.forName(name);
+ classes.put(name, clazz);
+ }
+ if (ChannelHandler.class.isAssignableFrom(clazz))
+ return (ChannelHandler)clazz.newInstance();
+ return null;
+ }
}
@@ -918,9 +918,7 @@ public static void setContentLength(HttpMessage message, long contentLength) {
message.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(contentLength));
}
- // ~~~~~~~~~~~ Chunked response
- final ChunkedWriteHandler chunkedWriteHandler = new ChunkedWriteHandler();
-
+
static class LazyChunkedInput implements org.jboss.netty.handler.stream.ChunkedInput {
private boolean closed = false;
@@ -979,7 +977,12 @@ public void writeChunk(Request playRequest, Response playResponse, ChannelHandle
copyResponse(ctx, playRequest, playResponse, nettyRequest);
}
((LazyChunkedInput) playResponse.direct).writeChunk(chunk);
- chunkedWriteHandler.resumeTransfer();
+ if (Server.pipelines.get("ChunkedWriteHandler") != null) {
+ ((ChunkedWriteHandler)Server.pipelines.get("ChunkedWriteHandler")).resumeTransfer();
+ }
+ if (Server.pipelines.get("SslChunkedWriteHandler") != null) {
+ ((ChunkedWriteHandler)Server.pipelines.get("SslChunkedWriteHandler")).resumeTransfer();
+ }
} catch (Exception e) {
throw new UnexpectedException(e);
}
@@ -988,7 +991,12 @@ public void writeChunk(Request playRequest, Response playResponse, ChannelHandle
public void closeChunked(Request playRequest, Response playResponse, ChannelHandlerContext ctx, HttpRequest nettyRequest) {
try {
((LazyChunkedInput) playResponse.direct).close();
- chunkedWriteHandler.resumeTransfer();
+ if (Server.pipelines.get("ChunkedWriteHandler") != null) {
+ ((ChunkedWriteHandler)Server.pipelines.get("ChunkedWriteHandler")).resumeTransfer();
+ }
+ if (Server.pipelines.get("SslChunkedWriteHandler") != null) {
+ ((ChunkedWriteHandler)Server.pipelines.get("SslChunkedWriteHandler")).resumeTransfer();
+ }
} catch (Exception e) {
throw new UnexpectedException(e);
}
@@ -10,18 +10,22 @@
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelException;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
+import org.jboss.netty.channel.ChannelHandler;
import play.Logger;
import play.Play;
import play.Play.Mode;
import play.libs.IO;
import play.server.ssl.SslHttpServerPipelineFactory;
import play.vfs.VirtualFile;
+import java.util.Map;
+import java.util.HashMap;
public class Server {
public static int httpPort;
public static int httpsPort;
+ public static Map<String, ChannelHandler> pipelines = new HashMap<String, ChannelHandler>();
public final static String PID_FILE = "server.pid";
@@ -16,15 +16,13 @@
private volatile HttpMessage currentMessage;
private volatile OutputStream out;
- private final int maxContentLength;
+ private final static int maxContentLength = Integer.valueOf(Play.configuration.getProperty("play.netty.maxContentLength", "-1"));
private volatile File file;
/**
* Creates a new instance.
*/
- public StreamChunkAggregator(int maxContentLength) {
- this.maxContentLength = maxContentLength;
- }
+ public StreamChunkAggregator() { }
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
@@ -12,15 +12,20 @@
import play.Play;
import play.server.FlashPolicyHandler;
import play.server.StreamChunkAggregator;
+import play.server.HttpServerPipelineFactory;
+import org.jboss.netty.channel.ChannelHandler;
+import play.Logger;
+import play.server.Server;
import static org.jboss.netty.channel.Channels.pipeline;
-public class SslHttpServerPipelineFactory implements ChannelPipelineFactory {
+public class SslHttpServerPipelineFactory extends HttpServerPipelineFactory {
+
+ private String pipelineConfig = Play.configuration.getProperty("play.ssl.netty.pipeline", "play.server.FlashPolicyHandler,org.jboss.netty.handler.codec.http.HttpRequestDecoder,play.server.StreamChunkAggregator,org.jboss.netty.handler.codec.http.HttpResponseEncoder,org.jboss.netty.handler.stream.ChunkedWriteHandler,play.server.ssl.SslPlayHandler");
public ChannelPipeline getPipeline() throws Exception {
- Integer max = Integer.valueOf(Play.configuration.getProperty("play.netty.maxContentLength", "-1"));
String mode = Play.configuration.getProperty("play.netty.clientAuth", "none");
String enabledCiphers = Play.configuration.getProperty("play.ssl.enabledCiphers", "");
@@ -42,14 +47,32 @@ public ChannelPipeline getPipeline() throws Exception {
engine.setEnableSessionCreation(true);
- pipeline.addLast("flashPolicy", new FlashPolicyHandler());
pipeline.addLast("ssl", new SslHandler(engine));
- pipeline.addLast("decoder", new HttpRequestDecoder());
- pipeline.addLast("aggregator", new StreamChunkAggregator(max));
- pipeline.addLast("encoder", new HttpResponseEncoder());
- pipeline.addLast("chunkedWriter", new ChunkedWriteHandler());
+
+ // Get all the pipeline. Give the user the opportunity to add their own
+ String[] handlers = pipelineConfig.split(",");
+ for (int i = 0; i < handlers.length - 1; i++) {
+ String handler = handlers[i];
+ try {
+ String name = getName(handler.trim());
+ ChannelHandler instance = getInstance(handler);
+ if (instance != null) {
+ pipeline.addLast(name, instance);
+ Server.pipelines.put("Ssl" + name, instance);
+ }
+ } catch(Throwable e) {
+ Logger.error(" error adding " + handler, e);
+ }
- pipeline.addLast("handler", new SslPlayHandler());
+ }
+
+ // The last one is always the play handler
+ String handler = handlers[handlers.length - 1];
+ ChannelHandler instance = getInstance(handler);
+ if (instance != null) {
+ pipeline.addLast("handler", instance);
+ Server.pipelines.put("SslHandler", instance);
+ }
return pipeline;
}
@@ -196,6 +196,17 @@ mail.smtp=mock
# Try to keep a low as possible. 1 thread will serialize all requests (very useful for debugging purpose)
# play.pool=3
+# Netty pipeline configuration (advanced settings)
+# You can default netty settings by overriding the following line. Each handler must be comma separated.
+# The last value must be the PlayHandler class (or your own that extends PlayHandler)
+# Default values are
+# play.netty.pipeline = play.server.FlashPolicyHandler,org.jboss.netty.handler.codec.http.HttpRequestDecoder,play.server.StreamChunkAggregator,org.jboss.netty.handler.codec.http.HttpResponseEncoder,org.jboss.netty.handler.stream.ChunkedWriteHandler,play.server.PlayHandler
+# For example, to enable Netty response compression
+# play.netty.pipeline = play.server.FlashPolicyHandler,org.jboss.netty.handler.codec.http.HttpRequestDecoder,play.server.StreamChunkAggregator,org.jboss.netty.handler.codec.http.HttpResponseEncoder,org.jboss.netty.handler.codec.http.HttpContentCompressor,org.jboss.netty.handler.stream.ChunkedWriteHandler,play.server.PlayHandler
+# For SSL, use the play.ssl.netty.pipeline property
+# play.ssl.netty.pipeline = play.server.FlashPolicyHandler,org.jboss.netty.handler.codec.http.HttpRequestDecoder,play.server.StreamChunkAggregator,org.jboss.netty.handler.codec.http.HttpResponseEncoder,org.jboss.netty.handler.codec.http.HttpContentCompressor,org.jboss.netty.handler.stream.ChunkedWriteHandler,play.server.ssl.SslPlayHandler
+
+
# Open file from errors pages
# ~~~~~
# If your text editor supports opening files by URL, Play! will

0 comments on commit a46abe5

Please sign in to comment.