1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.http.websocketx.extensions.compression;
17
18 import io.netty.handler.codec.compression.ZlibCodecFactory;
19 import io.netty.handler.codec.http.websocketx.extensions.WebSocketClientExtension;
20 import io.netty.handler.codec.http.websocketx.extensions.WebSocketClientExtensionHandshaker;
21 import io.netty.handler.codec.http.websocketx.extensions.WebSocketExtensionData;
22 import io.netty.handler.codec.http.websocketx.extensions.WebSocketExtensionDecoder;
23 import io.netty.handler.codec.http.websocketx.extensions.WebSocketExtensionEncoder;
24 import io.netty.handler.codec.http.websocketx.extensions.WebSocketExtensionFilterProvider;
25
26 import java.util.HashMap;
27 import java.util.Iterator;
28 import java.util.Map.Entry;
29
30 import static io.netty.handler.codec.http.websocketx.extensions.compression.PerMessageDeflateServerExtensionHandshaker.*;
31 import static io.netty.util.internal.ObjectUtil.*;
32
33
34
35
36
37 public final class PerMessageDeflateClientExtensionHandshaker implements WebSocketClientExtensionHandshaker {
38
39 private final int compressionLevel;
40 private final boolean allowClientWindowSize;
41 private final int requestedServerWindowSize;
42 private final boolean allowClientNoContext;
43 private final boolean requestedServerNoContext;
44 private final WebSocketExtensionFilterProvider extensionFilterProvider;
45 private final int maxAllocation;
46
47
48
49
50
51
52
53 @Deprecated
54 public PerMessageDeflateClientExtensionHandshaker() {
55 this(0);
56 }
57
58
59
60
61
62
63 public PerMessageDeflateClientExtensionHandshaker(int maxAllocation) {
64 this(6, ZlibCodecFactory.isSupportingWindowSizeAndMemLevel(), MAX_WINDOW_SIZE, false, false, maxAllocation);
65 }
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87 @Deprecated
88 public PerMessageDeflateClientExtensionHandshaker(int compressionLevel,
89 boolean allowClientWindowSize, int requestedServerWindowSize,
90 boolean allowClientNoContext, boolean requestedServerNoContext) {
91 this(compressionLevel, allowClientWindowSize, requestedServerWindowSize, allowClientNoContext,
92 requestedServerNoContext, 0);
93 }
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114 public PerMessageDeflateClientExtensionHandshaker(int compressionLevel,
115 boolean allowClientWindowSize, int requestedServerWindowSize,
116 boolean allowClientNoContext, boolean requestedServerNoContext,
117 int maxAllocation) {
118 this(compressionLevel, allowClientWindowSize, requestedServerWindowSize,
119 allowClientNoContext, requestedServerNoContext, WebSocketExtensionFilterProvider.DEFAULT, maxAllocation);
120 }
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144 @Deprecated
145 public PerMessageDeflateClientExtensionHandshaker(int compressionLevel,
146 boolean allowClientWindowSize, int requestedServerWindowSize,
147 boolean allowClientNoContext, boolean requestedServerNoContext,
148 WebSocketExtensionFilterProvider extensionFilterProvider) {
149 this(compressionLevel, allowClientWindowSize, requestedServerWindowSize,
150 allowClientNoContext, requestedServerNoContext, extensionFilterProvider, 0);
151 }
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174 public PerMessageDeflateClientExtensionHandshaker(int compressionLevel,
175 boolean allowClientWindowSize, int requestedServerWindowSize,
176 boolean allowClientNoContext, boolean requestedServerNoContext,
177 WebSocketExtensionFilterProvider extensionFilterProvider,
178 int maxAllocation) {
179
180 if (requestedServerWindowSize > MAX_WINDOW_SIZE || requestedServerWindowSize < MIN_WINDOW_SIZE) {
181 throw new IllegalArgumentException(
182 "requestedServerWindowSize: " + requestedServerWindowSize + " (expected: 8-15)");
183 }
184 if (compressionLevel < 0 || compressionLevel > 9) {
185 throw new IllegalArgumentException(
186 "compressionLevel: " + compressionLevel + " (expected: 0-9)");
187 }
188 this.compressionLevel = compressionLevel;
189 this.allowClientWindowSize = allowClientWindowSize;
190 this.requestedServerWindowSize = requestedServerWindowSize;
191 this.allowClientNoContext = allowClientNoContext;
192 this.requestedServerNoContext = requestedServerNoContext;
193 this.extensionFilterProvider = checkNotNull(extensionFilterProvider, "extensionFilterProvider");
194 this.maxAllocation = checkPositiveOrZero(maxAllocation, "maxAllocation");
195 }
196
197 @Override
198 public WebSocketExtensionData newRequestData() {
199 HashMap<String, String> parameters = new HashMap<String, String>(4);
200 if (requestedServerNoContext) {
201 parameters.put(SERVER_NO_CONTEXT, null);
202 }
203 if (allowClientNoContext) {
204 parameters.put(CLIENT_NO_CONTEXT, null);
205 }
206 if (requestedServerWindowSize != MAX_WINDOW_SIZE) {
207 parameters.put(SERVER_MAX_WINDOW, Integer.toString(requestedServerWindowSize));
208 }
209 if (allowClientWindowSize) {
210 parameters.put(CLIENT_MAX_WINDOW, null);
211 }
212 return new WebSocketExtensionData(PERMESSAGE_DEFLATE_EXTENSION, parameters);
213 }
214
215 @Override
216 public WebSocketClientExtension handshakeExtension(WebSocketExtensionData extensionData) {
217 if (!PERMESSAGE_DEFLATE_EXTENSION.equals(extensionData.name())) {
218 return null;
219 }
220
221 boolean succeed = true;
222 int clientWindowSize = MAX_WINDOW_SIZE;
223 int serverWindowSize = MAX_WINDOW_SIZE;
224 boolean serverNoContext = false;
225 boolean clientNoContext = false;
226
227 Iterator<Entry<String, String>> parametersIterator =
228 extensionData.parameters().entrySet().iterator();
229 while (succeed && parametersIterator.hasNext()) {
230 Entry<String, String> parameter = parametersIterator.next();
231
232 if (CLIENT_MAX_WINDOW.equalsIgnoreCase(parameter.getKey())) {
233
234 if (allowClientWindowSize) {
235 clientWindowSize = Integer.parseInt(parameter.getValue());
236 if (clientWindowSize > MAX_WINDOW_SIZE || clientWindowSize < MIN_WINDOW_SIZE) {
237 succeed = false;
238 }
239 } else {
240 succeed = false;
241 }
242 } else if (SERVER_MAX_WINDOW.equalsIgnoreCase(parameter.getKey())) {
243
244 serverWindowSize = Integer.parseInt(parameter.getValue());
245 if (serverWindowSize > MAX_WINDOW_SIZE || serverWindowSize < MIN_WINDOW_SIZE) {
246 succeed = false;
247 }
248 } else if (CLIENT_NO_CONTEXT.equalsIgnoreCase(parameter.getKey())) {
249
250 if (allowClientNoContext) {
251 clientNoContext = true;
252 } else {
253 succeed = false;
254 }
255 } else if (SERVER_NO_CONTEXT.equalsIgnoreCase(parameter.getKey())) {
256
257 serverNoContext = true;
258 } else {
259
260 succeed = false;
261 }
262 }
263
264 if ((requestedServerNoContext && !serverNoContext) ||
265 requestedServerWindowSize < serverWindowSize) {
266 succeed = false;
267 }
268
269 if (succeed) {
270 return new PermessageDeflateExtension(serverNoContext, serverWindowSize,
271 clientNoContext, clientWindowSize, extensionFilterProvider, maxAllocation);
272 } else {
273 return null;
274 }
275 }
276
277 private final class PermessageDeflateExtension implements WebSocketClientExtension {
278
279 private final boolean serverNoContext;
280 private final int serverWindowSize;
281 private final boolean clientNoContext;
282 private final int clientWindowSize;
283 private final WebSocketExtensionFilterProvider extensionFilterProvider;
284 private final int maxAllocation;
285
286 @Override
287 public int rsv() {
288 return RSV1;
289 }
290
291 PermessageDeflateExtension(boolean serverNoContext, int serverWindowSize,
292 boolean clientNoContext, int clientWindowSize,
293 WebSocketExtensionFilterProvider extensionFilterProvider, int maxAllocation) {
294 this.serverNoContext = serverNoContext;
295 this.serverWindowSize = serverWindowSize;
296 this.clientNoContext = clientNoContext;
297 this.clientWindowSize = clientWindowSize;
298 this.extensionFilterProvider = extensionFilterProvider;
299 this.maxAllocation = maxAllocation;
300 }
301
302 @Override
303 public WebSocketExtensionEncoder newExtensionEncoder() {
304 return new PerMessageDeflateEncoder(compressionLevel, clientWindowSize, clientNoContext,
305 extensionFilterProvider.encoderFilter());
306 }
307
308 @Override
309 public WebSocketExtensionDecoder newExtensionDecoder() {
310 return new PerMessageDeflateDecoder(serverNoContext, extensionFilterProvider.decoderFilter(),
311 maxAllocation);
312 }
313 }
314
315 }