1 module hunt.http.codec.http.decode.Parser;
2 
3 import hunt.http.codec.http.frame;
4 import hunt.http.codec.http.hpack.HpackDecoder;
5 
6 import hunt.http.codec.http.decode.BodyParser;
7 import hunt.http.codec.http.decode.ContinuationBodyParser;
8 import hunt.http.codec.http.decode.DataBodyParser;
9 import hunt.http.codec.http.decode.HeaderParser;
10 import hunt.http.codec.http.decode.HeaderBlockParser;
11 import hunt.http.codec.http.decode.HeaderBlockFragments;
12 import hunt.http.codec.http.decode.HeadersBodyParser;
13 import hunt.http.codec.http.decode.GoAwayBodyParser;
14 import hunt.http.codec.http.decode.PingBodyParser;
15 import hunt.http.codec.http.decode.PriorityBodyParser;
16 import hunt.http.codec.http.decode.PushPromiseBodyParser;
17 import hunt.http.codec.http.decode.ResetBodyParser;
18 import hunt.http.codec.http.decode.SettingsBodyParser;
19 import hunt.http.codec.http.decode.WindowUpdateBodyParser;
20 
21 import hunt.io.BufferUtils;
22 import hunt.io.ByteBuffer;
23 
24 import hunt.Exceptions;
25 
26 import hunt.logging;
27 
28 import std.conv;
29 import std.stdio;
30 
31 
32 
33 /**
34  * <p>
35  * The HTTP/2 protocol parser.
36  * </p>
37  * <p>
38  * This parser makes use of the {@link HeaderParser} and of {@link BodyParser}s
39  * to parse HTTP/2 frames.
40  * </p>
41  */
42 class Parser {
43     
44 
45     private Listener listener;
46     private HeaderParser headerParser;
47     private BodyParser[FrameType] bodyParsers;
48     private bool continuation;
49     private State state = State.HEADER;
50 
51     this(Listener listener, int maxDynamicTableSize, int maxHeaderSize) {
52         this.listener = listener;
53         this.headerParser = new HeaderParser();
54         // this.bodyParsers = new BodyParser[FrameTypeSize];
55 
56         HeaderBlockParser headerBlockParser = new HeaderBlockParser(new HpackDecoder(maxDynamicTableSize, maxHeaderSize));
57         HeaderBlockFragments headerBlockFragments = new HeaderBlockFragments();
58 
59         bodyParsers[FrameType.DATA] = new DataBodyParser(headerParser, listener);
60         bodyParsers[FrameType.HEADERS] = new HeadersBodyParser(headerParser, listener, headerBlockParser, headerBlockFragments);
61         bodyParsers[FrameType.PRIORITY] = new PriorityBodyParser(headerParser, listener);
62         bodyParsers[FrameType.RST_STREAM] = new ResetBodyParser(headerParser, listener);
63         bodyParsers[FrameType.SETTINGS] = new SettingsBodyParser(headerParser, listener);
64         bodyParsers[FrameType.PUSH_PROMISE] = new PushPromiseBodyParser(headerParser, listener, headerBlockParser);
65         bodyParsers[FrameType.PING] = new PingBodyParser(headerParser, listener);
66         bodyParsers[FrameType.GO_AWAY] = new GoAwayBodyParser(headerParser, listener);
67         bodyParsers[FrameType.WINDOW_UPDATE] = new WindowUpdateBodyParser(headerParser, listener);
68         bodyParsers[FrameType.CONTINUATION] = new ContinuationBodyParser(headerParser, listener, headerBlockParser, headerBlockFragments);
69     }
70 
71     private void reset() {
72         headerParser.reset();
73         state = State.HEADER;
74     }
75 
76     /**
77      * <p>
78      * Parses the given {@code buffer} bytes and emit events to a
79      * {@link Listener}.
80      * </p>
81      * <p>
82      * When this method returns, the buffer may not be fully consumed, so
83      * invocations to this method should be wrapped in a loop:
84      * </p>
85      * <p>
86      * <pre>
87      * while (buffer.hasRemaining())
88      * 	parser.parse(buffer);
89      * </pre>
90      *
91      * @param buffer the buffer to parse
92      */
93     void parse(ByteBuffer buffer) {
94         try {
95             while (true) {
96                 switch (state) {
97                     case State.HEADER: {
98                         if (parseHeader(buffer)) {
99                             break;
100                         } else {
101                             return;
102                         }
103                     }
104                     case State.BODY: {
105                         if (parseBody(buffer)) {
106                             break;
107                         } else {
108                             return;
109                         }
110                     }
111                     default: {
112                         throw new IllegalStateException("");
113                     }
114                 }
115             }
116         } catch (Exception x) {
117             errorf("HTTP2 parsing error", x);
118             BufferUtils.clear(buffer);
119             notifyConnectionFailure(cast(int)ErrorCode.PROTOCOL_ERROR, "parser_error");
120         }
121     }
122 
123     protected bool parseHeader(ByteBuffer buffer) {
124         if (headerParser.parse(buffer)) {
125             int frameType = getFrameType();
126             version(HUNT_HTTP_DEBUG) {
127                 tracef("Parsed %s frame header", cast(FrameType)(frameType));
128             }
129 
130             if (continuation) {
131                 if (frameType != FrameType.CONTINUATION) {
132                     // SPEC: CONTINUATION frames must be consecutive.
133                     BufferUtils.clear(buffer);
134                     notifyConnectionFailure(cast(int)ErrorCode.PROTOCOL_ERROR, "continuation_frame_expected");
135                     return false;
136                 }
137                 if (headerParser.hasFlag(Flags.END_HEADERS)) {
138                     continuation = false;
139                 }
140             } else {
141                 if (frameType == FrameType.HEADERS && !headerParser.hasFlag(Flags.END_HEADERS)) {
142                     continuation = true;
143                 }
144             }
145             state = State.BODY;
146             return true;
147         } else {
148             return false;
149         }
150     }
151 
152     protected bool parseBody(ByteBuffer buffer) {
153         int type = getFrameType();
154         if (type < 0 || type >= bodyParsers.length) {
155             BufferUtils.clear(buffer);
156             notifyConnectionFailure(cast(int)ErrorCode.PROTOCOL_ERROR, "unknown_frame_type_" ~ type.to!string);
157             return false;
158         }
159 
160         FrameType frameType = cast(FrameType)(type);
161         version(HUNT_HTTP_DEBUG) {
162             tracef("Parsing %s frame", frameType);
163         }
164         BodyParser bodyParser = bodyParsers[frameType];
165         if (headerParser.getLength() == 0) {
166             bodyParser.emptyBody(buffer);
167             reset();
168             version(HUNT_HTTP_DEBUG) {
169                 tracef("Parsed %s frame, empty body", frameType);
170             }
171             return true;
172         } else {
173             if (bodyParser.parse(buffer)) {
174                 reset();
175                 version(HUNT_HTTP_DEBUG) {
176                     tracef("Parsed %s frame", frameType);
177                 }
178                 return true;
179             } else {
180                 return false;
181             }
182         }
183     }
184 
185     protected int getFrameType() {
186         return headerParser.getFrameType();
187     }
188 
189     protected bool hasFlag(int bit) {
190         return headerParser.hasFlag(bit);
191     }
192 
193     protected void notifyConnectionFailure(int error, string reason) {
194         try {
195             listener.onConnectionFailure(error, reason);
196         } catch (Exception x) {
197             errorf("Failure while notifying listener %s", x, listener);
198         }
199     }
200 
201     interface Listener {
202         void onData(DataFrame frame);
203 
204         void onHeaders(HeadersFrame frame);
205 
206         void onPriority(PriorityFrame frame);
207 
208         void onReset(ResetFrame frame);
209 
210         void onSettings(SettingsFrame frame);
211 
212         void onPushPromise(PushPromiseFrame frame);
213 
214         void onPing(PingFrame frame);
215 
216         void onGoAway(GoAwayFrame frame);
217 
218         void onWindowUpdate(WindowUpdateFrame frame);
219 
220         void onConnectionFailure(int error, string reason);
221 
222         static class Adapter : Listener {
223             override
224             void onData(DataFrame frame) {
225             }
226 
227             override
228             void onHeaders(HeadersFrame frame) {
229             }
230 
231             override
232             void onPriority(PriorityFrame frame) {
233             }
234 
235             override
236             void onReset(ResetFrame frame) {
237             }
238 
239             override
240             void onSettings(SettingsFrame frame) {
241             }
242 
243             override
244             void onPushPromise(PushPromiseFrame frame) {
245             }
246 
247             override
248             void onPing(PingFrame frame) {
249             }
250 
251             override
252             void onGoAway(GoAwayFrame frame) {
253             }
254 
255             override
256             void onWindowUpdate(WindowUpdateFrame frame) {
257             }
258 
259             override
260             void onConnectionFailure(int error, string reason) {
261                 writeln("connection failure -> " ~ error.to!string ~ ", " ~ reason);
262                 warningf("Connection failure: %d/%s", error, reason);
263             }
264         }
265     }
266 
267     private enum State {
268         HEADER, BODY
269     }
270 }