1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.http.websocketx;
17
18 import io.netty.handler.codec.http.websocketx.WebSocketClientProtocolHandler.ClientHandshakeStateEvent;
19 import io.netty.util.internal.ObjectUtil;
20
21 import java.util.Arrays;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.LinkedHashSet;
25 import java.util.Locale;
26 import java.util.Set;
27
28 import static io.netty.util.internal.ObjectUtil.checkNonEmpty;
29 import static io.netty.util.internal.ObjectUtil.checkNotNull;
30 import static io.netty.util.internal.ObjectUtil.checkPositive;
31
32
33
34
35
36
37
38
39
40
41
42 public final class WebSocketServerProtocolConfig {
43
44 static final long DEFAULT_HANDSHAKE_TIMEOUT_MILLIS = 10000L;
45 static final long DEFAULT_FORCE_CLOSE_TIMEOUT_MILLIS = 10000L;
46
47 private final String websocketPath;
48 private final String subprotocols;
49 private final boolean checkStartsWith;
50 private final long handshakeTimeoutMillis;
51 private final long forceCloseTimeoutMillis;
52 private final boolean handleCloseFrames;
53 private final WebSocketCloseStatus sendCloseFrame;
54 private final boolean dropPongFrames;
55 private final WebSocketDecoderConfig decoderConfig;
56 private final Set<String> allowedOrigins;
57
58 private WebSocketServerProtocolConfig(
59 String websocketPath,
60 String subprotocols,
61 boolean checkStartsWith,
62 long handshakeTimeoutMillis,
63 long forceCloseTimeoutMillis,
64 boolean handleCloseFrames,
65 WebSocketCloseStatus sendCloseFrame,
66 boolean dropPongFrames,
67 WebSocketDecoderConfig decoderConfig,
68 Set<String> allowedOrigins
69 ) {
70 this.websocketPath = websocketPath;
71 this.subprotocols = subprotocols;
72 this.checkStartsWith = checkStartsWith;
73 this.handshakeTimeoutMillis = checkPositive(handshakeTimeoutMillis, "handshakeTimeoutMillis");
74 this.forceCloseTimeoutMillis = forceCloseTimeoutMillis;
75 this.handleCloseFrames = handleCloseFrames;
76 this.sendCloseFrame = sendCloseFrame;
77 this.dropPongFrames = dropPongFrames;
78 this.decoderConfig = decoderConfig == null ? WebSocketDecoderConfig.DEFAULT : decoderConfig;
79 this.allowedOrigins = allowedOrigins;
80 }
81
82 public String websocketPath() {
83 return websocketPath;
84 }
85
86 public String subprotocols() {
87 return subprotocols;
88 }
89
90 public boolean checkStartsWith() {
91 return checkStartsWith;
92 }
93
94 public long handshakeTimeoutMillis() {
95 return handshakeTimeoutMillis;
96 }
97
98 public long forceCloseTimeoutMillis() {
99 return forceCloseTimeoutMillis;
100 }
101
102 public boolean handleCloseFrames() {
103 return handleCloseFrames;
104 }
105
106 public WebSocketCloseStatus sendCloseFrame() {
107 return sendCloseFrame;
108 }
109
110 public boolean dropPongFrames() {
111 return dropPongFrames;
112 }
113
114 public WebSocketDecoderConfig decoderConfig() {
115 return decoderConfig;
116 }
117
118
119
120
121
122 public Set<String> allowedOrigins() {
123 return allowedOrigins;
124 }
125
126 @Override
127 public String toString() {
128 return "WebSocketServerProtocolConfig" +
129 " {websocketPath=" + websocketPath +
130 ", subprotocols=" + subprotocols +
131 ", checkStartsWith=" + checkStartsWith +
132 ", handshakeTimeoutMillis=" + handshakeTimeoutMillis +
133 ", forceCloseTimeoutMillis=" + forceCloseTimeoutMillis +
134 ", handleCloseFrames=" + handleCloseFrames +
135 ", sendCloseFrame=" + sendCloseFrame +
136 ", dropPongFrames=" + dropPongFrames +
137 ", decoderConfig=" + decoderConfig +
138 ", allowedOrigins=" + allowedOrigins +
139 "}";
140 }
141
142 public Builder toBuilder() {
143 return new Builder(this);
144 }
145
146 public static Builder newBuilder() {
147 return new Builder("/", null, false, DEFAULT_HANDSHAKE_TIMEOUT_MILLIS,
148 DEFAULT_FORCE_CLOSE_TIMEOUT_MILLIS, true, WebSocketCloseStatus.NORMAL_CLOSURE, true,
149 WebSocketDecoderConfig.DEFAULT, Collections.<String>emptySet());
150 }
151
152 public static final class Builder {
153 private String websocketPath;
154 private String subprotocols;
155 private boolean checkStartsWith;
156 private long handshakeTimeoutMillis;
157 private long forceCloseTimeoutMillis;
158 private boolean handleCloseFrames;
159 private WebSocketCloseStatus sendCloseFrame;
160 private boolean dropPongFrames;
161 private WebSocketDecoderConfig decoderConfig;
162 private WebSocketDecoderConfig.Builder decoderConfigBuilder;
163 private Set<String> allowedOrigins;
164
165 private Builder(WebSocketServerProtocolConfig serverConfig) {
166 this(ObjectUtil.checkNotNull(serverConfig, "serverConfig").websocketPath(),
167 serverConfig.subprotocols(),
168 serverConfig.checkStartsWith(),
169 serverConfig.handshakeTimeoutMillis(),
170 serverConfig.forceCloseTimeoutMillis(),
171 serverConfig.handleCloseFrames(),
172 serverConfig.sendCloseFrame(),
173 serverConfig.dropPongFrames(),
174 serverConfig.decoderConfig(),
175 serverConfig.allowedOrigins()
176 );
177 }
178
179 private Builder(String websocketPath,
180 String subprotocols,
181 boolean checkStartsWith,
182 long handshakeTimeoutMillis,
183 long forceCloseTimeoutMillis,
184 boolean handleCloseFrames,
185 WebSocketCloseStatus sendCloseFrame,
186 boolean dropPongFrames,
187 WebSocketDecoderConfig decoderConfig,
188 Set<String> allowedOrigins) {
189 this.websocketPath = websocketPath;
190 this.subprotocols = subprotocols;
191 this.checkStartsWith = checkStartsWith;
192 this.handshakeTimeoutMillis = handshakeTimeoutMillis;
193 this.forceCloseTimeoutMillis = forceCloseTimeoutMillis;
194 this.handleCloseFrames = handleCloseFrames;
195 this.sendCloseFrame = sendCloseFrame;
196 this.dropPongFrames = dropPongFrames;
197 this.decoderConfig = decoderConfig;
198 this.allowedOrigins = allowedOrigins;
199 }
200
201
202
203
204 public Builder websocketPath(String websocketPath) {
205 this.websocketPath = websocketPath;
206 return this;
207 }
208
209
210
211
212 public Builder subprotocols(String subprotocols) {
213 this.subprotocols = subprotocols;
214 return this;
215 }
216
217
218
219
220
221 public Builder checkStartsWith(boolean checkStartsWith) {
222 this.checkStartsWith = checkStartsWith;
223 return this;
224 }
225
226
227
228
229
230 public Builder handshakeTimeoutMillis(long handshakeTimeoutMillis) {
231 this.handshakeTimeoutMillis = handshakeTimeoutMillis;
232 return this;
233 }
234
235
236
237
238 public Builder forceCloseTimeoutMillis(long forceCloseTimeoutMillis) {
239 this.forceCloseTimeoutMillis = forceCloseTimeoutMillis;
240 return this;
241 }
242
243
244
245
246 public Builder handleCloseFrames(boolean handleCloseFrames) {
247 this.handleCloseFrames = handleCloseFrames;
248 return this;
249 }
250
251
252
253
254 public Builder sendCloseFrame(WebSocketCloseStatus sendCloseFrame) {
255 this.sendCloseFrame = sendCloseFrame;
256 return this;
257 }
258
259
260
261
262 public Builder dropPongFrames(boolean dropPongFrames) {
263 this.dropPongFrames = dropPongFrames;
264 return this;
265 }
266
267
268
269
270 public Builder decoderConfig(WebSocketDecoderConfig decoderConfig) {
271 this.decoderConfig = decoderConfig == null ? WebSocketDecoderConfig.DEFAULT : decoderConfig;
272 this.decoderConfigBuilder = null;
273 return this;
274 }
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292 public Builder allowedOrigins(String... allowedOrigins) {
293 return allowedOrigins(Arrays.asList(checkNonEmpty(allowedOrigins, "allowedOrigins")));
294 }
295
296
297
298
299
300
301 public Builder allowedOrigins(Collection<String> allowedOrigins) {
302 checkNonEmpty(allowedOrigins, "allowedOrigins");
303 Set<String> origins = new LinkedHashSet<String>(allowedOrigins.size());
304 for (String origin : allowedOrigins) {
305 origins.add(checkNotNull(origin, "origin").toLowerCase(Locale.ROOT));
306 }
307 this.allowedOrigins = Collections.unmodifiableSet(origins);
308 return this;
309 }
310
311 private WebSocketDecoderConfig.Builder decoderConfigBuilder() {
312 if (decoderConfigBuilder == null) {
313 decoderConfigBuilder = decoderConfig.toBuilder();
314 }
315 return decoderConfigBuilder;
316 }
317
318 public Builder maxFramePayloadLength(int maxFramePayloadLength) {
319 decoderConfigBuilder().maxFramePayloadLength(maxFramePayloadLength);
320 return this;
321 }
322
323 public Builder expectMaskedFrames(boolean expectMaskedFrames) {
324 decoderConfigBuilder().expectMaskedFrames(expectMaskedFrames);
325 return this;
326 }
327
328 public Builder allowMaskMismatch(boolean allowMaskMismatch) {
329 decoderConfigBuilder().allowMaskMismatch(allowMaskMismatch);
330 return this;
331 }
332
333 public Builder allowExtensions(boolean allowExtensions) {
334 decoderConfigBuilder().allowExtensions(allowExtensions);
335 return this;
336 }
337
338 public Builder closeOnProtocolViolation(boolean closeOnProtocolViolation) {
339 decoderConfigBuilder().closeOnProtocolViolation(closeOnProtocolViolation);
340 return this;
341 }
342
343 public Builder withUTF8Validator(boolean withUTF8Validator) {
344 decoderConfigBuilder().withUTF8Validator(withUTF8Validator);
345 return this;
346 }
347
348
349
350
351 public WebSocketServerProtocolConfig build() {
352 return new WebSocketServerProtocolConfig(
353 websocketPath,
354 subprotocols,
355 checkStartsWith,
356 handshakeTimeoutMillis,
357 forceCloseTimeoutMillis,
358 handleCloseFrames,
359 sendCloseFrame,
360 dropPongFrames,
361 decoderConfigBuilder == null ? decoderConfig : decoderConfigBuilder.build(),
362 allowedOrigins
363 );
364 }
365 }
366 }