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