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 }