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.WebSocketClientExtension;
19  import io.netty.handler.codec.http.websocketx.extensions.WebSocketClientExtensionHandshaker;
20  import io.netty.handler.codec.http.websocketx.extensions.WebSocketExtensionData;
21  import io.netty.handler.codec.http.websocketx.extensions.WebSocketExtensionDecoder;
22  import io.netty.handler.codec.http.websocketx.extensions.WebSocketExtensionEncoder;
23  import io.netty.handler.codec.http.websocketx.extensions.WebSocketExtensionFilterProvider;
24  
25  import java.util.Collections;
26  
27  import static io.netty.handler.codec.http.websocketx.extensions.compression.DeflateFrameServerExtensionHandshaker.*;
28  import static io.netty.util.internal.ObjectUtil.*;
29  
30  /**
31   * <a href="https://tools.ietf.org/id/draft-tyoshino-hybi-websocket-perframe-deflate-06.txt">perframe-deflate</a>
32   * handshake implementation.
33   */
34  public final class DeflateFrameClientExtensionHandshaker implements WebSocketClientExtensionHandshaker {
35  
36      private final int compressionLevel;
37      private final boolean useWebkitExtensionName;
38      private final WebSocketExtensionFilterProvider extensionFilterProvider;
39      private final int maxAllocation;
40  
41      /**
42       * Constructor with default configuration.
43       *
44       * @deprecated
45       *            Use {@link DeflateFrameClientExtensionHandshaker#DeflateFrameClientExtensionHandshaker(boolean, int)}.
46       */
47      @Deprecated
48      public DeflateFrameClientExtensionHandshaker(boolean useWebkitExtensionName) {
49          this(6, useWebkitExtensionName, 0);
50      }
51  
52      /**
53       * Constructor with default configuration.
54       *
55       * @param maxAllocation
56       *            Maximum size of the decompression buffer. Must be &gt;= 0. If zero, maximum size is not limited.
57       */
58      public DeflateFrameClientExtensionHandshaker(boolean useWebkitExtensionName, int maxAllocation) {
59          this(6, useWebkitExtensionName, maxAllocation);
60      }
61  
62      /**
63       * Constructor with custom configuration.
64       *
65       * @param compressionLevel
66       *            Compression level between 0 and 9 (default is 6).
67       * @deprecated
68       *            Use {@link
69       *            DeflateFrameClientExtensionHandshaker#DeflateFrameClientExtensionHandshaker(int, boolean, int)}.
70       */
71      @Deprecated
72      public DeflateFrameClientExtensionHandshaker(int compressionLevel, boolean useWebkitExtensionName) {
73          this(compressionLevel, useWebkitExtensionName, 0);
74      }
75  
76      /**
77       * Constructor with custom configuration.
78       *
79       * @param compressionLevel
80       *            Compression level between 0 and 9 (default is 6).
81       * @param maxAllocation
82       *            Maximum size of the decompression buffer. Must be &gt;= 0. If zero, maximum size is not limited.
83       */
84      public DeflateFrameClientExtensionHandshaker(int compressionLevel, boolean useWebkitExtensionName,
85                                                   int maxAllocation) {
86          this(compressionLevel, useWebkitExtensionName, WebSocketExtensionFilterProvider.DEFAULT, maxAllocation);
87      }
88  
89      /**
90       * Constructor with custom configuration.
91       *
92       * @param compressionLevel
93       *            Compression level between 0 and 9 (default is 6).
94       * @param extensionFilterProvider
95       *            provides client extension filters for per frame deflate encoder and decoder.
96       * @deprecated
97       *            Use {@link DeflateFrameClientExtensionHandshaker#DeflateFrameClientExtensionHandshaker(int, boolean,
98       *            WebSocketExtensionFilterProvider, int)}.
99       */
100     @Deprecated
101     public DeflateFrameClientExtensionHandshaker(int compressionLevel, boolean useWebkitExtensionName,
102                                                  WebSocketExtensionFilterProvider extensionFilterProvider) {
103         this(compressionLevel, useWebkitExtensionName, extensionFilterProvider, 0);
104     }
105 
106     /**
107      * Constructor with custom configuration.
108      *
109      * @param compressionLevel
110      *            Compression level between 0 and 9 (default is 6).
111      * @param extensionFilterProvider
112      *            provides client extension filters for per frame deflate encoder and decoder.
113      * @param maxAllocation
114      *            Maximum size of the decompression buffer. Must be &gt;= 0. If zero, maximum size is not limited.
115      */
116     public DeflateFrameClientExtensionHandshaker(int compressionLevel, boolean useWebkitExtensionName,
117             WebSocketExtensionFilterProvider extensionFilterProvider, int maxAllocation) {
118         if (compressionLevel < 0 || compressionLevel > 9) {
119             throw new IllegalArgumentException(
120                     "compressionLevel: " + compressionLevel + " (expected: 0-9)");
121         }
122         this.compressionLevel = compressionLevel;
123         this.useWebkitExtensionName = useWebkitExtensionName;
124         this.extensionFilterProvider = checkNotNull(extensionFilterProvider, "extensionFilterProvider");
125         this.maxAllocation = checkPositiveOrZero(maxAllocation, "maxAllocation");
126     }
127 
128     @Override
129     public WebSocketExtensionData newRequestData() {
130         return new WebSocketExtensionData(
131                 useWebkitExtensionName ? X_WEBKIT_DEFLATE_FRAME_EXTENSION : DEFLATE_FRAME_EXTENSION,
132                 Collections.<String, String>emptyMap());
133     }
134 
135     @Override
136     public WebSocketClientExtension handshakeExtension(WebSocketExtensionData extensionData) {
137         if (!X_WEBKIT_DEFLATE_FRAME_EXTENSION.equals(extensionData.name()) &&
138             !DEFLATE_FRAME_EXTENSION.equals(extensionData.name())) {
139             return null;
140         }
141 
142         if (extensionData.parameters().isEmpty()) {
143             return new DeflateFrameClientExtension(compressionLevel, extensionFilterProvider, maxAllocation);
144         } else {
145             return null;
146         }
147     }
148 
149     private static class DeflateFrameClientExtension implements WebSocketClientExtension {
150 
151         private final int compressionLevel;
152         private final WebSocketExtensionFilterProvider extensionFilterProvider;
153         private final int maxAllocation;
154 
155         DeflateFrameClientExtension(int compressionLevel, WebSocketExtensionFilterProvider extensionFilterProvider,
156                                     int maxAllocation) {
157             this.compressionLevel = compressionLevel;
158             this.extensionFilterProvider = extensionFilterProvider;
159             this.maxAllocation = maxAllocation;
160         }
161 
162         @Override
163         public int rsv() {
164             return RSV1;
165         }
166 
167         @Override
168         public WebSocketExtensionEncoder newExtensionEncoder() {
169             return new PerFrameDeflateEncoder(compressionLevel, 15, false,
170                                               extensionFilterProvider.encoderFilter());
171         }
172 
173         @Override
174         public WebSocketExtensionDecoder newExtensionDecoder() {
175             return new PerFrameDeflateDecoder(false, extensionFilterProvider.decoderFilter(), maxAllocation);
176         }
177     }
178 
179 }