1 module hunt.http.codec.http.decode.DataBodyParser;
2 
3 import hunt.http.codec.http.decode.BodyParser;
4 import hunt.http.codec.http.decode.HeaderParser;
5 import hunt.http.codec.http.decode.Parser;
6 
7 import hunt.http.codec.http.frame.DataFrame;
8 import hunt.http.codec.http.frame.ErrorCode;
9 
10 import hunt.io.BufferUtils;
11 import hunt.io.ByteBuffer;
12 
13 import hunt.Exceptions;
14 import std.algorithm;
15 import std.stdio;
16 /**
17 */
18 class DataBodyParser :BodyParser {
19 	private State state = State.PREPARE;
20 	private int padding;
21 	private int paddingLength;
22 	private int length;
23 
24 	this(HeaderParser headerParser, Parser.Listener listener) {
25 		super(headerParser, listener);
26 	}
27 
28 	private void reset() {
29 		state = State.PREPARE;
30 		padding = 0;
31 		paddingLength = 0;
32 		length = 0;
33 	}
34 
35 	override
36 	protected void emptyBody(ByteBuffer buffer) {
37 		if (isPadding())
38 			connectionFailure(buffer, cast(int)ErrorCode.PROTOCOL_ERROR, "invalid_data_frame");
39 		else
40 			onData(BufferUtils.EMPTY_BUFFER, false, 0);
41 	}
42 
43 	override
44 	bool parse(ByteBuffer buffer) {
45 		bool loop = false;
46 		while (buffer.hasRemaining() || loop) {
47 			switch (state) {
48 			case State.PREPARE: {
49 				// SPEC: wrong streamId is treated as connection error.
50 				if (getStreamId() == 0)
51 					return connectionFailure(buffer, cast(int)ErrorCode.PROTOCOL_ERROR, "invalid_data_frame");
52 
53 				length = getBodyLength();
54 				state = isPadding() ? State.PADDING_LENGTH : State.DATA;
55 				break;
56 			}
57 			case State.PADDING_LENGTH: {
58 				padding = 1; // We have seen this byte.
59 				paddingLength = buffer.get() & 0xFF;
60 				--length;
61 				length -= paddingLength;
62 				state = State.DATA;
63 				loop = length == 0;
64 				if (length < 0)
65 					return connectionFailure(buffer, cast(int)ErrorCode.FRAME_SIZE_ERROR, "invalid_data_frame_padding");
66 				break;
67 			}
68 			case State.DATA: {
69 				int size = std.algorithm.min(buffer.remaining(), length);
70 				int position = buffer.position();
71 				int limit = buffer.limit();
72 				buffer.limit(position + size);
73 				ByteBuffer slice = buffer.slice();
74 				buffer.limit(limit);
75 				buffer.position(position + size);
76 
77 				length -= size;
78 				if (length == 0) {
79 					state = State.PADDING;
80 					loop = paddingLength == 0;
81 					// Padding bytes include the bytes that define the
82 					// padding length plus the actual padding bytes.
83 					onData(slice, false, padding + paddingLength);
84 				} else {
85 					// We got partial data, simulate a smaller frame, and stay
86 					// in DATA state.
87 					// No padding for these synthetic frames (even if we have
88 					// read
89 					// the padding length already), it will be accounted at the
90 					// end.
91 					onData(slice, true, 0);
92 				}
93 				break;
94 			}
95 			case State.PADDING: {
96 				int size = std.algorithm.min(buffer.remaining(), paddingLength);
97 				buffer.position(buffer.position() + size);
98 				paddingLength -= size;
99 				if (paddingLength == 0) {
100 					reset();
101 					return true;
102 				}
103 				break;
104 			}
105 			default: {
106 				throw new IllegalStateException("");
107 			}
108 			}
109 		}
110 		return false;
111 	}
112 
113 	private void onData(ByteBuffer buffer, bool fragment, int padding) {
114 		DataFrame frame = new DataFrame(getStreamId(), buffer, !fragment && isEndStream(), padding);
115 		notifyData(frame);
116 	}
117 
118 	private enum State {
119 		PREPARE, PADDING_LENGTH, DATA, PADDING
120 	}
121 }