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 }