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 import java.util.HashMap;
23 import java.util.Map;
24 import java.util.concurrent.atomic.AtomicReference;
25
26 import org.eclipse.jetty.http2.ErrorCode;
27 import org.eclipse.jetty.http2.Flags;
28 import org.eclipse.jetty.http2.frames.SettingsFrame;
29 import org.eclipse.jetty.util.log.Log;
30 import org.eclipse.jetty.util.log.Logger;
31
32 public class SettingsBodyParser extends BodyParser
33 {
34 private static final Logger LOG = Log.getLogger(SettingsBodyParser.class);
35 private State state = State.PREPARE;
36 private int cursor;
37 private int length;
38 private int settingId;
39 private int settingValue;
40 private Map<Integer, Integer> settings;
41
42 public SettingsBodyParser(HeaderParser headerParser, Parser.Listener listener)
43 {
44 super(headerParser, listener);
45 }
46
47 protected void reset()
48 {
49 state = State.PREPARE;
50 cursor = 0;
51 length = 0;
52 settingId = 0;
53 settingValue = 0;
54 settings = null;
55 }
56
57 @Override
58 protected void emptyBody(ByteBuffer buffer)
59 {
60 onSettings(new HashMap<>());
61 }
62
63 @Override
64 public boolean parse(ByteBuffer buffer)
65 {
66 while (buffer.hasRemaining())
67 {
68 switch (state)
69 {
70 case PREPARE:
71 {
72
73 if (getStreamId() != 0)
74 return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_settings_frame");
75 length = getBodyLength();
76 settings = new HashMap<>();
77 state = State.SETTING_ID;
78 break;
79 }
80 case SETTING_ID:
81 {
82 if (buffer.remaining() >= 2)
83 {
84 settingId = buffer.getShort() & 0xFF_FF;
85 state = State.SETTING_VALUE;
86 length -= 2;
87 if (length <= 0)
88 return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_settings_frame");
89 }
90 else
91 {
92 cursor = 2;
93 settingId = 0;
94 state = State.SETTING_ID_BYTES;
95 }
96 break;
97 }
98 case SETTING_ID_BYTES:
99 {
100 int currByte = buffer.get() & 0xFF;
101 --cursor;
102 settingId += currByte << (8 * cursor);
103 --length;
104 if (length <= 0)
105 return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_settings_frame");
106 if (cursor == 0)
107 {
108 state = State.SETTING_VALUE;
109 }
110 break;
111 }
112 case SETTING_VALUE:
113 {
114 if (buffer.remaining() >= 4)
115 {
116 settingValue = buffer.getInt();
117 if (LOG.isDebugEnabled())
118 LOG.debug(String.format("setting %d=%d",settingId, settingValue));
119 settings.put(settingId, settingValue);
120 state = State.SETTING_ID;
121 length -= 4;
122 if (length == 0)
123 return onSettings(settings);
124 }
125 else
126 {
127 cursor = 4;
128 settingValue = 0;
129 state = State.SETTING_VALUE_BYTES;
130 }
131 break;
132 }
133 case SETTING_VALUE_BYTES:
134 {
135 int currByte = buffer.get() & 0xFF;
136 --cursor;
137 settingValue += currByte << (8 * cursor);
138 --length;
139 if (cursor > 0 && length <= 0)
140 return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_settings_frame");
141 if (cursor == 0)
142 {
143 if (LOG.isDebugEnabled())
144 LOG.debug(String.format("setting %d=%d",settingId, settingValue));
145 settings.put(settingId, settingValue);
146 state = State.SETTING_ID;
147 if (length == 0)
148 return onSettings(settings);
149 }
150 break;
151 }
152 default:
153 {
154 throw new IllegalStateException();
155 }
156 }
157 }
158 return false;
159 }
160
161 protected boolean onSettings(Map<Integer, Integer> settings)
162 {
163 SettingsFrame frame = new SettingsFrame(settings, hasFlag(Flags.ACK));
164 reset();
165 notifySettings(frame);
166 return true;
167 }
168
169 public static SettingsFrame parseBody(final ByteBuffer buffer)
170 {
171 final int bodyLength = buffer.remaining();
172 final AtomicReference<SettingsFrame> frameRef = new AtomicReference<>();
173 SettingsBodyParser parser = new SettingsBodyParser(null, null)
174 {
175 @Override
176 protected int getStreamId()
177 {
178 return 0;
179 }
180
181 @Override
182 protected int getBodyLength()
183 {
184 return bodyLength;
185 }
186
187 @Override
188 protected boolean onSettings(Map<Integer, Integer> settings)
189 {
190 frameRef.set(new SettingsFrame(settings, false));
191 return true;
192 }
193
194 @Override
195 protected boolean connectionFailure(ByteBuffer buffer, int error, String reason)
196 {
197 frameRef.set(null);
198 return false;
199 }
200 };
201 if (bodyLength == 0)
202 parser.emptyBody(buffer);
203 else
204 parser.parse(buffer);
205 return frameRef.get();
206 }
207
208 private enum State
209 {
210 PREPARE, SETTING_ID, SETTING_ID_BYTES, SETTING_VALUE, SETTING_VALUE_BYTES
211 }
212 }