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.netty5.handler.codec.http.websocketx;
37
38 import io.netty5.buffer.api.Buffer;
39 import io.netty5.buffer.api.ByteCursor;
40 import io.netty5.util.ByteProcessor;
41
42
43
44
45 final class Utf8Validator implements ByteProcessor {
46 private static final int UTF8_ACCEPT = 0;
47 private static final int UTF8_REJECT = 12;
48
49 private static final byte[] TYPES = { 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, 0, 0, 0, 0, 0, 0, 0,
53 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,
54 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,
55 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,
56 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,
57 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,
58 8, 8, 8, 8, 8, 8 };
59
60 private static final byte[] STATES = { 0, 12, 24, 36, 60, 96, 84, 12, 12, 12, 48, 72, 12, 12,
61 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 12, 12, 12, 12, 12, 0, 12, 0, 12, 12,
62 12, 24, 12, 12, 12, 12, 12, 24, 12, 24, 12, 12, 12, 12, 12, 12, 12, 12, 12, 24, 12, 12,
63 12, 12, 12, 24, 12, 12, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 12, 12, 12, 12, 36,
64 12, 36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12, 12, 36, 12, 12, 12, 12,
65 12, 12, 12, 12, 12, 12 };
66
67 private int state = UTF8_ACCEPT;
68 private int codep;
69 private boolean checking;
70
71 public void check(Buffer buffer) {
72 checking = true;
73 buffer.forEachReadable(0, (index, component) -> {
74 ByteCursor cursor = component.openCursor();
75 while (cursor.readByte()) {
76 process(cursor.getByte());
77 }
78 return true;
79 });
80 }
81
82 public void finish() {
83 checking = false;
84 codep = 0;
85 if (state != UTF8_ACCEPT) {
86 state = UTF8_ACCEPT;
87 throw new CorruptedWebSocketFrameException(
88 WebSocketCloseStatus.INVALID_PAYLOAD_DATA, "bytes are not UTF-8");
89 }
90 }
91
92 @Override
93 public boolean process(byte b) {
94 byte type = TYPES[b & 0xFF];
95
96 codep = state != UTF8_ACCEPT ? b & 0x3f | codep << 6 : 0xff >> type & b;
97
98 state = STATES[state + type];
99
100 if (state == UTF8_REJECT) {
101 checking = false;
102 throw new CorruptedWebSocketFrameException(
103 WebSocketCloseStatus.INVALID_PAYLOAD_DATA, "bytes are not UTF-8");
104 }
105 return true;
106 }
107
108 public boolean isChecking() {
109 return checking;
110 }
111 }