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 parentStreamId;
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 parentStreamId = 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 connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_headers_priority_frame");
74 }
75 }
76
77 @Override
78 public boolean parse(ByteBuffer buffer)
79 {
80 boolean loop = false;
81 while (buffer.hasRemaining() || loop)
82 {
83 switch (state)
84 {
85 case PREPARE:
86 {
87
88 if (getStreamId() == 0)
89 return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_headers_frame");
90
91 length = getBodyLength();
92
93 if (isPadding())
94 {
95 state = State.PADDING_LENGTH;
96 }
97 else if (hasFlag(Flags.PRIORITY))
98 {
99 state = State.EXCLUSIVE;
100 }
101 else
102 {
103 state = State.HEADERS;
104 }
105 break;
106 }
107 case PADDING_LENGTH:
108 {
109 paddingLength = buffer.get() & 0xFF;
110 --length;
111 length -= paddingLength;
112 state = hasFlag(Flags.PRIORITY) ? State.EXCLUSIVE : State.HEADERS;
113 loop = length == 0;
114 if (length < 0)
115 return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_headers_frame_padding");
116 break;
117 }
118 case EXCLUSIVE:
119 {
120
121
122 int currByte = buffer.get(buffer.position());
123 exclusive = (currByte & 0x80) == 0x80;
124 state = State.PARENT_STREAM_ID;
125 break;
126 }
127 case PARENT_STREAM_ID:
128 {
129 if (buffer.remaining() >= 4)
130 {
131 parentStreamId = buffer.getInt();
132 parentStreamId &= 0x7F_FF_FF_FF;
133 length -= 4;
134 state = State.WEIGHT;
135 if (length < 1)
136 return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_headers_frame");
137 }
138 else
139 {
140 state = State.PARENT_STREAM_ID_BYTES;
141 cursor = 4;
142 }
143 break;
144 }
145 case PARENT_STREAM_ID_BYTES:
146 {
147 int currByte = buffer.get() & 0xFF;
148 --cursor;
149 parentStreamId += currByte << (8 * cursor);
150 --length;
151 if (cursor > 0 && length <= 0)
152 return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_headers_frame");
153 if (cursor == 0)
154 {
155 parentStreamId &= 0x7F_FF_FF_FF;
156 state = State.WEIGHT;
157 if (length < 1)
158 return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_headers_frame");
159 }
160 break;
161 }
162 case WEIGHT:
163 {
164 weight = (buffer.get() & 0xFF) + 1;
165 --length;
166 state = State.HEADERS;
167 loop = length == 0;
168 break;
169 }
170 case HEADERS:
171 {
172 if (hasFlag(Flags.END_HEADERS))
173 {
174 MetaData metaData = headerBlockParser.parse(buffer, length);
175 if (metaData != null)
176 {
177 state = State.PADDING;
178 loop = paddingLength == 0;
179 onHeaders(parentStreamId, weight, exclusive, metaData);
180 }
181 }
182 else
183 {
184 int remaining = buffer.remaining();
185 if (remaining < length)
186 {
187 headerBlockFragments.storeFragment(buffer, remaining, false);
188 length -= remaining;
189 }
190 else
191 {
192 headerBlockFragments.setStreamId(getStreamId());
193 headerBlockFragments.setEndStream(isEndStream());
194 if (hasFlag(Flags.PRIORITY))
195 headerBlockFragments.setPriorityFrame(new PriorityFrame(getStreamId(), parentStreamId, weight, exclusive));
196 headerBlockFragments.storeFragment(buffer, length, false);
197 state = State.PADDING;
198 loop = paddingLength == 0;
199 }
200 }
201 break;
202 }
203 case PADDING:
204 {
205 int size = Math.min(buffer.remaining(), paddingLength);
206 buffer.position(buffer.position() + size);
207 paddingLength -= size;
208 if (paddingLength == 0)
209 {
210 reset();
211 return true;
212 }
213 break;
214 }
215 default:
216 {
217 throw new IllegalStateException();
218 }
219 }
220 }
221 return false;
222 }
223
224 private void onHeaders(int parentStreamId, int weight, boolean exclusive, MetaData metaData)
225 {
226 PriorityFrame priorityFrame = null;
227 if (hasFlag(Flags.PRIORITY))
228 priorityFrame = new PriorityFrame(getStreamId(), parentStreamId, weight, exclusive);
229 HeadersFrame frame = new HeadersFrame(getStreamId(), metaData, priorityFrame, isEndStream());
230 notifyHeaders(frame);
231 }
232
233 private enum State
234 {
235 PREPARE, PADDING_LENGTH, EXCLUSIVE, PARENT_STREAM_ID, PARENT_STREAM_ID_BYTES, WEIGHT, HEADERS, PADDING
236 }
237 }