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