1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.spdy.parser;
20
21 import java.nio.ByteBuffer;
22 import java.util.EnumMap;
23
24 import org.eclipse.jetty.spdy.CompressionFactory;
25 import org.eclipse.jetty.spdy.frames.ControlFrame;
26 import org.eclipse.jetty.spdy.frames.ControlFrameType;
27
28 public abstract class ControlFrameParser
29 {
30 private final EnumMap<ControlFrameType, ControlFrameBodyParser> parsers = new EnumMap<>(ControlFrameType.class);
31 private final ControlFrameBodyParser unknownParser = new UnknownControlFrameBodyParser(this);
32 private State state = State.VERSION;
33 private int cursor;
34 private short version;
35 private short type;
36 private byte flags;
37 private int length;
38 private ControlFrameBodyParser bodyParser;
39 private int bytesToSkip = 0;
40
41 public ControlFrameParser(CompressionFactory.Decompressor decompressor)
42 {
43 parsers.put(ControlFrameType.SYN_STREAM, new SynStreamBodyParser(decompressor, this));
44 parsers.put(ControlFrameType.SYN_REPLY, new SynReplyBodyParser(decompressor, this));
45 parsers.put(ControlFrameType.RST_STREAM, new RstStreamBodyParser(this));
46 parsers.put(ControlFrameType.SETTINGS, new SettingsBodyParser(this));
47 parsers.put(ControlFrameType.NOOP, new NoOpBodyParser(this));
48 parsers.put(ControlFrameType.PING, new PingBodyParser(this));
49 parsers.put(ControlFrameType.GO_AWAY, new GoAwayBodyParser(this));
50 parsers.put(ControlFrameType.HEADERS, new HeadersBodyParser(decompressor, this));
51 parsers.put(ControlFrameType.WINDOW_UPDATE, new WindowUpdateBodyParser(this));
52 parsers.put(ControlFrameType.CREDENTIAL, new CredentialBodyParser(this));
53 }
54
55 public short getVersion()
56 {
57 return version;
58 }
59
60 public byte getFlags()
61 {
62 return flags;
63 }
64
65 public int getLength()
66 {
67 return length;
68 }
69
70 public void skip(int bytesToSkip)
71 {
72 state = State.SKIP;
73 this.bytesToSkip = bytesToSkip;
74 }
75
76 public boolean parse(ByteBuffer buffer)
77 {
78 while (buffer.hasRemaining())
79 {
80 switch (state)
81 {
82 case VERSION:
83 {
84 if (buffer.remaining() >= 2)
85 {
86 version = (short)(buffer.getShort() & 0x7F_FF);
87 state = State.TYPE;
88 }
89 else
90 {
91 state = State.VERSION_BYTES;
92 cursor = 2;
93 }
94 break;
95 }
96 case VERSION_BYTES:
97 {
98 byte currByte = buffer.get();
99 --cursor;
100 version += (currByte & 0xFF) << 8 * cursor;
101 if (cursor == 0)
102 {
103 version &= 0x7F_FF;
104 state = State.TYPE;
105 }
106 break;
107 }
108 case TYPE:
109 {
110 if (buffer.remaining() >= 2)
111 {
112 type = buffer.getShort();
113 state = State.FLAGS;
114 }
115 else
116 {
117 state = State.TYPE_BYTES;
118 cursor = 2;
119 }
120 break;
121 }
122 case TYPE_BYTES:
123 {
124 byte currByte = buffer.get();
125 --cursor;
126 type += (currByte & 0xFF) << 8 * cursor;
127 if (cursor == 0)
128 state = State.FLAGS;
129 break;
130 }
131 case FLAGS:
132 {
133 flags = buffer.get();
134 cursor = 3;
135 state = State.LENGTH;
136 break;
137 }
138 case LENGTH:
139 {
140 byte currByte = buffer.get();
141 --cursor;
142 length += (currByte & 0xFF) << 8 * cursor;
143 if (cursor > 0)
144 break;
145
146 ControlFrameType controlFrameType = ControlFrameType.from(type);
147
148
149 if (controlFrameType == null)
150 bodyParser = unknownParser;
151 else
152 bodyParser = parsers.get(controlFrameType);
153
154 state = State.BODY;
155
156
157
158
159
160 }
161 case BODY:
162 {
163 if (bodyParser.parse(buffer))
164 {
165 reset();
166 return true;
167 }
168 break;
169 }
170 case SKIP:
171 {
172 int remaining = buffer.remaining();
173 if (remaining >= bytesToSkip)
174 {
175 buffer.position(buffer.position() + bytesToSkip);
176 reset();
177 return true;
178 }
179 else
180 {
181 buffer.position(buffer.limit());
182 bytesToSkip = bytesToSkip - remaining;
183 return false;
184 }
185 }
186 default:
187 {
188 throw new IllegalStateException();
189 }
190 }
191 }
192 return false;
193 }
194
195 void reset()
196 {
197 state = State.VERSION;
198 cursor = 0;
199 version = 0;
200 type = 0;
201 flags = 0;
202 length = 0;
203 bodyParser = null;
204 bytesToSkip = 0;
205 }
206
207 protected abstract void onControlFrame(ControlFrame frame);
208
209 private enum State
210 {
211 VERSION, VERSION_BYTES, TYPE, TYPE_BYTES, FLAGS, LENGTH, BODY, SKIP
212 }
213 }