1 module hunt.http.codec.http.decode.ContinuationBodyParser; 2 3 import hunt.io.ByteBuffer; 4 5 import hunt.http.codec.http.decode.BodyParser; 6 import hunt.http.codec.http.decode.HeaderBlockParser; 7 import hunt.http.codec.http.decode.HeaderBlockFragments; 8 import hunt.http.codec.http.decode.HeaderParser; 9 import hunt.http.codec.http.decode.Parser; 10 11 import hunt.http.codec.http.frame.ErrorCode; 12 import hunt.http.codec.http.frame.Flags; 13 import hunt.http.codec.http.frame.HeadersFrame; 14 15 import hunt.http.HttpMetaData; 16 17 import hunt.Exceptions; 18 19 /** 20 */ 21 class ContinuationBodyParser :BodyParser { 22 private HeaderBlockParser headerBlockParser; 23 private HeaderBlockFragments headerBlockFragments; 24 private State state = State.PREPARE; 25 private int length; 26 27 this(HeaderParser headerParser, Parser.Listener listener, 28 HeaderBlockParser headerBlockParser, HeaderBlockFragments headerBlockFragments) { 29 super(headerParser, listener); 30 this.headerBlockParser = headerBlockParser; 31 this.headerBlockFragments = headerBlockFragments; 32 } 33 34 override 35 protected void emptyBody(ByteBuffer buffer) { 36 if (hasFlag(Flags.END_HEADERS)) 37 onHeaders(); 38 } 39 40 override 41 bool parse(ByteBuffer buffer) { 42 while (buffer.hasRemaining()) { 43 switch (state) { 44 case State.PREPARE: { 45 // SPEC: wrong streamId is treated as connection error. 46 if (getStreamId() == 0) 47 return connectionFailure(buffer, cast(int)ErrorCode.PROTOCOL_ERROR, "invalid_continuation_frame"); 48 49 if (getStreamId() != headerBlockFragments.getStreamId()) 50 return connectionFailure(buffer, cast(int)ErrorCode.PROTOCOL_ERROR, "invalid_continuation_stream"); 51 52 length = getBodyLength(); 53 state = State.FRAGMENT; 54 break; 55 } 56 case State.FRAGMENT: { 57 int remaining = buffer.remaining(); 58 if (remaining < length) { 59 headerBlockFragments.storeFragment(buffer, remaining, false); 60 length -= remaining; 61 break; 62 } else { 63 bool last = hasFlag(Flags.END_HEADERS); 64 headerBlockFragments.storeFragment(buffer, length, last); 65 reset(); 66 if (last) 67 onHeaders(); 68 return true; 69 } 70 } 71 default: { 72 throw new IllegalStateException(""); 73 } 74 } 75 } 76 return false; 77 } 78 79 private void onHeaders() { 80 ByteBuffer headerBlock = headerBlockFragments.complete(); 81 HttpMetaData metaData = headerBlockParser.parse(headerBlock, headerBlock.remaining()); 82 HeadersFrame frame = new HeadersFrame(getStreamId(), metaData, headerBlockFragments.getPriorityFrame(), 83 headerBlockFragments.isEndStream()); 84 notifyHeaders(frame); 85 } 86 87 private void reset() { 88 state = State.PREPARE; 89 length = 0; 90 } 91 92 private enum State { 93 PREPARE, FRAGMENT 94 } 95 }