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.websocket.api.extensions.Frame;
26 import org.eclipse.jetty.websocket.common.frames.BinaryFrame;
27 import org.eclipse.jetty.websocket.common.frames.CloseFrame;
28 import org.eclipse.jetty.websocket.common.frames.ContinuationFrame;
29 import org.eclipse.jetty.websocket.common.frames.PingFrame;
30 import org.eclipse.jetty.websocket.common.frames.PongFrame;
31 import org.eclipse.jetty.websocket.common.frames.TextFrame;
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
57 public abstract class WebSocketFrame implements Frame
58 {
59 public static WebSocketFrame copy(Frame copy)
60 {
61 WebSocketFrame frame = null;
62 switch (copy.getOpCode())
63 {
64 case OpCode.BINARY:
65 frame = new BinaryFrame();
66 break;
67 case OpCode.TEXT:
68 frame = new TextFrame();
69 break;
70 case OpCode.CLOSE:
71 frame = new CloseFrame();
72 break;
73 case OpCode.CONTINUATION:
74 frame = new ContinuationFrame();
75 break;
76 case OpCode.PING:
77 frame = new PingFrame();
78 break;
79 case OpCode.PONG:
80 frame = new PongFrame();
81 break;
82 default:
83 throw new IllegalArgumentException("Cannot copy frame with opcode " + copy.getOpCode() + " - " + copy);
84 }
85
86 frame.copyHeaders(copy);
87 frame.setPayload(copy.getPayload());
88
89 return frame;
90 }
91
92
93
94
95
96
97
98
99
100
101
102
103
104 protected byte finRsvOp;
105 protected boolean masked = false;
106
107 protected byte mask[];
108
109
110
111
112
113 protected ByteBuffer data;
114
115 protected int payloadLength = 0;
116
117
118
119
120 protected WebSocketFrame(byte opcode)
121 {
122 reset();
123 setOpCode(opcode);
124 }
125
126 public abstract void assertValid();
127
128 protected void copy(WebSocketFrame copy, ByteBuffer payload)
129 {
130 copyHeaders(copy);
131 setPayload(payload);
132 }
133
134 protected void copyHeaders(Frame frame)
135 {
136 finRsvOp = 0x00;
137 finRsvOp |= frame.isFin()?0x80:0x00;
138 finRsvOp |= frame.isRsv1()?0x40:0x00;
139 finRsvOp |= frame.isRsv2()?0x20:0x00;
140 finRsvOp |= frame.isRsv3()?0x10:0x00;
141 finRsvOp |= frame.getOpCode() & 0x0F;
142
143 masked = frame.isMasked();
144 if (masked)
145 {
146 mask = frame.getMask();
147 }
148 else
149 {
150 mask = null;
151 }
152 }
153
154 protected void copyHeaders(WebSocketFrame copy)
155 {
156 finRsvOp = copy.finRsvOp;
157 masked = copy.masked;
158 mask = null;
159 if (copy.mask != null)
160 {
161 mask = new byte[copy.mask.length];
162 System.arraycopy(copy.mask,0,mask,0,mask.length);
163 }
164 }
165
166 @Override
167 public boolean equals(Object obj)
168 {
169 if (this == obj)
170 {
171 return true;
172 }
173 if (obj == null)
174 {
175 return false;
176 }
177 if (getClass() != obj.getClass())
178 {
179 return false;
180 }
181 WebSocketFrame other = (WebSocketFrame)obj;
182 if (data == null)
183 {
184 if (other.data != null)
185 {
186 return false;
187 }
188 }
189 else if (!data.equals(other.data))
190 {
191 return false;
192 }
193 if (finRsvOp != other.finRsvOp)
194 {
195 return false;
196 }
197 if (!Arrays.equals(mask,other.mask))
198 {
199 return false;
200 }
201 if (masked != other.masked)
202 {
203 return false;
204 }
205 return true;
206 }
207
208 @Override
209 public byte[] getMask()
210 {
211 return mask;
212 }
213
214 @Override
215 public final byte getOpCode()
216 {
217 return (byte)(finRsvOp & 0x0F);
218 }
219
220
221
222
223
224
225
226
227
228 @Override
229 public ByteBuffer getPayload()
230 {
231 return data;
232 }
233
234 public String getPayloadAsUTF8()
235 {
236 return BufferUtil.toUTF8String(getPayload());
237 }
238
239 @Override
240 public int getPayloadLength()
241 {
242 if (data == null)
243 {
244 return 0;
245 }
246 return payloadLength;
247 }
248
249 @Override
250 public Type getType()
251 {
252 return Type.from(getOpCode());
253 }
254
255 @Override
256 public int hashCode()
257 {
258 final int prime = 31;
259 int result = 1;
260 result = (prime * result) + ((data == null)?0:data.hashCode());
261 result = (prime * result) + finRsvOp;
262 result = (prime * result) + Arrays.hashCode(mask);
263 return result;
264 }
265
266 @Override
267 public boolean hasPayload()
268 {
269 return ((data != null) && (payloadLength > 0));
270 }
271
272 public abstract boolean isControlFrame();
273
274 public abstract boolean isDataFrame();
275
276 @Override
277 public boolean isFin()
278 {
279 return (byte)(finRsvOp & 0x80) != 0;
280 }
281
282 @Override
283 public boolean isLast()
284 {
285 return isFin();
286 }
287
288 @Override
289 public boolean isMasked()
290 {
291 return masked;
292 }
293
294 @Override
295 public boolean isRsv1()
296 {
297 return (byte)(finRsvOp & 0x40) != 0;
298 }
299
300 @Override
301 public boolean isRsv2()
302 {
303 return (byte)(finRsvOp & 0x20) != 0;
304 }
305
306 @Override
307 public boolean isRsv3()
308 {
309 return (byte)(finRsvOp & 0x10) != 0;
310 }
311
312
313
314
315
316
317
318
319 public int position()
320 {
321 if (data == null)
322 {
323 return -1;
324 }
325 return data.position();
326 }
327
328
329
330
331
332
333
334
335 @Override
336 public int remaining()
337 {
338 if (data == null)
339 {
340 return 0;
341 }
342 return data.remaining();
343 }
344
345 public void reset()
346 {
347 finRsvOp = (byte)0x80;
348 masked = false;
349 data = null;
350 payloadLength = 0;
351 mask = null;
352 }
353
354 public WebSocketFrame setFin(boolean fin)
355 {
356
357 this.finRsvOp = (byte)((finRsvOp & 0x7F) | (fin?0x80:0x00));
358 return this;
359 }
360
361 public Frame setMask(byte[] maskingKey)
362 {
363 this.mask = maskingKey;
364 this.masked = (mask != null);
365 return this;
366 }
367
368 public Frame setMasked(boolean mask)
369 {
370 this.masked = mask;
371 return this;
372 }
373
374 protected WebSocketFrame setOpCode(byte op)
375 {
376 this.finRsvOp = (byte)((finRsvOp & 0xF0) | (op & 0x0F));
377 return this;
378 }
379
380
381
382
383
384
385
386
387
388
389
390 public WebSocketFrame setPayload(ByteBuffer buf)
391 {
392 if (buf == null)
393 {
394 data = null;
395 return this;
396 }
397
398 data = buf.slice();
399 payloadLength = data.limit();
400 return this;
401 }
402
403 public WebSocketFrame setRsv1(boolean rsv1)
404 {
405
406 this.finRsvOp = (byte)((finRsvOp & 0xBF) | (rsv1?0x40:0x00));
407 return this;
408 }
409
410 public WebSocketFrame setRsv2(boolean rsv2)
411 {
412
413 this.finRsvOp = (byte)((finRsvOp & 0xDF) | (rsv2?0x20:0x00));
414 return this;
415 }
416
417 public WebSocketFrame setRsv3(boolean rsv3)
418 {
419
420 this.finRsvOp = (byte)((finRsvOp & 0xEF) | (rsv3?0x10:0x00));
421 return this;
422 }
423
424 @Override
425 public String toString()
426 {
427 StringBuilder b = new StringBuilder();
428 b.append(OpCode.name((byte)(finRsvOp & 0x0F)));
429 b.append('[');
430 b.append("len=").append(payloadLength);
431 b.append(",fin=").append((finRsvOp & 0x80) != 0);
432 b.append(",rsv=");
433 b.append(((finRsvOp & 0x40) != 0)?'1':'.');
434 b.append(((finRsvOp & 0x20) != 0)?'1':'.');
435 b.append(((finRsvOp & 0x10) != 0)?'1':'.');
436 b.append(",masked=").append(masked);
437 b.append(",remaining=").append(remaining());
438 b.append(",position=").append(position());
439 b.append(']');
440 return b.toString();
441 }
442 }