1 module hunt.http.codec.http.decode.ResetBodyParser; 2 3 import hunt.io.ByteBuffer; 4 5 import hunt.http.codec.http.decode.BodyParser; 6 import hunt.http.codec.http.decode.HeaderParser; 7 import hunt.http.codec.http.decode.Parser; 8 9 import hunt.http.codec.http.frame.ErrorCode; 10 import hunt.http.codec.http.frame.ResetFrame; 11 12 import hunt.Exceptions; 13 14 /** 15 */ 16 class ResetBodyParser :BodyParser { 17 private State state = State.PREPARE; 18 private int cursor; 19 private int error; 20 21 this(HeaderParser headerParser, Parser.Listener listener) { 22 super(headerParser, listener); 23 } 24 25 private void reset() { 26 state = State.PREPARE; 27 cursor = 0; 28 error = 0; 29 } 30 31 override 32 bool parse(ByteBuffer buffer) { 33 while (buffer.hasRemaining()) { 34 switch (state) { 35 case State.PREPARE: { 36 // SPEC: wrong streamId is treated as connection error. 37 if (getStreamId() == 0) 38 return connectionFailure(buffer, cast(int)ErrorCode.PROTOCOL_ERROR, "invalid_rst_stream_frame"); 39 int length = getBodyLength(); 40 if (length != 4) 41 return connectionFailure(buffer, cast(int)ErrorCode.FRAME_SIZE_ERROR, "invalid_rst_stream_frame"); 42 state = State.ERROR; 43 break; 44 } 45 case State.ERROR: { 46 if (buffer.remaining() >= 4) { 47 return onReset(buffer.get!int()); 48 } else { 49 state = State.ERROR_BYTES; 50 cursor = 4; 51 } 52 break; 53 } 54 case State.ERROR_BYTES: { 55 int currByte = buffer.get() & 0xFF; 56 --cursor; 57 error += currByte << (8 * cursor); 58 if (cursor == 0) 59 return onReset(error); 60 break; 61 } 62 default: { 63 throw new IllegalStateException(""); 64 } 65 } 66 } 67 return false; 68 } 69 70 private bool onReset(int error) { 71 ResetFrame frame = new ResetFrame(getStreamId(), error); 72 reset(); 73 notifyReset(frame); 74 return true; 75 } 76 77 private enum State { 78 PREPARE, ERROR, ERROR_BYTES 79 } 80 }