1 module hunt.http.codec.http.decode.HeaderParser;
2 
3 import hunt.io.ByteBuffer;
4 
5 import hunt.http.codec.http.frame.Frame;
6 
7 import hunt.Exceptions;
8 
9 /**
10  * <p>
11  * The parser for the frame header of HTTP/2 frames.
12  * </p>
13  *
14  * @see Parser
15  */
16 class HeaderParser {
17 	private State state = State.LENGTH;
18 	private int cursor;
19 
20 	private int length;
21 	private int type;
22 	private int flags;
23 	private int streamId;
24 
25 	void reset() {
26 		state = State.LENGTH;
27 		cursor = 0;
28 		
29 		length = 0;
30 		type = 0;
31 		flags = 0;
32 		streamId = 0;
33 	}
34 
35 	/**
36 	 * <p>
37 	 * Parses the header bytes in the given {@code buffer}; only the header
38 	 * bytes are consumed, therefore when this method returns, the buffer may
39 	 * contain unconsumed bytes.
40 	 * </p>
41 	 *
42 	 * @param buffer
43 	 *            the buffer to parse
44 	 * @return true if the whole header bytes were parsed, false if not enough
45 	 *         header bytes were present in the buffer
46 	 */
47 	bool parse(ByteBuffer buffer) {
48 		while (buffer.hasRemaining()) {
49 			switch (state) {
50 			case State.LENGTH: {
51 				int octet = buffer.get() & 0xFF;
52 				length = (length << 8) + octet;
53 				if (++cursor == 3) {
54 					length &= Frame.MAX_MAX_LENGTH;
55 					state = State.TYPE;
56 				}
57 				break;
58 			}
59 			case State.TYPE: {
60 				type = buffer.get() & 0xFF;
61 				state = State.FLAGS;
62 				break;
63 			}
64 			case State.FLAGS: {
65 				flags = buffer.get() & 0xFF;
66 				state = State.STREAM_ID;
67 				break;
68 			}
69 			case State.STREAM_ID: {
70 				if (buffer.remaining() >= 4) {
71 					streamId = buffer.get!int();
72 					// Most significant bit MUST be ignored as per specification.
73 					streamId &= 0x7F_FF_FF_FF;
74 					return true;
75 				} else {
76 					state = State.STREAM_ID_BYTES;
77 					cursor = 4;
78 				}
79 				break;
80 			}
81 			case State.STREAM_ID_BYTES: {
82 				int currByte = buffer.get() & 0xFF;
83 				--cursor;
84 				streamId += currByte << (8 * cursor);
85 				if (cursor == 0) {
86 					// Most significant bit MUST be ignored as per specification.
87 					streamId &= 0x7F_FF_FF_FF;
88 					return true;
89 				}
90 				break;
91 			}
92 			default: {
93 				throw new IllegalStateException("");
94 			}
95 			}
96 		}
97 		return false;
98 	}
99 
100 	int getLength() {
101 		return length;
102 	}
103 
104 	int getFrameType() {
105 		return type;
106 	}
107 
108 	bool hasFlag(int bit) {
109 		return (flags & bit) == bit;
110 	}
111 
112 	int getStreamId() {
113 		return streamId;
114 	}
115 
116 	private enum State {
117 		LENGTH, TYPE, FLAGS, STREAM_ID, STREAM_ID_BYTES
118 	}
119 }