1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 package io.netty.handler.codec.http.websocketx;
37
38 import io.netty.buffer.ByteBuf;
39 import io.netty.util.ByteProcessor;
40
41
42
43
44 final class Utf8Validator implements ByteProcessor {
45 private static final int UTF8_ACCEPT = 0;
46 private static final int UTF8_REJECT = 12;
47
48 private static final byte[] TYPES = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
49 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
50 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
51 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
52 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1,
53 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 7, 7, 7, 7,
54 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8,
55 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
56 2, 2, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 11, 6, 6, 6, 5, 8, 8, 8, 8, 8,
57 8, 8, 8, 8, 8, 8 };
58
59 private static final byte[] STATES = { 0, 12, 24, 36, 60, 96, 84, 12, 12, 12, 48, 72, 12, 12,
60 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 12, 12, 12, 12, 12, 0, 12, 0, 12, 12,
61 12, 24, 12, 12, 12, 12, 12, 24, 12, 24, 12, 12, 12, 12, 12, 12, 12, 12, 12, 24, 12, 12,
62 12, 12, 12, 24, 12, 12, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 12, 12, 12, 12, 36,
63 12, 36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12, 12, 36, 12, 12, 12, 12,
64 12, 12, 12, 12, 12, 12 };
65
66 @SuppressWarnings("RedundantFieldInitialization")
67 private int state = UTF8_ACCEPT;
68 private int codep;
69 private boolean checking;
70
71 public void check(ByteBuf buffer) {
72 checking = true;
73 buffer.forEachByte(this);
74 }
75
76 void check(ByteBuf buffer, int index, int length) {
77 checking = true;
78 buffer.forEachByte(index, length, this);
79 }
80
81 public void finish() {
82 checking = false;
83 codep = 0;
84 if (state != UTF8_ACCEPT) {
85 state = UTF8_ACCEPT;
86 throw new CorruptedWebSocketFrameException(
87 WebSocketCloseStatus.INVALID_PAYLOAD_DATA, "bytes are not UTF-8");
88 }
89 }
90
91 @Override
92 public boolean process(byte b) throws Exception {
93 byte type = TYPES[b & 0xFF];
94
95 codep = state != UTF8_ACCEPT ? b & 0x3f | codep << 6 : 0xff >> type & b;
96
97 state = STATES[state + type];
98
99 if (state == UTF8_REJECT) {
100 checking = false;
101 throw new CorruptedWebSocketFrameException(
102 WebSocketCloseStatus.INVALID_PAYLOAD_DATA, "bytes are not UTF-8");
103 }
104 return true;
105 }
106
107 public boolean isChecking() {
108 return checking;
109 }
110 }