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 parser;
39
40 public ControlFrameParser(CompressionFactory.Decompressor decompressor)
41 {
42 parsers.put(ControlFrameType.SYN_STREAM, new SynStreamBodyParser(decompressor, this));
43 parsers.put(ControlFrameType.SYN_REPLY, new SynReplyBodyParser(decompressor, this));
44 parsers.put(ControlFrameType.RST_STREAM, new RstStreamBodyParser(this));
45 parsers.put(ControlFrameType.SETTINGS, new SettingsBodyParser(this));
46 parsers.put(ControlFrameType.NOOP, new NoOpBodyParser(this));
47 parsers.put(ControlFrameType.PING, new PingBodyParser(this));
48 parsers.put(ControlFrameType.GO_AWAY, new GoAwayBodyParser(this));
49 parsers.put(ControlFrameType.HEADERS, new HeadersBodyParser(decompressor, this));
50 parsers.put(ControlFrameType.WINDOW_UPDATE, new WindowUpdateBodyParser(this));
51 parsers.put(ControlFrameType.CREDENTIAL, new CredentialBodyParser(this));
52 }
53
54 public short getVersion()
55 {
56 return version;
57 }
58
59 public byte getFlags()
60 {
61 return flags;
62 }
63
64 public int getLength()
65 {
66 return length;
67 }
68
69 public boolean parse(ByteBuffer buffer)
70 {
71 while (buffer.hasRemaining())
72 {
73 switch (state)
74 {
75 case VERSION:
76 {
77 if (buffer.remaining() >= 2)
78 {
79 version = (short)(buffer.getShort() & 0x7F_FF);
80 state = State.TYPE;
81 }
82 else
83 {
84 state = State.VERSION_BYTES;
85 cursor = 2;
86 }
87 break;
88 }
89 case VERSION_BYTES:
90 {
91 byte currByte = buffer.get();
92 --cursor;
93 version += (currByte & 0xFF) << 8 * cursor;
94 if (cursor == 0)
95 {
96 version &= 0x7F_FF;
97 state = State.TYPE;
98 }
99 break;
100 }
101 case TYPE:
102 {
103 if (buffer.remaining() >= 2)
104 {
105 type = buffer.getShort();
106 state = State.FLAGS;
107 }
108 else
109 {
110 state = State.TYPE_BYTES;
111 cursor = 2;
112 }
113 break;
114 }
115 case TYPE_BYTES:
116 {
117 byte currByte = buffer.get();
118 --cursor;
119 type += (currByte & 0xFF) << 8 * cursor;
120 if (cursor == 0)
121 state = State.FLAGS;
122 break;
123 }
124 case FLAGS:
125 {
126 flags = buffer.get();
127 cursor = 3;
128 state = State.LENGTH;
129 break;
130 }
131 case LENGTH:
132 {
133 byte currByte = buffer.get();
134 --cursor;
135 length += (currByte & 0xFF) << 8 * cursor;
136 if (cursor > 0)
137 break;
138
139 ControlFrameType controlFrameType = ControlFrameType.from(type);
140
141
142 if (controlFrameType == null)
143 parser = unknownParser;
144 else
145 parser = parsers.get(controlFrameType);
146
147 state = State.BODY;
148
149
150
151
152
153 }
154 case BODY:
155 {
156 if (parser.parse(buffer))
157 {
158 reset();
159 return true;
160 }
161 break;
162 }
163 default:
164 {
165 throw new IllegalStateException();
166 }
167 }
168 }
169 return false;
170 }
171
172 private void reset()
173 {
174 state = State.VERSION;
175 cursor = 0;
176 version = 0;
177 type = 0;
178 flags = 0;
179 length = 0;
180 parser = null;
181 }
182
183 protected abstract void onControlFrame(ControlFrame frame);
184
185 private enum State
186 {
187 VERSION, VERSION_BYTES, TYPE, TYPE_BYTES, FLAGS, LENGTH, BODY
188 }
189 }