View Javadoc
1   /*
2    * Copyright 2014 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.handler.codec.http.websocketx.extensions.compression;
17  
18  import io.netty.handler.codec.http.websocketx.extensions.WebSocketExtensionData;
19  import io.netty.handler.codec.http.websocketx.extensions.WebSocketExtensionDecoder;
20  import io.netty.handler.codec.http.websocketx.extensions.WebSocketExtensionEncoder;
21  import io.netty.handler.codec.http.websocketx.extensions.WebSocketExtensionFilterProvider;
22  import io.netty.handler.codec.http.websocketx.extensions.WebSocketServerExtension;
23  import io.netty.handler.codec.http.websocketx.extensions.WebSocketServerExtensionHandshaker;
24  
25  import java.util.Collections;
26  
27  import static io.netty.util.internal.ObjectUtil.*;
28  
29  /**
30   * <a href="https://tools.ietf.org/id/draft-tyoshino-hybi-websocket-perframe-deflate-06.txt">perframe-deflate</a>
31   * handshake implementation.
32   */
33  public final class DeflateFrameServerExtensionHandshaker implements WebSocketServerExtensionHandshaker {
34  
35      public static final int DEFAULT_COMPRESSION_LEVEL = 6;
36  
37      static final String X_WEBKIT_DEFLATE_FRAME_EXTENSION = "x-webkit-deflate-frame";
38      static final String DEFLATE_FRAME_EXTENSION = "deflate-frame";
39  
40      private final int compressionLevel;
41      private final WebSocketExtensionFilterProvider extensionFilterProvider;
42      private final int maxAllocation;
43  
44      /**
45       * Constructor with default configuration.
46       * @deprecated
47       *            Use {@link DeflateFrameServerExtensionHandshaker#DeflateFrameServerExtensionHandshaker(int, int)}
48       *            with {@link DeflateFrameServerExtensionHandshaker#DEFAULT_COMPRESSION_LEVEL}.
49       */
50      @Deprecated
51      public DeflateFrameServerExtensionHandshaker() {
52          this(DEFAULT_COMPRESSION_LEVEL, 0);
53      }
54  
55      /**
56       * Constructor with custom configuration.
57       *
58       * @param compressionLevel
59       *            Compression level between 0 and 9 (default is 6).
60       * @deprecated
61       *            Use {@link DeflateFrameServerExtensionHandshaker#DeflateFrameServerExtensionHandshaker(int, int)}.
62       */
63      @Deprecated
64      public DeflateFrameServerExtensionHandshaker(int compressionLevel) {
65          this(compressionLevel, 0);
66      }
67  
68      /**
69       * Constructor with custom configuration.
70       *
71       * @param compressionLevel
72       *            Compression level between 0 and 9 (default is 6).
73       * @param maxAllocation
74       *            Maximum size of the decompression buffer. Must be &gt;= 0. If zero, maximum size is not limited.
75       */
76      public DeflateFrameServerExtensionHandshaker(int compressionLevel, int maxAllocation) {
77          this(compressionLevel, WebSocketExtensionFilterProvider.DEFAULT, maxAllocation);
78      }
79  
80      /**
81       * Constructor with custom configuration.
82       *
83       * @param compressionLevel
84       *            Compression level between 0 and 9 (default is 6).
85       * @param extensionFilterProvider
86       *            provides server extension filters for per frame deflate encoder and decoder.
87       * @deprecated
88       *            Use {@link DeflateFrameServerExtensionHandshaker#DeflateFrameServerExtensionHandshaker(int,
89       *            WebSocketExtensionFilterProvider, int)}.
90       */
91      @Deprecated
92      public DeflateFrameServerExtensionHandshaker(int compressionLevel,
93                                                   WebSocketExtensionFilterProvider extensionFilterProvider) {
94          this(compressionLevel, extensionFilterProvider, 0);
95      }
96  
97      /**
98       * Constructor with custom configuration.
99       *
100      * @param compressionLevel
101      *            Compression level between 0 and 9 (default is 6).
102      * @param extensionFilterProvider
103      *            provides server extension filters for per frame deflate encoder and decoder.
104      * @param maxAllocation
105      *            Maximum size of the decompression buffer. Must be &gt;= 0. If zero, maximum size is not limited.
106      */
107     public DeflateFrameServerExtensionHandshaker(int compressionLevel,
108             WebSocketExtensionFilterProvider extensionFilterProvider,
109             int maxAllocation) {
110         if (compressionLevel < 0 || compressionLevel > 9) {
111             throw new IllegalArgumentException(
112                     "compressionLevel: " + compressionLevel + " (expected: 0-9)");
113         }
114         this.compressionLevel = compressionLevel;
115         this.extensionFilterProvider = checkNotNull(extensionFilterProvider, "extensionFilterProvider");
116         this.maxAllocation = checkPositiveOrZero(maxAllocation, "maxAllocation");
117     }
118 
119     @Override
120     public WebSocketServerExtension handshakeExtension(WebSocketExtensionData extensionData) {
121         if (!X_WEBKIT_DEFLATE_FRAME_EXTENSION.equals(extensionData.name()) &&
122             !DEFLATE_FRAME_EXTENSION.equals(extensionData.name())) {
123             return null;
124         }
125 
126         if (extensionData.parameters().isEmpty()) {
127             return new DeflateFrameServerExtension(compressionLevel, extensionData.name(), extensionFilterProvider,
128                                                    maxAllocation);
129         } else {
130             return null;
131         }
132     }
133 
134     private static class DeflateFrameServerExtension implements WebSocketServerExtension {
135 
136         private final String extensionName;
137         private final int compressionLevel;
138         private final WebSocketExtensionFilterProvider extensionFilterProvider;
139         private final int maxAllocation;
140 
141         DeflateFrameServerExtension(int compressionLevel, String extensionName,
142                 WebSocketExtensionFilterProvider extensionFilterProvider,
143                 int maxAllocation) {
144             this.extensionName = extensionName;
145             this.compressionLevel = compressionLevel;
146             this.extensionFilterProvider = extensionFilterProvider;
147             this.maxAllocation = maxAllocation;
148         }
149 
150         @Override
151         public int rsv() {
152             return RSV1;
153         }
154 
155         @Override
156         public WebSocketExtensionEncoder newExtensionEncoder() {
157             return new PerFrameDeflateEncoder(compressionLevel, 15, false,
158                                               extensionFilterProvider.encoderFilter());
159         }
160 
161         @Override
162         public WebSocketExtensionDecoder newExtensionDecoder() {
163             return new PerFrameDeflateDecoder(false, extensionFilterProvider.decoderFilter(), maxAllocation);
164         }
165 
166         @Override
167         public WebSocketExtensionData newReponseData() {
168             return new WebSocketExtensionData(extensionName, Collections.<String, String>emptyMap());
169         }
170     }
171 
172 }