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.Arrays;
23
24 import org.eclipse.jetty.util.BufferUtil;
25 import org.eclipse.jetty.util.StringUtil;
26 import org.eclipse.jetty.websocket.api.ProtocolException;
27 import org.eclipse.jetty.websocket.api.extensions.Frame;
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 public class WebSocketFrame implements Frame
54 {
55
56 public static final int MAX_CONTROL_PAYLOAD = 125;
57
58 public static WebSocketFrame binary()
59 {
60 return new WebSocketFrame(OpCode.BINARY);
61 }
62
63 public static WebSocketFrame binary(byte buf[])
64 {
65 return new WebSocketFrame(OpCode.BINARY).setPayload(buf);
66 }
67
68 public static WebSocketFrame ping()
69 {
70 return new WebSocketFrame(OpCode.PING);
71 }
72
73 public static WebSocketFrame pong()
74 {
75 return new WebSocketFrame(OpCode.PONG);
76 }
77
78 public static WebSocketFrame text()
79 {
80 return new WebSocketFrame(OpCode.TEXT);
81 }
82
83 public static WebSocketFrame text(String msg)
84 {
85 return new WebSocketFrame(OpCode.TEXT).setPayload(msg);
86 }
87
88 private boolean fin = true;
89 private boolean rsv1 = false;
90 private boolean rsv2 = false;
91 private boolean rsv3 = false;
92 protected byte opcode = OpCode.UNDEFINED;
93 private boolean masked = false;
94 private byte mask[];
95
96
97
98
99
100 private ByteBuffer data;
101 private int payloadLength = 0;
102
103 private int payloadStart = -1;
104
105 private Type type;
106 private boolean continuation = false;
107 private int continuationIndex = 0;
108
109
110
111
112 public WebSocketFrame()
113 {
114 this(OpCode.UNDEFINED);
115 }
116
117
118
119
120 public WebSocketFrame(byte opcode)
121 {
122 reset();
123 setOpCode(opcode);
124 }
125
126
127
128
129
130
131
132 public WebSocketFrame(Frame frame)
133 {
134 if (frame instanceof WebSocketFrame)
135 {
136 WebSocketFrame wsf = (WebSocketFrame)frame;
137 copy(wsf,wsf.data);
138 }
139 else
140 {
141
142 fin = frame.isFin();
143 rsv1 = frame.isRsv1();
144 rsv2 = frame.isRsv2();
145 rsv3 = frame.isRsv3();
146 opcode = frame.getType().getOpCode();
147 type = frame.getType();
148 masked = frame.isMasked();
149 mask = null;
150 byte maskCopy[] = frame.getMask();
151 if (maskCopy != null)
152 {
153 mask = new byte[maskCopy.length];
154 System.arraycopy(maskCopy,0,mask,0,mask.length);
155 }
156
157 setPayload(frame.getPayload());
158 }
159 }
160
161
162
163
164
165
166
167
168
169 public WebSocketFrame(WebSocketFrame copy)
170 {
171 copy(copy,copy.data);
172 }
173
174
175
176
177
178
179
180
181
182
183
184 public WebSocketFrame(WebSocketFrame copy, ByteBuffer altPayload)
185 {
186 copy(copy,altPayload);
187 }
188
189 public void assertValid()
190 {
191 if (OpCode.isControlFrame(opcode))
192 {
193 if (getPayloadLength() > WebSocketFrame.MAX_CONTROL_PAYLOAD)
194 {
195 throw new ProtocolException("Desired payload length [" + getPayloadLength() + "] exceeds maximum control payload length ["
196 + MAX_CONTROL_PAYLOAD + "]");
197 }
198
199 if (fin == false)
200 {
201 throw new ProtocolException("Cannot have FIN==false on Control frames");
202 }
203
204 if (rsv1 == true)
205 {
206 throw new ProtocolException("Cannot have RSV1==true on Control frames");
207 }
208
209 if (rsv2 == true)
210 {
211 throw new ProtocolException("Cannot have RSV2==true on Control frames");
212 }
213
214 if (rsv3 == true)
215 {
216 throw new ProtocolException("Cannot have RSV3==true on Control frames");
217 }
218
219 if (isContinuation())
220 {
221 throw new ProtocolException("Control frames cannot be Continuations");
222 }
223 }
224 }
225
226 private final void copy(WebSocketFrame copy, ByteBuffer payload)
227 {
228 fin = copy.fin;
229 rsv1 = copy.rsv1;
230 rsv2 = copy.rsv2;
231 rsv3 = copy.rsv3;
232 opcode = copy.opcode;
233 type = copy.type;
234 masked = copy.masked;
235 mask = null;
236 if (copy.mask != null)
237 {
238 mask = new byte[copy.mask.length];
239 System.arraycopy(copy.mask,0,mask,0,mask.length);
240 }
241 continuationIndex = copy.continuationIndex;
242 continuation = copy.continuation;
243
244 setPayload(payload);
245 }
246
247 @Override
248 public boolean equals(Object obj)
249 {
250 if (this == obj)
251 {
252 return true;
253 }
254 if (obj == null)
255 {
256 return false;
257 }
258 if (getClass() != obj.getClass())
259 {
260 return false;
261 }
262 WebSocketFrame other = (WebSocketFrame)obj;
263 if (continuation != other.continuation)
264 {
265 return false;
266 }
267 if (continuationIndex != other.continuationIndex)
268 {
269 return false;
270 }
271 if (data == null)
272 {
273 if (other.data != null)
274 {
275 return false;
276 }
277 }
278 else if (!data.equals(other.data))
279 {
280 return false;
281 }
282 if (fin != other.fin)
283 {
284 return false;
285 }
286 if (!Arrays.equals(mask,other.mask))
287 {
288 return false;
289 }
290 if (masked != other.masked)
291 {
292 return false;
293 }
294 if (opcode != other.opcode)
295 {
296 return false;
297 }
298 if (rsv1 != other.rsv1)
299 {
300 return false;
301 }
302 if (rsv2 != other.rsv2)
303 {
304 return false;
305 }
306 if (rsv3 != other.rsv3)
307 {
308 return false;
309 }
310 return true;
311 }
312
313
314
315
316
317
318
319
320
321
322 public int getContinuationIndex()
323 {
324 return continuationIndex;
325 }
326
327 @Override
328 public byte[] getMask()
329 {
330 if (!masked)
331 {
332 throw new IllegalStateException("Frame is not masked");
333 }
334 return mask;
335 }
336
337 @Override
338 public final byte getOpCode()
339 {
340 return opcode;
341 }
342
343
344
345
346
347
348
349
350
351 @Override
352 public ByteBuffer getPayload()
353 {
354 if (data != null)
355 {
356 return data;
357 }
358 else
359 {
360 return null;
361 }
362 }
363
364 public String getPayloadAsUTF8()
365 {
366 if (data == null)
367 {
368 return null;
369 }
370 return BufferUtil.toUTF8String(data);
371 }
372
373 @Override
374 public int getPayloadLength()
375 {
376 if (data == null)
377 {
378 return 0;
379 }
380 return payloadLength;
381 }
382
383 @Override
384 public int getPayloadStart()
385 {
386 if (data == null)
387 {
388 return -1;
389 }
390 return payloadStart;
391 }
392
393 @Override
394 public Type getType()
395 {
396 return type;
397 }
398
399 @Override
400 public int hashCode()
401 {
402 final int prime = 31;
403 int result = 1;
404 result = (prime * result) + (continuation?1231:1237);
405 result = (prime * result) + continuationIndex;
406 result = (prime * result) + ((data == null)?0:data.hashCode());
407 result = (prime * result) + (fin?1231:1237);
408 result = (prime * result) + Arrays.hashCode(mask);
409 result = (prime * result) + (masked?1231:1237);
410 result = (prime * result) + opcode;
411 result = (prime * result) + (rsv1?1231:1237);
412 result = (prime * result) + (rsv2?1231:1237);
413 result = (prime * result) + (rsv3?1231:1237);
414 return result;
415 }
416
417 @Override
418 public boolean hasPayload()
419 {
420 return ((data != null) && (payloadLength > 0));
421 }
422
423 @Override
424 public boolean isContinuation()
425 {
426 return continuation;
427 }
428
429 public boolean isControlFrame()
430 {
431 return OpCode.isControlFrame(opcode);
432 }
433
434 public boolean isDataFrame()
435 {
436 return OpCode.isDataFrame(opcode);
437 }
438
439 @Override
440 public boolean isFin()
441 {
442 return fin;
443 }
444
445 @Override
446 public boolean isLast()
447 {
448 return fin;
449 }
450
451 public boolean isLastFrame()
452 {
453 return fin;
454 }
455
456 @Override
457 public boolean isMasked()
458 {
459 return masked;
460 }
461
462 @Override
463 public boolean isRsv1()
464 {
465 return rsv1;
466 }
467
468 @Override
469 public boolean isRsv2()
470 {
471 return rsv2;
472 }
473
474 @Override
475 public boolean isRsv3()
476 {
477 return rsv3;
478 }
479
480
481
482
483
484
485
486
487 public int position()
488 {
489 if (data == null)
490 {
491 return -1;
492 }
493 return data.position();
494 }
495
496
497
498
499
500
501
502
503 @Override
504 public int remaining()
505 {
506 if (data == null)
507 {
508 return 0;
509 }
510 return data.remaining();
511 }
512
513 public void reset()
514 {
515 fin = true;
516 rsv1 = false;
517 rsv2 = false;
518 rsv3 = false;
519 opcode = -1;
520 masked = false;
521 data = null;
522 payloadLength = 0;
523 mask = null;
524 continuationIndex = 0;
525 continuation = false;
526 }
527
528 public Frame setContinuation(boolean continuation)
529 {
530 this.continuation = continuation;
531 return this;
532 }
533
534 public Frame setContinuationIndex(int continuationIndex)
535 {
536 this.continuationIndex = continuationIndex;
537 return this;
538 }
539
540 public WebSocketFrame setFin(boolean fin)
541 {
542 this.fin = fin;
543 return this;
544 }
545
546 public Frame setMask(byte[] maskingKey)
547 {
548 this.mask = maskingKey;
549 this.masked = (mask != null);
550 return this;
551 }
552
553 public Frame setMasked(boolean mask)
554 {
555 this.masked = mask;
556 return this;
557 }
558
559 public WebSocketFrame setOpCode(byte op)
560 {
561 this.opcode = op;
562
563 if (op == OpCode.UNDEFINED)
564 {
565 this.type = null;
566 }
567 else
568 {
569 this.type = Frame.Type.from(op);
570 }
571 return this;
572 }
573
574
575
576
577
578
579
580 public WebSocketFrame setPayload(byte buf[])
581 {
582 if (buf == null)
583 {
584 data = null;
585 return this;
586 }
587
588 if (OpCode.isControlFrame(opcode))
589 {
590 if (buf.length > WebSocketFrame.MAX_CONTROL_PAYLOAD)
591 {
592 throw new ProtocolException("Control Payloads can not exceed 125 bytes in length.");
593 }
594 }
595
596 data = BufferUtil.toBuffer(buf);
597 payloadStart = data.position();
598 payloadLength = data.limit();
599 return this;
600 }
601
602
603
604
605
606
607
608 public WebSocketFrame setPayload(byte buf[], int offset, int len)
609 {
610 if (buf == null)
611 {
612 data = null;
613 return this;
614 }
615
616 if (OpCode.isControlFrame(opcode))
617 {
618 if (len > WebSocketFrame.MAX_CONTROL_PAYLOAD)
619 {
620 throw new ProtocolException("Control Payloads can not exceed 125 bytes in length.");
621 }
622 }
623
624 data = BufferUtil.toBuffer(buf,offset,len);
625 payloadStart = data.position();
626 payloadLength = data.limit();
627 return this;
628 }
629
630
631
632
633
634
635
636
637
638
639
640 public WebSocketFrame setPayload(ByteBuffer buf)
641 {
642 if (buf == null)
643 {
644 data = null;
645 return this;
646 }
647
648 if (OpCode.isControlFrame(opcode))
649 {
650 if (buf.remaining() > WebSocketFrame.MAX_CONTROL_PAYLOAD)
651 {
652 throw new ProtocolException("Control Payloads can not exceed 125 bytes in length. (was " + buf.remaining() + " bytes)");
653 }
654 }
655
656 data = buf.slice();
657 payloadStart = data.position();
658 payloadLength = data.limit();
659 return this;
660 }
661
662 public WebSocketFrame setPayload(String str)
663 {
664 setPayload(BufferUtil.toBuffer(str,StringUtil.__UTF8_CHARSET));
665 return this;
666 }
667
668 public WebSocketFrame setRsv1(boolean rsv1)
669 {
670 this.rsv1 = rsv1;
671 return this;
672 }
673
674 public WebSocketFrame setRsv2(boolean rsv2)
675 {
676 this.rsv2 = rsv2;
677 return this;
678 }
679
680 public WebSocketFrame setRsv3(boolean rsv3)
681 {
682 this.rsv3 = rsv3;
683 return this;
684 }
685
686 @Override
687 public String toString()
688 {
689 StringBuilder b = new StringBuilder();
690 b.append(OpCode.name(opcode));
691 b.append('[');
692 b.append("len=").append(payloadLength);
693 b.append(",fin=").append(fin);
694 b.append(",rsv=");
695 b.append(rsv1?'1':'.');
696 b.append(rsv2?'1':'.');
697 b.append(rsv3?'1':'.');
698 b.append(",masked=").append(masked);
699 b.append(",continuation=").append(continuation);
700 b.append(",payloadStart=").append(getPayloadStart());
701 b.append(",remaining=").append(remaining());
702 b.append(",position=").append(position());
703 b.append(']');
704 return b.toString();
705 }
706 }