1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.websocket.common;
20
21 import java.nio.ByteBuffer;
22 import java.util.List;
23
24 import org.eclipse.jetty.io.ByteBufferPool;
25 import org.eclipse.jetty.util.BufferUtil;
26 import org.eclipse.jetty.websocket.api.ProtocolException;
27 import org.eclipse.jetty.websocket.api.WebSocketBehavior;
28 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
29 import org.eclipse.jetty.websocket.api.extensions.Extension;
30 import org.eclipse.jetty.websocket.api.extensions.Frame;
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 public class Generator
57 {
58
59
60
61 public static final int MAX_HEADER_LENGTH = 28;
62
63 private final WebSocketBehavior behavior;
64 private final ByteBufferPool bufferPool;
65 private final boolean validating;
66
67
68
69
70
71
72
73
74
75
76
77 private byte flagsInUse=0x00;
78
79
80
81
82
83
84
85
86
87 public Generator(WebSocketPolicy policy, ByteBufferPool bufferPool)
88 {
89 this(policy,bufferPool,true);
90 }
91
92
93
94
95
96
97
98
99
100
101
102 public Generator(WebSocketPolicy policy, ByteBufferPool bufferPool, boolean validating)
103 {
104 this.behavior = policy.getBehavior();
105 this.bufferPool = bufferPool;
106 this.validating = validating;
107 }
108
109 public void assertFrameValid(Frame frame)
110 {
111 if (!validating)
112 {
113 return;
114 }
115
116
117
118
119
120
121
122 if (frame.isRsv1() && !isRsv1InUse())
123 {
124 throw new ProtocolException("RSV1 not allowed to be set");
125 }
126
127 if (frame.isRsv2() && !isRsv2InUse())
128 {
129 throw new ProtocolException("RSV2 not allowed to be set");
130 }
131
132 if (frame.isRsv3() && !isRsv3InUse())
133 {
134 throw new ProtocolException("RSV3 not allowed to be set");
135 }
136
137 if (OpCode.isControlFrame(frame.getOpCode()))
138 {
139
140
141
142
143
144 if (frame.getPayloadLength() > 125)
145 {
146 throw new ProtocolException("Invalid control frame payload length");
147 }
148
149 if (!frame.isFin())
150 {
151 throw new ProtocolException("Control Frames must be FIN=true");
152 }
153
154
155
156
157
158
159 if (frame.getOpCode() == OpCode.CLOSE)
160 {
161
162 ByteBuffer payload = frame.getPayload();
163 if (payload != null)
164 {
165 new CloseInfo(payload,true);
166 }
167 }
168 }
169 }
170
171 public void configureFromExtensions(List<? extends Extension> exts)
172 {
173
174 flagsInUse = 0x00;
175
176
177 for (Extension ext : exts)
178 {
179 if (ext.isRsv1User())
180 {
181 flagsInUse = (byte)(flagsInUse | 0x40);
182 }
183 if (ext.isRsv2User())
184 {
185 flagsInUse = (byte)(flagsInUse | 0x20);
186 }
187 if (ext.isRsv3User())
188 {
189 flagsInUse = (byte)(flagsInUse | 0x10);
190 }
191 }
192 }
193
194 public ByteBuffer generateHeaderBytes(Frame frame)
195 {
196 ByteBuffer buffer = bufferPool.acquire(MAX_HEADER_LENGTH,true);
197 generateHeaderBytes(frame,buffer);
198 return buffer;
199 }
200
201 public void generateHeaderBytes(Frame frame, ByteBuffer buffer)
202 {
203 int p=BufferUtil.flipToFill(buffer);
204
205
206 assertFrameValid(frame);
207
208
209
210
211 byte b = 0x00;
212
213
214 if (frame.isFin())
215 {
216 b |= 0x80;
217 }
218
219
220 if (frame.isRsv1())
221 {
222 b |= 0x40;
223 }
224 if (frame.isRsv2())
225 {
226 b |= 0x20;
227 }
228 if (frame.isRsv3())
229 {
230 b |= 0x10;
231 }
232
233
234 byte opcode = frame.getOpCode();
235
236 if (frame.getOpCode() == OpCode.CONTINUATION)
237 {
238
239 opcode = OpCode.CONTINUATION;
240 }
241
242 b |= opcode & 0x0F;
243
244 buffer.put(b);
245
246
247 b = (frame.isMasked()?(byte)0x80:(byte)0x00);
248
249
250 int payloadLength = frame.getPayloadLength();
251
252
253
254
255 if (payloadLength > 0xFF_FF)
256 {
257
258 b |= 0x7F;
259 buffer.put(b);
260 buffer.put((byte)0);
261 buffer.put((byte)0);
262 buffer.put((byte)0);
263 buffer.put((byte)0);
264 buffer.put((byte)((payloadLength >> 24) & 0xFF));
265 buffer.put((byte)((payloadLength >> 16) & 0xFF));
266 buffer.put((byte)((payloadLength >> 8) & 0xFF));
267 buffer.put((byte)(payloadLength & 0xFF));
268 }
269
270
271
272 else if (payloadLength >= 0x7E )
273 {
274 b |= 0x7E;
275 buffer.put(b);
276 buffer.put((byte)(payloadLength >> 8));
277 buffer.put((byte)(payloadLength & 0xFF));
278 }
279
280
281
282 else
283 {
284 b |= (payloadLength & 0x7F);
285 buffer.put(b);
286 }
287
288
289 if (frame.isMasked())
290 {
291 byte[] mask = frame.getMask();
292 buffer.put(mask);
293 int maskInt = 0;
294 for (byte maskByte : mask)
295 maskInt = (maskInt << 8) + (maskByte & 0xFF);
296
297
298 ByteBuffer payload = frame.getPayload();
299 if ((payload != null) && (payload.remaining() > 0))
300 {
301 int maskOffset = 0;
302 int start = payload.position();
303 int end = payload.limit();
304 int remaining;
305 while ((remaining = end - start) > 0)
306 {
307 if (remaining >= 4)
308 {
309 payload.putInt(start, payload.getInt(start) ^ maskInt);
310 start += 4;
311 }
312 else
313 {
314 payload.put(start, (byte)(payload.get(start) ^ mask[maskOffset & 3]));
315 ++start;
316 ++maskOffset;
317 }
318 }
319 }
320 }
321
322 BufferUtil.flipToFlush(buffer,p);
323 }
324
325
326
327
328
329
330
331
332
333 public void generateWholeFrame(Frame frame, ByteBuffer buf)
334 {
335 buf.put(generateHeaderBytes(frame));
336 if (frame.hasPayload())
337 {
338 buf.put(frame.getPayload());
339 }
340 }
341
342 public ByteBufferPool getBufferPool()
343 {
344 return bufferPool;
345 }
346
347
348 public void setRsv1InUse(boolean rsv1InUse)
349 {
350 flagsInUse = (byte)((flagsInUse & 0xBF) | (rsv1InUse?0x40:0x00));
351 }
352
353 public void setRsv2InUse(boolean rsv2InUse)
354 {
355 flagsInUse = (byte)((flagsInUse & 0xDF) | (rsv2InUse?0x20:0x00));
356 }
357
358 public void setRsv3InUse(boolean rsv3InUse)
359 {
360 flagsInUse = (byte)((flagsInUse & 0xEF) | (rsv3InUse?0x10:0x00));
361 }
362
363 public boolean isRsv1InUse()
364 {
365 return (flagsInUse & 0x40) != 0;
366 }
367
368 public boolean isRsv2InUse()
369 {
370 return (flagsInUse & 0x20) != 0;
371 }
372
373 public boolean isRsv3InUse()
374 {
375 return (flagsInUse & 0x10) != 0;
376 }
377
378 @Override
379 public String toString()
380 {
381 StringBuilder builder = new StringBuilder();
382 builder.append("Generator[");
383 builder.append(behavior);
384 if (validating)
385 {
386 builder.append(",validating");
387 }
388 if (isRsv1InUse())
389 {
390 builder.append(",+rsv1");
391 }
392 if (isRsv2InUse())
393 {
394 builder.append(",+rsv2");
395 }
396 if (isRsv3InUse())
397 {
398 builder.append(",+rsv3");
399 }
400 builder.append("]");
401 return builder.toString();
402 }
403 }