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