1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  package org.jboss.netty.handler.codec.http;
17  
18  import org.jboss.netty.buffer.ChannelBuffer;
19  import org.jboss.netty.handler.codec.compression.JdkZlibEncoder;
20  import org.jboss.netty.handler.codec.compression.ZlibEncoder;
21  import org.jboss.netty.handler.codec.compression.ZlibWrapper;
22  import org.jboss.netty.handler.codec.embedder.EncoderEmbedder;
23  import org.jboss.netty.logging.InternalLogger;
24  import org.jboss.netty.logging.InternalLoggerFactory;
25  import org.jboss.netty.util.internal.DetectionUtil;
26  import org.jboss.netty.util.internal.StringUtil;
27  import org.jboss.netty.util.internal.SystemPropertyUtil;
28  
29  
30  
31  
32  
33  
34  
35  
36  public class HttpContentCompressor extends HttpContentEncoder {
37  
38      private static final InternalLogger logger = InternalLoggerFactory.getInstance(HttpContentCompressor.class);
39  
40      private static final int DEFAULT_JDK_WINDOW_SIZE = 15;
41      private static final int DEFAULT_JDK_MEM_LEVEL = 8;
42  
43      private static final boolean noJdkZlibEncoder;
44  
45      static {
46          noJdkZlibEncoder = SystemPropertyUtil.getBoolean("io.netty.noJdkZlibEncoder", false);
47          if (logger.isDebugEnabled()) {
48              logger.debug("-Dio.netty.noJdkZlibEncoder: " + noJdkZlibEncoder);
49          }
50      }
51  
52      private final int compressionLevel;
53      private final int windowBits;
54      private final int memLevel;
55  
56      
57  
58  
59  
60      public HttpContentCompressor() {
61          this(6);
62      }
63  
64      
65  
66  
67  
68  
69  
70  
71  
72  
73      public HttpContentCompressor(int compressionLevel) {
74          this(compressionLevel, DEFAULT_JDK_WINDOW_SIZE, DEFAULT_JDK_MEM_LEVEL);
75      }
76  
77      
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95      public HttpContentCompressor(int compressionLevel, int windowBits, int memLevel) {
96          if (compressionLevel < 0 || compressionLevel > 9) {
97              throw new IllegalArgumentException(
98                      "compressionLevel: " + compressionLevel + " (expected: 0-9)");
99          }
100         if (windowBits < 9 || windowBits > 15) {
101             throw new IllegalArgumentException(
102                     "windowBits: " + windowBits + " (expected: 9-15)");
103         }
104         if (memLevel < 1 || memLevel > 9) {
105             throw new IllegalArgumentException(
106                     "memLevel: " + memLevel + " (expected: 1-9)");
107         }
108         this.compressionLevel = compressionLevel;
109         this.windowBits = windowBits;
110         this.memLevel = memLevel;
111     }
112 
113     @Override
114     protected EncoderEmbedder<ChannelBuffer> newContentEncoder(
115             HttpMessage msg, String acceptEncoding) throws Exception {
116         String contentEncoding = msg.headers().get(HttpHeaders.Names.CONTENT_ENCODING);
117         if (contentEncoding != null &&
118             !HttpHeaders.Values.IDENTITY.equalsIgnoreCase(contentEncoding)) {
119             
120             return null;
121         }
122 
123         ZlibWrapper wrapper = determineWrapper(acceptEncoding);
124         if (wrapper == null) {
125             return null;
126         }
127 
128         if (DetectionUtil.javaVersion() < 7 || noJdkZlibEncoder ||
129             windowBits != DEFAULT_JDK_WINDOW_SIZE || memLevel != DEFAULT_JDK_MEM_LEVEL) {
130             return new EncoderEmbedder<ChannelBuffer>(
131                     new ZlibEncoder(wrapper, compressionLevel, windowBits, memLevel));
132         } else {
133             return new EncoderEmbedder<ChannelBuffer>(
134                     new JdkZlibEncoder(wrapper, compressionLevel));
135         }
136     }
137 
138     @Override
139     protected String getTargetContentEncoding(String acceptEncoding) throws Exception {
140         ZlibWrapper wrapper = determineWrapper(acceptEncoding);
141         if (wrapper == null) {
142             return null;
143         }
144 
145         switch (wrapper) {
146         case GZIP:
147             return "gzip";
148         case ZLIB:
149             return "deflate";
150         default:
151             throw new Error();
152         }
153     }
154 
155     private static ZlibWrapper determineWrapper(String acceptEncoding) {
156         float starQ = -1.0f;
157         float gzipQ = -1.0f;
158         float deflateQ = -1.0f;
159         for (String encoding: StringUtil.split(acceptEncoding, ',')) {
160             float q = 1.0f;
161             int equalsPos = encoding.indexOf('=');
162             if (equalsPos != -1) {
163                 try {
164                     q = Float.valueOf(encoding.substring(equalsPos + 1));
165                 } catch (NumberFormatException e) {
166                     
167                     q = 0.0f;
168                 }
169             }
170             if (encoding.indexOf('*') >= 0) {
171                 starQ = q;
172             } else if (encoding.contains("gzip") && q > gzipQ) {
173                 gzipQ = q;
174             } else if (encoding.contains("deflate") && q > deflateQ) {
175                 deflateQ = q;
176             }
177         }
178         if (gzipQ > 0.0f || deflateQ > 0.0f) {
179             if (gzipQ >= deflateQ) {
180                 return ZlibWrapper.GZIP;
181             } else {
182                 return ZlibWrapper.ZLIB;
183             }
184         }
185         if (starQ > 0.0f) {
186             if (gzipQ == -1.0f) {
187                 return ZlibWrapper.GZIP;
188             }
189             if (deflateQ == -1.0f) {
190                 return ZlibWrapper.ZLIB;
191             }
192         }
193         return null;
194     }
195 }