1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.http2.parser;
20
21 import java.nio.ByteBuffer;
22
23 import org.eclipse.jetty.http.MetaData;
24 import org.eclipse.jetty.http2.ErrorCode;
25 import org.eclipse.jetty.http2.Flags;
26 import org.eclipse.jetty.http2.frames.HeadersFrame;
27 import org.eclipse.jetty.http2.frames.PriorityFrame;
28 import org.eclipse.jetty.util.BufferUtil;
29
30 public class HeadersBodyParser extends BodyParser
31 {
32 private final HeaderBlockParser headerBlockParser;
33 private final HeaderBlockFragments headerBlockFragments;
34 private State state = State.PREPARE;
35 private int cursor;
36 private int length;
37 private int paddingLength;
38 private boolean exclusive;
39 private int streamId;
40 private int weight;
41
42 public HeadersBodyParser(HeaderParser headerParser, Parser.Listener listener, HeaderBlockParser headerBlockParser, HeaderBlockFragments headerBlockFragments)
43 {
44 super(headerParser, listener);
45 this.headerBlockParser = headerBlockParser;
46 this.headerBlockFragments = headerBlockFragments;
47 }
48
49 private void reset()
50 {
51 state = State.PREPARE;
52 cursor = 0;
53 length = 0;
54 paddingLength = 0;
55 exclusive = false;
56 streamId = 0;
57 weight = 0;
58 }
59
60 @Override
61 protected void emptyBody(ByteBuffer buffer)
62 {
63 if (hasFlag(Flags.END_HEADERS))
64 {
65 MetaData metaData = headerBlockParser.parse(BufferUtil.EMPTY_BUFFER, 0);
66 onHeaders(0, 0, false, metaData);
67 }
68 else
69 {
70 headerBlockFragments.setStreamId(getStreamId());
71 headerBlockFragments.setEndStream(isEndStream());
72 if (hasFlag(Flags.PRIORITY))
73 headerBlockFragments.setPriorityFrame(new PriorityFrame(streamId, getStreamId(), weight, exclusive));
74 }
75 reset();
76 }
77
78 @Override
79 public boolean parse(ByteBuffer buffer)
80 {
81 boolean loop = false;
82 while (buffer.hasRemaining() || loop)
83 {
84 switch (state)
85 {
86 case PREPARE:
87 {
88
89 if (getStreamId() == 0)
90 return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_headers_frame");
91
92 length = getBodyLength();
93
94 if (isPadding())
95 {
96 state = State.PADDING_LENGTH;
97 }
98 else if (hasFlag(Flags.PRIORITY))
99 {
100 state = State.EXCLUSIVE;
101 }
102 else
103 {
104 state = State.HEADERS;
105 }
106 break;
107 }
108 case PADDING_LENGTH:
109 {
110 paddingLength = buffer.get() & 0xFF;
111 --length;
112 length -= paddingLength;
113 state = hasFlag(Flags.PRIORITY) ? State.EXCLUSIVE : State.HEADERS;
114 loop = length == 0;
115 if (length < 0)
116 return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_headers_frame_padding");
117 break;
118 }
119 case EXCLUSIVE:
120 {
121
122
123 int currByte = buffer.get(buffer.position());
124 exclusive = (currByte & 0x80) == 0x80;
125 state = State.STREAM_ID;
126 break;
127 }
128 case STREAM_ID:
129 {
130 if (buffer.remaining() >= 4)
131 {
132 streamId = buffer.getInt();
133 streamId &= 0x7F_FF_FF_FF;
134 length -= 4;
135 state = State.WEIGHT;
136 if (length < 1)
137 return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_headers_frame");
138 }
139 else
140 {
141 state = State.STREAM_ID_BYTES;
142 cursor = 4;
143 }
144 break;
145 }
146 case STREAM_ID_BYTES:
147 {
148 int currByte = buffer.get() & 0xFF;
149 --cursor;
150 streamId += currByte << (8 * cursor);
151 --length;
152 if (cursor > 0 && length <= 0)
153 return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_headers_frame");
154 if (cursor == 0)
155 {
156 streamId &= 0x7F_FF_FF_FF;
157 state = State.WEIGHT;
158 if (length < 1)
159 return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_headers_frame");
160 }
161 break;
162 }
163 case WEIGHT:
164 {
165 weight = buffer.get() & 0xFF;
166 --length;
167 state = State.HEADERS;
168 loop = length == 0;
169 break;
170 }
171 case HEADERS:
172 {
173 if (hasFlag(Flags.END_HEADERS))
174 {
175 MetaData metaData = headerBlockParser.parse(buffer, length);
176 if (metaData != null)
177 {
178 state = State.PADDING;
179 loop = paddingLength == 0;
180 onHeaders(streamId, weight, exclusive, metaData);
181 }
182 }
183 else
184 {
185 int remaining = buffer.remaining();
186 if (remaining < length)
187 {
188 headerBlockFragments.storeFragment(buffer, remaining, false);
189 length -= remaining;
190 }
191 else
192 {
193 headerBlockFragments.setStreamId(getStreamId());
194 headerBlockFragments.setEndStream(isEndStream());
195 if (hasFlag(Flags.PRIORITY))
196 headerBlockFragments.setPriorityFrame(new PriorityFrame(streamId, getStreamId(), weight, exclusive));
197 headerBlockFragments.storeFragment(buffer, length, false);
198 state = State.PADDING;
199 loop = paddingLength == 0;
200 }
201 }
202 break;
203 }
204 case PADDING:
205 {
206 int size = Math.min(buffer.remaining(), paddingLength);
207 buffer.position(buffer.position() + size);
208 paddingLength -= size;
209 if (paddingLength == 0)
210 {
211 reset();
212 return true;
213 }
214 break;
215 }
216 default:
217 {
218 throw new IllegalStateException();
219 }
220 }
221 }
222 return false;
223 }
224
225 private void onHeaders(int streamId, int weight, boolean exclusive, MetaData metaData)
226 {
227 PriorityFrame priorityFrame = null;
228 if (hasFlag(Flags.PRIORITY))
229 priorityFrame = new PriorityFrame(streamId, getStreamId(), weight, exclusive);
230 HeadersFrame frame = new HeadersFrame(getStreamId(), metaData, priorityFrame, isEndStream());
231 notifyHeaders(frame);
232 }
233
234 private enum State
235 {
236 PREPARE, PADDING_LENGTH, EXCLUSIVE, STREAM_ID, STREAM_ID_BYTES, WEIGHT, HEADERS, PADDING
237 }
238 }