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 int frameType = getFrameType();
136 if (LOG.isDebugEnabled())
137 LOG.debug("Parsed {} frame header", FrameType.from(frameType));
138
139 if (continuation)
140 {
141 if (frameType != FrameType.CONTINUATION.getType())
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.getType() &&
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 FrameType frameType = FrameType.from(type);
176 if (LOG.isDebugEnabled())
177 LOG.debug("Parsing {} frame", frameType);
178
179 BodyParser bodyParser = bodyParsers[type];
180 if (headerParser.getLength() == 0)
181 {
182 bodyParser.emptyBody(buffer);
183 }
184 else
185 {
186 if (!bodyParser.parse(buffer))
187 return false;
188 }
189 if (LOG.isDebugEnabled())
190 LOG.debug("Parsed {} frame", frameType);
191 reset();
192 return true;
193 }
194
195 protected int getFrameType()
196 {
197 return headerParser.getFrameType();
198 }
199
200 protected boolean hasFlag(int bit)
201 {
202 return headerParser.hasFlag(bit);
203 }
204
205 protected void notifyConnectionFailure(int error, String reason)
206 {
207 try
208 {
209 listener.onConnectionFailure(error, reason);
210 }
211 catch (Throwable x)
212 {
213 LOG.info("Failure while notifying listener " + listener, x);
214 }
215 }
216
217 public interface Listener
218 {
219 public void onData(DataFrame frame);
220
221 public void onHeaders(HeadersFrame frame);
222
223 public void onPriority(PriorityFrame frame);
224
225 public void onReset(ResetFrame frame);
226
227 public void onSettings(SettingsFrame frame);
228
229 public void onPushPromise(PushPromiseFrame frame);
230
231 public void onPing(PingFrame frame);
232
233 public void onGoAway(GoAwayFrame frame);
234
235 public void onWindowUpdate(WindowUpdateFrame frame);
236
237 public void onConnectionFailure(int error, String reason);
238
239 public static class Adapter implements Listener
240 {
241 @Override
242 public void onData(DataFrame frame)
243 {
244 }
245
246 @Override
247 public void onHeaders(HeadersFrame frame)
248 {
249 }
250
251 @Override
252 public void onPriority(PriorityFrame frame)
253 {
254 }
255
256 @Override
257 public void onReset(ResetFrame frame)
258 {
259 }
260
261 @Override
262 public void onSettings(SettingsFrame frame)
263 {
264 }
265
266 @Override
267 public void onPushPromise(PushPromiseFrame frame)
268 {
269 }
270
271 @Override
272 public void onPing(PingFrame frame)
273 {
274 }
275
276 @Override
277 public void onGoAway(GoAwayFrame frame)
278 {
279 }
280
281 @Override
282 public void onWindowUpdate(WindowUpdateFrame frame)
283 {
284 }
285
286 @Override
287 public void onConnectionFailure(int error, String reason)
288 {
289 LOG.warn("Connection failure: {}/{}", error, reason);
290 }
291 }
292 }
293
294 private enum State
295 {
296 HEADER, BODY
297 }
298 }