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