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.MessageTooLargeException;
29 import org.eclipse.jetty.websocket.api.ProtocolException;
30 import org.eclipse.jetty.websocket.api.WebSocketBehavior;
31 import org.eclipse.jetty.websocket.api.WebSocketException;
32 import org.eclipse.jetty.websocket.api.WebSocketPolicy;
33 import org.eclipse.jetty.websocket.api.extensions.Extension;
34 import org.eclipse.jetty.websocket.api.extensions.Frame;
35 import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
36 import org.eclipse.jetty.websocket.common.io.payload.CloseReasonValidator;
37 import org.eclipse.jetty.websocket.common.io.payload.DeMaskProcessor;
38 import org.eclipse.jetty.websocket.common.io.payload.NoOpValidator;
39 import org.eclipse.jetty.websocket.common.io.payload.PayloadProcessor;
40 import org.eclipse.jetty.websocket.common.io.payload.UTF8Validator;
41
42
43
44
45 public class Parser
46 {
47 private enum State
48 {
49 START,
50 FINOP,
51 PAYLOAD_LEN,
52 PAYLOAD_LEN_BYTES,
53 MASK,
54 MASK_BYTES,
55 PAYLOAD
56 }
57
58 private static final Logger LOG = Log.getLogger(Parser.class);
59 private final WebSocketPolicy policy;
60 private final ByteBufferPool bufferPool;
61
62
63 private State state = State.START;
64 private int cursor = 0;
65
66 private WebSocketFrame frame;
67 private Frame priorDataFrame;
68 private byte lastDataOpcode;
69
70 private ByteBuffer payload;
71 private int payloadLength;
72 private PayloadProcessor maskProcessor = new DeMaskProcessor();
73 private PayloadProcessor strictnessProcessor;
74
75
76 private boolean rsv1InUse = false;
77
78 private boolean rsv2InUse = false;
79
80 private boolean rsv3InUse = false;
81
82 private boolean isTextFrameValidated = true;
83
84 private IncomingFrames incomingFramesHandler;
85
86 public Parser(WebSocketPolicy wspolicy, ByteBufferPool bufferPool)
87 {
88 this.bufferPool = bufferPool;
89 this.policy = wspolicy;
90 }
91
92 private void assertSanePayloadLength(long len)
93 {
94 LOG.debug("Payload Length: " + len);
95
96 if (len > Integer.MAX_VALUE)
97 {
98
99 throw new MessageTooLargeException("[int-sane!] cannot handle payload lengths larger than " + Integer.MAX_VALUE);
100 }
101 policy.assertValidMessageSize((int)len);
102
103 switch (frame.getOpCode())
104 {
105 case OpCode.CLOSE:
106 if (len == 1)
107 {
108 throw new ProtocolException("Invalid close frame payload length, [" + payloadLength + "]");
109 }
110
111 case OpCode.PING:
112 case OpCode.PONG:
113 if (len > WebSocketFrame.MAX_CONTROL_PAYLOAD)
114 {
115 throw new ProtocolException("Invalid control frame payload length, [" + payloadLength + "] cannot exceed ["
116 + WebSocketFrame.MAX_CONTROL_PAYLOAD + "]");
117 }
118 break;
119 }
120 }
121
122 public void configureFromExtensions(List<? extends Extension> exts)
123 {
124
125 this.rsv1InUse = false;
126 this.rsv2InUse = false;
127 this.rsv3InUse = false;
128 this.isTextFrameValidated = true;
129
130
131 for (Extension ext : exts)
132 {
133 if (ext.isRsv1User())
134 {
135 this.rsv1InUse = true;
136 }
137 if (ext.isRsv2User())
138 {
139 this.rsv2InUse = true;
140 }
141 if (ext.isRsv3User())
142 {
143 this.rsv3InUse = true;
144 }
145 if (ext.isTextDataDecoder())
146 {
147 this.isTextFrameValidated = false;
148 }
149 }
150 }
151
152 public IncomingFrames getIncomingFramesHandler()
153 {
154 return incomingFramesHandler;
155 }
156
157 public WebSocketPolicy getPolicy()
158 {
159 return policy;
160 }
161
162 public boolean isRsv1InUse()
163 {
164 return rsv1InUse;
165 }
166
167 public boolean isRsv2InUse()
168 {
169 return rsv2InUse;
170 }
171
172 public boolean isRsv3InUse()
173 {
174 return rsv3InUse;
175 }
176
177 protected void notifyFrame(final Frame f)
178 {
179 if (LOG.isDebugEnabled())
180 {
181 LOG.debug("{} Notify {}",policy.getBehavior(),incomingFramesHandler);
182 }
183
184 if (policy.getBehavior() == WebSocketBehavior.SERVER)
185 {
186
187
188 if (f.isMasked() == false)
189 {
190 throw new ProtocolException("Client frames MUST be masked (RFC-6455)");
191 }
192 }
193
194 if (incomingFramesHandler == null)
195 {
196 return;
197 }
198 try
199 {
200 incomingFramesHandler.incomingFrame(f);
201 }
202 catch (WebSocketException e)
203 {
204 notifyWebSocketException(e);
205 }
206 catch (Throwable t)
207 {
208 LOG.warn(t);
209 notifyWebSocketException(new WebSocketException(t));
210 }
211 }
212
213 protected void notifyWebSocketException(WebSocketException e)
214 {
215 LOG.warn(e);
216 if (incomingFramesHandler == null)
217 {
218 return;
219 }
220 incomingFramesHandler.incomingError(e);
221 }
222
223 public synchronized void parse(ByteBuffer buffer)
224 {
225 if (buffer.remaining() <= 0)
226 {
227 return;
228 }
229 try
230 {
231
232
233
234 while (parseFrame(buffer))
235 {
236 LOG.debug("{} Parsed Frame: {}",policy.getBehavior(),frame);
237 notifyFrame(frame);
238 if (frame.isDataFrame() && frame.isFin())
239 {
240 priorDataFrame = null;
241 }
242 else
243 {
244 priorDataFrame = frame;
245 }
246 }
247 }
248 catch (WebSocketException e)
249 {
250 buffer.position(buffer.limit());
251 this.payload = null;
252 notifyWebSocketException(e);
253 }
254 catch (Throwable t)
255 {
256 buffer.position(buffer.limit());
257 this.payload = null;
258 notifyWebSocketException(new WebSocketException(t));
259 }
260 }
261
262
263
264
265
266
267
268
269
270
271
272
273 private boolean parseFrame(ByteBuffer buffer)
274 {
275 if (buffer.remaining() <= 0)
276 {
277 return false;
278 }
279
280 LOG.debug("{} Parsing {} bytes",policy.getBehavior(),buffer.remaining());
281 while (buffer.hasRemaining())
282 {
283 switch (state)
284 {
285 case START:
286 {
287 if ((frame != null) && (frame.isFin()))
288 {
289 frame.reset();
290 }
291
292 state = State.FINOP;
293 break;
294 }
295 case FINOP:
296 {
297
298 byte b = buffer.get();
299 boolean fin = ((b & 0x80) != 0);
300 boolean rsv1 = ((b & 0x40) != 0);
301 boolean rsv2 = ((b & 0x20) != 0);
302 boolean rsv3 = ((b & 0x10) != 0);
303 byte opc = (byte)(b & 0x0F);
304 byte opcode = opc;
305
306 if (!OpCode.isKnown(opcode))
307 {
308 throw new ProtocolException("Unknown opcode: " + opc);
309 }
310
311 if (LOG.isDebugEnabled())
312 {
313 LOG.debug("OpCode {}, fin={} rsv={}{}{}",OpCode.name(opcode),fin,(rsv1?'1':'.'),(rsv2?'1':'.'),(rsv3?'1':'.'));
314 }
315
316
317
318
319
320
321
322 if (!rsv1InUse && rsv1)
323 {
324 throw new ProtocolException("RSV1 not allowed to be set");
325 }
326
327 if (!rsv2InUse && rsv2)
328 {
329 throw new ProtocolException("RSV2 not allowed to be set");
330 }
331
332 if (!rsv3InUse && rsv3)
333 {
334 throw new ProtocolException("RSV3 not allowed to be set");
335 }
336
337 boolean isContinuation = false;
338
339 switch (opcode)
340 {
341 case OpCode.TEXT:
342 if (isTextFrameValidated)
343 {
344 strictnessProcessor = new UTF8Validator();
345 }
346 else
347 {
348 strictnessProcessor = NoOpValidator.INSTANCE;
349 }
350 break;
351 case OpCode.CLOSE:
352 strictnessProcessor = new CloseReasonValidator();
353 break;
354 default:
355 strictnessProcessor = NoOpValidator.INSTANCE;
356 break;
357 }
358
359 if (OpCode.isControlFrame(opcode))
360 {
361
362 if (!fin)
363 {
364 throw new ProtocolException("Fragmented Control Frame [" + OpCode.name(opcode) + "]");
365 }
366 }
367 else if (opcode == OpCode.CONTINUATION)
368 {
369 isContinuation = true;
370
371 if (priorDataFrame == null)
372 {
373 throw new ProtocolException("CONTINUATION frame without prior !FIN");
374 }
375
376 opcode = lastDataOpcode;
377 }
378 else if (OpCode.isDataFrame(opcode))
379 {
380
381 if ((priorDataFrame != null) && (!priorDataFrame.isFin()))
382 {
383 throw new ProtocolException("Unexpected " + OpCode.name(opcode) + " frame, was expecting CONTINUATION");
384 }
385 }
386
387
388 frame = new WebSocketFrame(opcode);
389 frame.setFin(fin);
390 frame.setRsv1(rsv1);
391 frame.setRsv2(rsv2);
392 frame.setRsv3(rsv3);
393 frame.setContinuation(isContinuation);
394
395 if (frame.isDataFrame())
396 {
397 lastDataOpcode = opcode;
398 }
399
400 state = State.PAYLOAD_LEN;
401 break;
402 }
403 case PAYLOAD_LEN:
404 {
405 byte b = buffer.get();
406 frame.setMasked((b & 0x80) != 0);
407 payloadLength = (byte)(0x7F & b);
408
409 if (payloadLength == 127)
410 {
411
412 payloadLength = 0;
413 state = State.PAYLOAD_LEN_BYTES;
414 cursor = 8;
415 break;
416 }
417 else if (payloadLength == 126)
418 {
419
420 payloadLength = 0;
421 state = State.PAYLOAD_LEN_BYTES;
422 cursor = 2;
423 break;
424 }
425
426 assertSanePayloadLength(payloadLength);
427 if (frame.isMasked())
428 {
429 state = State.MASK;
430 }
431 else
432 {
433
434 if (payloadLength == 0)
435 {
436 state = State.START;
437 return true;
438 }
439
440 maskProcessor.reset(frame);
441 state = State.PAYLOAD;
442 }
443
444 break;
445 }
446 case PAYLOAD_LEN_BYTES:
447 {
448 byte b = buffer.get();
449 --cursor;
450 payloadLength |= (b & 0xFF) << (8 * cursor);
451 if (cursor == 0)
452 {
453 assertSanePayloadLength(payloadLength);
454 if (frame.isMasked())
455 {
456 state = State.MASK;
457 }
458 else
459 {
460
461 if (payloadLength == 0)
462 {
463 state = State.START;
464 return true;
465 }
466
467 maskProcessor.reset(frame);
468 state = State.PAYLOAD;
469 }
470 }
471 break;
472 }
473 case MASK:
474 {
475 byte m[] = new byte[4];
476 frame.setMask(m);
477 if (buffer.remaining() >= 4)
478 {
479 buffer.get(m,0,4);
480
481 if (payloadLength == 0)
482 {
483 state = State.START;
484 return true;
485 }
486
487 maskProcessor.reset(frame);
488 state = State.PAYLOAD;
489 }
490 else
491 {
492 state = State.MASK_BYTES;
493 cursor = 4;
494 }
495 break;
496 }
497 case MASK_BYTES:
498 {
499 byte b = buffer.get();
500 frame.getMask()[4 - cursor] = b;
501 --cursor;
502 if (cursor == 0)
503 {
504
505 if (payloadLength == 0)
506 {
507 state = State.START;
508 return true;
509 }
510
511 maskProcessor.reset(frame);
512 state = State.PAYLOAD;
513 }
514 break;
515 }
516 case PAYLOAD:
517 {
518 if (parsePayload(buffer))
519 {
520
521 if (frame.getOpCode() == OpCode.CLOSE)
522 {
523 new CloseInfo(frame);
524 }
525 state = State.START;
526
527 return true;
528 }
529 break;
530 }
531 }
532 }
533
534 return false;
535 }
536
537
538
539
540
541
542
543
544 private boolean parsePayload(ByteBuffer buffer)
545 {
546 if (payloadLength == 0)
547 {
548 return true;
549 }
550
551 while (buffer.hasRemaining())
552 {
553 if (payload == null)
554 {
555 frame.assertValid();
556 payload = bufferPool.acquire(payloadLength,false);
557 BufferUtil.clearToFill(payload);
558 }
559
560
561
562
563 ByteBuffer window = buffer.slice();
564 int bytesExpected = payloadLength - payload.position();
565 int bytesAvailable = buffer.remaining();
566 int windowBytes = Math.min(bytesAvailable,bytesExpected);
567 window.limit(window.position() + windowBytes);
568
569 if (LOG.isDebugEnabled())
570 {
571 LOG.debug("Window: {}",BufferUtil.toDetailString(window));
572 }
573
574 maskProcessor.process(window);
575 strictnessProcessor.process(window);
576 int len = BufferUtil.put(window,payload);
577
578 buffer.position(buffer.position() + len);
579
580 if (payload.position() >= payloadLength)
581 {
582 BufferUtil.flipToFlush(payload,0);
583 frame.setPayload(payload);
584 this.payload = null;
585 return true;
586 }
587 }
588 return false;
589 }
590
591 public void setIncomingFramesHandler(IncomingFrames incoming)
592 {
593 this.incomingFramesHandler = incoming;
594 }
595
596 @Override
597 public String toString()
598 {
599 StringBuilder builder = new StringBuilder();
600 builder.append("Parser[");
601 if (incomingFramesHandler == null)
602 {
603 builder.append("NO_HANDLER");
604 }
605 else
606 {
607 builder.append(incomingFramesHandler.getClass().getSimpleName());
608 }
609 builder.append(",s=");
610 builder.append(state);
611 builder.append(",c=");
612 builder.append(cursor);
613 builder.append(",len=");
614 builder.append(payloadLength);
615 builder.append(",f=");
616 builder.append(frame);
617 builder.append("]");
618 return builder.toString();
619 }
620 }