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 }