1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.http2.parser;
20
21 import java.nio.ByteBuffer;
22
23 import org.eclipse.jetty.http2.ErrorCode;
24 import org.eclipse.jetty.http2.Flags;
25 import org.eclipse.jetty.http2.frames.DataFrame;
26 import org.eclipse.jetty.http2.frames.FrameType;
27 import org.eclipse.jetty.http2.frames.GoAwayFrame;
28 import org.eclipse.jetty.http2.frames.HeadersFrame;
29 import org.eclipse.jetty.http2.frames.PingFrame;
30 import org.eclipse.jetty.http2.frames.PriorityFrame;
31 import org.eclipse.jetty.http2.frames.PushPromiseFrame;
32 import org.eclipse.jetty.http2.frames.ResetFrame;
33 import org.eclipse.jetty.http2.frames.SettingsFrame;
34 import org.eclipse.jetty.http2.frames.WindowUpdateFrame;
35 import org.eclipse.jetty.http2.hpack.HpackDecoder;
36 import org.eclipse.jetty.io.ByteBufferPool;
37 import org.eclipse.jetty.util.BufferUtil;
38 import org.eclipse.jetty.util.log.Log;
39 import org.eclipse.jetty.util.log.Logger;
40
41
42
43
44
45
46 public class Parser
47 {
48 private static final Logger LOG = Log.getLogger(Parser.class);
49
50 private final Listener listener;
51 private final HeaderParser headerParser;
52 private final BodyParser[] bodyParsers;
53 private boolean continuation;
54 private State state = State.HEADER;
55
56 public Parser(ByteBufferPool byteBufferPool, Listener listener, int maxDynamicTableSize, int maxHeaderSize)
57 {
58 this.listener = listener;
59 this.headerParser = new HeaderParser();
60 this.bodyParsers = new BodyParser[FrameType.values().length];
61
62 HeaderBlockParser headerBlockParser = new HeaderBlockParser(byteBufferPool, new HpackDecoder(maxDynamicTableSize, maxHeaderSize));
63 HeaderBlockFragments headerBlockFragments = new HeaderBlockFragments();
64
65 bodyParsers[FrameType.DATA.getType()] = new DataBodyParser(headerParser, listener);
66 bodyParsers[FrameType.HEADERS.getType()] = new HeadersBodyParser(headerParser, listener, headerBlockParser, headerBlockFragments);
67 bodyParsers[FrameType.PRIORITY.getType()] = new PriorityBodyParser(headerParser, listener);
68 bodyParsers[FrameType.RST_STREAM.getType()] = new ResetBodyParser(headerParser, listener);
69 bodyParsers[FrameType.SETTINGS.getType()] = new SettingsBodyParser(headerParser, listener);
70 bodyParsers[FrameType.PUSH_PROMISE.getType()] = new PushPromiseBodyParser(headerParser, listener, headerBlockParser);
71 bodyParsers[FrameType.PING.getType()] = new PingBodyParser(headerParser, listener);
72 bodyParsers[FrameType.GO_AWAY.getType()] = new GoAwayBodyParser(headerParser, listener);
73 bodyParsers[FrameType.WINDOW_UPDATE.getType()] = new WindowUpdateBodyParser(headerParser, listener);
74 bodyParsers[FrameType.CONTINUATION.getType()] = new ContinuationBodyParser(headerParser, listener, headerBlockParser, headerBlockFragments);
75 }
76
77 private void reset()
78 {
79 headerParser.reset();
80 state = State.HEADER;
81 }
82
83
84
85
86
87
88
89
90
91
92
93
94 public void parse(ByteBuffer buffer)
95 {
96 try
97 {
98 while (true)
99 {
100 switch (state)
101 {
102 case HEADER:
103 {
104 if (!parseHeader(buffer))
105 return;
106 break;
107 }
108 case BODY:
109 {
110 if (!parseBody(buffer))
111 return;
112 break;
113 }
114 default:
115 {
116 throw new IllegalStateException();
117 }
118 }
119 }
120 }
121 catch (Throwable x)
122 {
123 if (LOG.isDebugEnabled())
124 LOG.debug(x);
125 BufferUtil.clear(buffer);
126 notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "parser_error");
127 }
128 }
129
130 protected boolean parseHeader(ByteBuffer buffer)
131 {
132 if (!headerParser.parse(buffer))
133 return false;
134
135 FrameType frameType = FrameType.from(getFrameType());
136 if (LOG.isDebugEnabled())
137 LOG.debug("Parsed {} frame header from {}", frameType, buffer);
138
139 if (continuation)
140 {
141 if (frameType != FrameType.CONTINUATION)
142 {
143
144 BufferUtil.clear(buffer);
145 notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "continuation_frame_expected");
146 return false;
147 }
148 if (headerParser.hasFlag(Flags.END_HEADERS))
149 {
150 continuation = false;
151 }
152 }
153 else
154 {
155 if (frameType == FrameType.HEADERS &&
156 !headerParser.hasFlag(Flags.END_HEADERS))
157 {
158 continuation = true;
159 }
160 }
161 state = State.BODY;
162 return true;
163 }
164
165 protected boolean parseBody(ByteBuffer buffer)
166 {
167 int type = getFrameType();
168 if (type < 0 || type >= bodyParsers.length)
169 {
170 BufferUtil.clear(buffer);
171 notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "unknown_frame_type_" + type);
172 return false;
173 }
174
175 BodyParser bodyParser = bodyParsers[type];
176 if (headerParser.getLength() == 0)
177 {
178 bodyParser.emptyBody(buffer);
179 }
180 else
181 {
182 if (!bodyParser.parse(buffer))
183 return false;
184 }
185 if (LOG.isDebugEnabled())
186 LOG.debug("Parsed {} frame body from {}", FrameType.from(type), buffer);
187 reset();
188 return true;
189 }
190
191 protected int getFrameType()
192 {
193 return headerParser.getFrameType();
194 }
195
196 protected boolean hasFlag(int bit)
197 {
198 return headerParser.hasFlag(bit);
199 }
200
201 protected void notifyConnectionFailure(int error, String reason)
202 {
203 try
204 {
205 listener.onConnectionFailure(error, reason);
206 }
207 catch (Throwable x)
208 {
209 LOG.info("Failure while notifying listener " + listener, x);
210 }
211 }
212
213 public interface Listener
214 {
215 public void onData(DataFrame frame);
216
217 public void onHeaders(HeadersFrame frame);
218
219 public void onPriority(PriorityFrame frame);
220
221 public void onReset(ResetFrame frame);
222
223 public void onSettings(SettingsFrame frame);
224
225 public void onPushPromise(PushPromiseFrame frame);
226
227 public void onPing(PingFrame frame);
228
229 public void onGoAway(GoAwayFrame frame);
230
231 public void onWindowUpdate(WindowUpdateFrame frame);
232
233 public void onConnectionFailure(int error, String reason);
234
235 public static class Adapter implements Listener
236 {
237 @Override
238 public void onData(DataFrame frame)
239 {
240 }
241
242 @Override
243 public void onHeaders(HeadersFrame frame)
244 {
245 }
246
247 @Override
248 public void onPriority(PriorityFrame frame)
249 {
250 }
251
252 @Override
253 public void onReset(ResetFrame frame)
254 {
255 }
256
257 @Override
258 public void onSettings(SettingsFrame frame)
259 {
260 }
261
262 @Override
263 public void onPushPromise(PushPromiseFrame frame)
264 {
265 }
266
267 @Override
268 public void onPing(PingFrame frame)
269 {
270 }
271
272 @Override
273 public void onGoAway(GoAwayFrame frame)
274 {
275 }
276
277 @Override
278 public void onWindowUpdate(WindowUpdateFrame frame)
279 {
280 }
281
282 @Override
283 public void onConnectionFailure(int error, String reason)
284 {
285 LOG.warn("Connection failure: {}/{}", error, reason);
286 }
287 }
288 }
289
290 private enum State
291 {
292 HEADER, BODY
293 }
294 }