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 }