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