1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.fcgi.parser;
20
21 import java.nio.ByteBuffer;
22 import java.nio.charset.Charset;
23
24 import org.eclipse.jetty.http.HttpField;
25 import org.eclipse.jetty.util.log.Log;
26 import org.eclipse.jetty.util.log.Logger;
27
28 public class ParamsContentParser extends ContentParser
29 {
30 private static final Logger LOG = Log.getLogger(ParamsContentParser.class);
31
32 private final ServerParser.Listener listener;
33 private State state = State.LENGTH;
34 private int cursor;
35 private int length;
36 private int nameLength;
37 private int valueLength;
38 private byte[] nameBytes;
39 private byte[] valueBytes;
40
41 public ParamsContentParser(HeaderParser headerParser, ServerParser.Listener listener)
42 {
43 super(headerParser);
44 this.listener = listener;
45 }
46
47 @Override
48 public Result parse(ByteBuffer buffer)
49 {
50 while (buffer.hasRemaining() || state == State.PARAM)
51 {
52 switch (state)
53 {
54 case LENGTH:
55 {
56 length = getContentLength();
57 state = State.NAME_LENGTH;
58 break;
59 }
60 case NAME_LENGTH:
61 {
62 if (isLargeLength(buffer))
63 {
64 if (buffer.remaining() >= 4)
65 {
66 nameLength = buffer.getInt() & 0x7F_FF;
67 state = State.VALUE_LENGTH;
68 length -= 4;
69 }
70 else
71 {
72 state = State.NAME_LENGTH_BYTES;
73 cursor = 0;
74 }
75 }
76 else
77 {
78 nameLength = buffer.get() & 0xFF;
79 state = State.VALUE_LENGTH;
80 --length;
81 }
82 break;
83 }
84 case NAME_LENGTH_BYTES:
85 {
86 int quarterInt = buffer.get() & 0xFF;
87 nameLength = (nameLength << 8) + quarterInt;
88 --length;
89 if (++cursor == 4)
90 {
91 nameLength &= 0x7F_FF;
92 state = State.VALUE_LENGTH;
93 }
94 break;
95 }
96 case VALUE_LENGTH:
97 {
98 if (isLargeLength(buffer))
99 {
100 if (buffer.remaining() >= 4)
101 {
102 valueLength = buffer.getInt() & 0x7F_FF;
103 state = State.NAME;
104 length -= 4;
105 }
106 else
107 {
108 state = State.VALUE_LENGTH_BYTES;
109 cursor = 0;
110 }
111 }
112 else
113 {
114 valueLength = buffer.get() & 0xFF;
115 state = State.NAME;
116 --length;
117 }
118 break;
119 }
120 case VALUE_LENGTH_BYTES:
121 {
122 int quarterInt = buffer.get() & 0xFF;
123 valueLength = (valueLength << 8) + quarterInt;
124 --length;
125 if (++cursor == 4)
126 {
127 valueLength &= 0x7F_FF;
128 state = State.NAME;
129 }
130 break;
131 }
132 case NAME:
133 {
134 nameBytes = new byte[nameLength];
135 if (buffer.remaining() >= nameLength)
136 {
137 buffer.get(nameBytes);
138 state = State.VALUE;
139 length -= nameLength;
140 }
141 else
142 {
143 state = State.NAME_BYTES;
144 cursor = 0;
145 }
146 break;
147 }
148 case NAME_BYTES:
149 {
150 nameBytes[cursor] = buffer.get();
151 --length;
152 if (++cursor == nameLength)
153 state = State.VALUE;
154 break;
155 }
156 case VALUE:
157 {
158 valueBytes = new byte[valueLength];
159 if (buffer.remaining() >= valueLength)
160 {
161 buffer.get(valueBytes);
162 state = State.PARAM;
163 length -= valueLength;
164 }
165 else
166 {
167 state = State.VALUE_BYTES;
168 cursor = 0;
169 }
170 break;
171 }
172 case VALUE_BYTES:
173 {
174 valueBytes[cursor] = buffer.get();
175 --length;
176 if (++cursor == valueLength)
177 state = State.PARAM;
178 break;
179 }
180 case PARAM:
181 {
182 Charset utf8 = Charset.forName("UTF-8");
183 onParam(new String(nameBytes, utf8), new String(valueBytes, utf8));
184 partialReset();
185 if (length == 0)
186 {
187 reset();
188 return Result.COMPLETE;
189 }
190 break;
191 }
192 default:
193 {
194 throw new IllegalStateException();
195 }
196 }
197 }
198 return Result.PENDING;
199 }
200
201 @Override
202 public void noContent()
203 {
204 onParams();
205 }
206
207 protected void onParam(String name, String value)
208 {
209 try
210 {
211 listener.onHeader(getRequest(), new HttpField(name, value));
212 }
213 catch (Throwable x)
214 {
215 if (LOG.isDebugEnabled())
216 LOG.debug("Exception while invoking listener " + listener, x);
217 }
218 }
219
220 protected void onParams()
221 {
222 try
223 {
224 listener.onHeaders(getRequest());
225 }
226 catch (Throwable x)
227 {
228 if (LOG.isDebugEnabled())
229 LOG.debug("Exception while invoking listener " + listener, x);
230 }
231 }
232
233 private boolean isLargeLength(ByteBuffer buffer)
234 {
235 return (buffer.get(buffer.position()) & 0x80) == 0x80;
236 }
237
238 private void partialReset()
239 {
240 state = State.NAME_LENGTH;
241 cursor = 0;
242 nameLength = 0;
243 valueLength = 0;
244 nameBytes = null;
245 valueBytes = null;
246 }
247
248 private void reset()
249 {
250 partialReset();
251 state = State.LENGTH;
252 length = 0;
253 }
254
255 private enum State
256 {
257 LENGTH, NAME_LENGTH, NAME_LENGTH_BYTES, VALUE_LENGTH, VALUE_LENGTH_BYTES, NAME, NAME_BYTES, VALUE, VALUE_BYTES, PARAM
258 }
259 }