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