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