1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.http.message;
29
30 import org.apache.http.Header;
31 import org.apache.http.HttpVersion;
32 import org.apache.http.ParseException;
33 import org.apache.http.ProtocolVersion;
34 import org.apache.http.RequestLine;
35 import org.apache.http.StatusLine;
36 import org.apache.http.annotation.ThreadingBehavior;
37 import org.apache.http.annotation.Contract;
38 import org.apache.http.protocol.HTTP;
39 import org.apache.http.util.Args;
40 import org.apache.http.util.CharArrayBuffer;
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60 @Contract(threading = ThreadingBehavior.IMMUTABLE)
61 public class BasicLineParser implements LineParser {
62
63
64
65
66
67
68
69
70
71 @Deprecated
72 public final static BasicLineParserr.html#BasicLineParser">BasicLineParser DEFAULT = new BasicLineParser();
73
74 public final static BasicLineParser.html#BasicLineParser">BasicLineParser INSTANCE = new BasicLineParser();
75
76
77
78
79
80 protected final ProtocolVersion protocol;
81
82
83
84
85
86
87
88
89
90 public BasicLineParser(final ProtocolVersion proto) {
91 this.protocol = proto != null? proto : HttpVersion.HTTP_1_1;
92 }
93
94
95
96
97
98 public BasicLineParser() {
99 this(null);
100 }
101
102
103 public static
104 ProtocolVersion parseProtocolVersion(final String value,
105 final LineParser parser) throws ParseException {
106 Args.notNull(value, "Value");
107
108 final CharArrayBufferhtml#CharArrayBuffer">CharArrayBuffer buffer = new CharArrayBuffer(value.length());
109 buffer.append(value);
110 final ParserCursoror.html#ParserCursor">ParserCursor cursor = new ParserCursor(0, value.length());
111 return (parser != null ? parser : BasicLineParser.INSTANCE)
112 .parseProtocolVersion(buffer, cursor);
113 }
114
115
116
117 @Override
118 public ProtocolVersion parseProtocolVersion(final CharArrayBuffer buffer,
119 final ParserCursor cursor) throws ParseException {
120 Args.notNull(buffer, "Char array buffer");
121 Args.notNull(cursor, "Parser cursor");
122 final String protoname = this.protocol.getProtocol();
123 final int protolength = protoname.length();
124
125 final int indexFrom = cursor.getPos();
126 final int indexTo = cursor.getUpperBound();
127
128 skipWhitespace(buffer, cursor);
129
130 int i = cursor.getPos();
131
132
133 if (i + protolength + 4 > indexTo) {
134 throw new ParseException
135 ("Not a valid protocol version: " +
136 buffer.substring(indexFrom, indexTo));
137 }
138
139
140 boolean ok = true;
141 for (int j=0; ok && (j<protolength); j++) {
142 ok = (buffer.charAt(i+j) == protoname.charAt(j));
143 }
144 if (ok) {
145 ok = (buffer.charAt(i+protolength) == '/');
146 }
147 if (!ok) {
148 throw new ParseException
149 ("Not a valid protocol version: " +
150 buffer.substring(indexFrom, indexTo));
151 }
152
153 i += protolength+1;
154
155 final int period = buffer.indexOf('.', i, indexTo);
156 if (period == -1) {
157 throw new ParseException
158 ("Invalid protocol version number: " +
159 buffer.substring(indexFrom, indexTo));
160 }
161 final int major;
162 try {
163 major = Integer.parseInt(buffer.substringTrimmed(i, period));
164 } catch (final NumberFormatException e) {
165 throw new ParseException
166 ("Invalid protocol major version number: " +
167 buffer.substring(indexFrom, indexTo));
168 }
169 i = period + 1;
170
171 int blank = buffer.indexOf(' ', i, indexTo);
172 if (blank == -1) {
173 blank = indexTo;
174 }
175 final int minor;
176 try {
177 minor = Integer.parseInt(buffer.substringTrimmed(i, blank));
178 } catch (final NumberFormatException e) {
179 throw new ParseException(
180 "Invalid protocol minor version number: " +
181 buffer.substring(indexFrom, indexTo));
182 }
183
184 cursor.updatePos(blank);
185
186 return createProtocolVersion(major, minor);
187
188 }
189
190
191
192
193
194
195
196
197
198
199
200 protected ProtocolVersion createProtocolVersion(final int major, final int minor) {
201 return protocol.forVersion(major, minor);
202 }
203
204
205
206
207 @Override
208 public boolean hasProtocolVersion(final CharArrayBuffer buffer,
209 final ParserCursor cursor) {
210 Args.notNull(buffer, "Char array buffer");
211 Args.notNull(cursor, "Parser cursor");
212 int index = cursor.getPos();
213
214 final String protoname = this.protocol.getProtocol();
215 final int protolength = protoname.length();
216
217 if (buffer.length() < protolength+4)
218 {
219 return false;
220 }
221
222 if (index < 0) {
223
224
225 index = buffer.length() -4 -protolength;
226 } else if (index == 0) {
227
228 while ((index < buffer.length()) &&
229 HTTP.isWhitespace(buffer.charAt(index))) {
230 index++;
231 }
232 }
233
234
235 if (index + protolength + 4 > buffer.length()) {
236 return false;
237 }
238
239
240
241 boolean ok = true;
242 for (int j=0; ok && (j<protolength); j++) {
243 ok = (buffer.charAt(index+j) == protoname.charAt(j));
244 }
245 if (ok) {
246 ok = (buffer.charAt(index+protolength) == '/');
247 }
248
249 return ok;
250 }
251
252
253
254 public static
255 RequestLine parseRequestLine(final String value,
256 final LineParser parser) throws ParseException {
257 Args.notNull(value, "Value");
258
259 final CharArrayBufferhtml#CharArrayBuffer">CharArrayBuffer buffer = new CharArrayBuffer(value.length());
260 buffer.append(value);
261 final ParserCursoror.html#ParserCursor">ParserCursor cursor = new ParserCursor(0, value.length());
262 return (parser != null ? parser : BasicLineParser.INSTANCE)
263 .parseRequestLine(buffer, cursor);
264 }
265
266
267
268
269
270
271
272
273
274
275
276 @Override
277 public RequestLine parseRequestLine(final CharArrayBuffer buffer,
278 final ParserCursor cursor) throws ParseException {
279
280 Args.notNull(buffer, "Char array buffer");
281 Args.notNull(cursor, "Parser cursor");
282 final int indexFrom = cursor.getPos();
283 final int indexTo = cursor.getUpperBound();
284
285 try {
286 skipWhitespace(buffer, cursor);
287 int i = cursor.getPos();
288
289 int blank = buffer.indexOf(' ', i, indexTo);
290 if (blank < 0) {
291 throw new ParseException("Invalid request line: " +
292 buffer.substring(indexFrom, indexTo));
293 }
294 final String method = buffer.substringTrimmed(i, blank);
295 cursor.updatePos(blank);
296
297 skipWhitespace(buffer, cursor);
298 i = cursor.getPos();
299
300 blank = buffer.indexOf(' ', i, indexTo);
301 if (blank < 0) {
302 throw new ParseException("Invalid request line: " +
303 buffer.substring(indexFrom, indexTo));
304 }
305 final String uri = buffer.substringTrimmed(i, blank);
306 cursor.updatePos(blank);
307
308 final ProtocolVersion ver = parseProtocolVersion(buffer, cursor);
309
310 skipWhitespace(buffer, cursor);
311 if (!cursor.atEnd()) {
312 throw new ParseException("Invalid request line: " +
313 buffer.substring(indexFrom, indexTo));
314 }
315
316 return createRequestLine(method, uri, ver);
317 } catch (final IndexOutOfBoundsException e) {
318 throw new ParseException("Invalid request line: " +
319 buffer.substring(indexFrom, indexTo));
320 }
321 }
322
323
324
325
326
327
328
329
330
331
332
333
334 protected RequestLine createRequestLine(final String method,
335 final String uri,
336 final ProtocolVersion ver) {
337 return new BasicRequestLine(method, uri, ver);
338 }
339
340
341
342 public static
343 StatusLine parseStatusLine(final String value,
344 final LineParser parser) throws ParseException {
345 Args.notNull(value, "Value");
346
347 final CharArrayBufferhtml#CharArrayBuffer">CharArrayBuffer buffer = new CharArrayBuffer(value.length());
348 buffer.append(value);
349 final ParserCursoror.html#ParserCursor">ParserCursor cursor = new ParserCursor(0, value.length());
350 return (parser != null ? parser : BasicLineParser.INSTANCE)
351 .parseStatusLine(buffer, cursor);
352 }
353
354
355
356 @Override
357 public StatusLine parseStatusLine(final CharArrayBuffer buffer,
358 final ParserCursor cursor) throws ParseException {
359 Args.notNull(buffer, "Char array buffer");
360 Args.notNull(cursor, "Parser cursor");
361 final int indexFrom = cursor.getPos();
362 final int indexTo = cursor.getUpperBound();
363
364 try {
365
366 final ProtocolVersion ver = parseProtocolVersion(buffer, cursor);
367
368
369 skipWhitespace(buffer, cursor);
370 int i = cursor.getPos();
371
372 int blank = buffer.indexOf(' ', i, indexTo);
373 if (blank < 0) {
374 blank = indexTo;
375 }
376 final int statusCode;
377 final String s = buffer.substringTrimmed(i, blank);
378 for (int j = 0; j < s.length(); j++) {
379 if (!Character.isDigit(s.charAt(j))) {
380 throw new ParseException(
381 "Status line contains invalid status code: "
382 + buffer.substring(indexFrom, indexTo));
383 }
384 }
385 try {
386 statusCode = Integer.parseInt(s);
387 } catch (final NumberFormatException e) {
388 throw new ParseException(
389 "Status line contains invalid status code: "
390 + buffer.substring(indexFrom, indexTo));
391 }
392
393 i = blank;
394 final String reasonPhrase;
395 if (i < indexTo) {
396 reasonPhrase = buffer.substringTrimmed(i, indexTo);
397 } else {
398 reasonPhrase = "";
399 }
400 return createStatusLine(ver, statusCode, reasonPhrase);
401
402 } catch (final IndexOutOfBoundsException e) {
403 throw new ParseException("Invalid status line: " +
404 buffer.substring(indexFrom, indexTo));
405 }
406 }
407
408
409
410
411
412
413
414
415
416
417
418
419 protected StatusLine createStatusLine(final ProtocolVersion ver,
420 final int status,
421 final String reason) {
422 return new BasicStatusLine(ver, status, reason);
423 }
424
425
426
427 public static
428 Header parseHeader(final String value,
429 final LineParser parser) throws ParseException {
430 Args.notNull(value, "Value");
431
432 final CharArrayBufferhtml#CharArrayBuffer">CharArrayBuffer buffer = new CharArrayBuffer(value.length());
433 buffer.append(value);
434 return (parser != null ? parser : BasicLineParser.INSTANCE)
435 .parseHeader(buffer);
436 }
437
438
439
440 @Override
441 public Header parseHeader(final CharArrayBuffer buffer)
442 throws ParseException {
443
444
445 return new BufferedHeader(buffer);
446 }
447
448
449
450
451
452 protected void skipWhitespace(final CharArrayBuffer buffer, final ParserCursor cursor) {
453 int pos = cursor.getPos();
454 final int indexTo = cursor.getUpperBound();
455 while ((pos < indexTo) &&
456 HTTP.isWhitespace(buffer.charAt(pos))) {
457 pos++;
458 }
459 cursor.updatePos(pos);
460 }
461
462 }