• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicLineParser.java $
3  * $Revision: 591798 $
4  * $Date: 2007-11-04 08:19:29 -0800 (Sun, 04 Nov 2007) $
5  *
6  * ====================================================================
7  * Licensed to the Apache Software Foundation (ASF) under one
8  * or more contributor license agreements.  See the NOTICE file
9  * distributed with this work for additional information
10  * regarding copyright ownership.  The ASF licenses this file
11  * to you under the Apache License, Version 2.0 (the
12  * "License"); you may not use this file except in compliance
13  * with the License.  You may obtain a copy of the License at
14  *
15  *   http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing,
18  * software distributed under the License is distributed on an
19  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20  * KIND, either express or implied.  See the License for the
21  * specific language governing permissions and limitations
22  * under the License.
23  * ====================================================================
24  *
25  * This software consists of voluntary contributions made by many
26  * individuals on behalf of the Apache Software Foundation.  For more
27  * information on the Apache Software Foundation, please see
28  * <http://www.apache.org/>.
29  *
30  */
31 
32 package org.apache.http.message;
33 
34 import org.apache.http.HttpVersion;
35 import org.apache.http.ProtocolVersion;
36 import org.apache.http.ParseException;
37 import org.apache.http.RequestLine;
38 import org.apache.http.StatusLine;
39 import org.apache.http.Header;
40 import org.apache.http.protocol.HTTP;
41 import org.apache.http.util.CharArrayBuffer;
42 
43 
44 /**
45  * Basic parser for lines in the head section of an HTTP message.
46  * There are individual methods for parsing a request line, a
47  * status line, or a header line.
48  * The lines to parse are passed in memory, the parser does not depend
49  * on any specific IO mechanism.
50  * Instances of this class are stateless and thread-safe.
51  * Derived classes MUST maintain these properties.
52  *
53  * <p>
54  * Note: This class was created by refactoring parsing code located in
55  * various other classes. The author tags from those other classes have
56  * been replicated here, although the association with the parsing code
57  * taken from there has not been traced.
58  * </p>
59  *
60  * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
61  * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
62  * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
63  * @author and others
64  *
65  * @deprecated Please use {@link java.net.URL#openConnection} instead.
66  *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
67  *     for further details.
68  */
69 @Deprecated
70 public class BasicLineParser implements LineParser {
71 
72     /**
73      * A default instance of this class, for use as default or fallback.
74      * Note that {@link BasicLineParser} is not a singleton, there can
75      * be many instances of the class itself and of derived classes.
76      * The instance here provides non-customized, default behavior.
77      */
78     public final static BasicLineParser DEFAULT = new BasicLineParser();
79 
80 
81     /**
82      * A version of the protocol to parse.
83      * The version is typically not relevant, but the protocol name.
84      */
85     protected final ProtocolVersion protocol;
86 
87 
88     /**
89      * Creates a new line parser for the given HTTP-like protocol.
90      *
91      * @param proto     a version of the protocol to parse, or
92      *                  <code>null</code> for HTTP. The actual version
93      *                  is not relevant, only the protocol name.
94      */
BasicLineParser(ProtocolVersion proto)95     public BasicLineParser(ProtocolVersion proto) {
96         if (proto == null) {
97             proto = HttpVersion.HTTP_1_1;
98         }
99         this.protocol = proto;
100     }
101 
102 
103     /**
104      * Creates a new line parser for HTTP.
105      */
BasicLineParser()106     public BasicLineParser() {
107         this(null);
108     }
109 
110 
111 
112     public final static
parseProtocolVersion(String value, LineParser parser)113         ProtocolVersion parseProtocolVersion(String value,
114                                              LineParser parser)
115         throws ParseException {
116 
117         if (value == null) {
118             throw new IllegalArgumentException
119                 ("Value to parse may not be null.");
120         }
121 
122         if (parser == null)
123             parser = BasicLineParser.DEFAULT;
124 
125         CharArrayBuffer buffer = new CharArrayBuffer(value.length());
126         buffer.append(value);
127         ParserCursor cursor = new ParserCursor(0, value.length());
128         return parser.parseProtocolVersion(buffer, cursor);
129     }
130 
131 
132     // non-javadoc, see interface LineParser
parseProtocolVersion(final CharArrayBuffer buffer, final ParserCursor cursor)133     public ProtocolVersion parseProtocolVersion(final CharArrayBuffer buffer,
134                                                 final ParserCursor cursor)
135         throws ParseException {
136 
137         if (buffer == null) {
138             throw new IllegalArgumentException("Char array buffer may not be null");
139         }
140         if (cursor == null) {
141             throw new IllegalArgumentException("Parser cursor may not be null");
142         }
143 
144         final String protoname = this.protocol.getProtocol();
145         final int protolength  = protoname.length();
146 
147         int indexFrom = cursor.getPos();
148         int indexTo = cursor.getUpperBound();
149 
150         skipWhitespace(buffer, cursor);
151 
152         int i = cursor.getPos();
153 
154         // long enough for "HTTP/1.1"?
155         if (i + protolength + 4 > indexTo) {
156             throw new ParseException
157                 ("Not a valid protocol version: " +
158                  buffer.substring(indexFrom, indexTo));
159         }
160 
161         // check the protocol name and slash
162         boolean ok = true;
163         for (int j=0; ok && (j<protolength); j++) {
164             ok = (buffer.charAt(i+j) == protoname.charAt(j));
165         }
166         if (ok) {
167             ok = (buffer.charAt(i+protolength) == '/');
168         }
169         if (!ok) {
170             throw new ParseException
171                 ("Not a valid protocol version: " +
172                  buffer.substring(indexFrom, indexTo));
173         }
174 
175         i += protolength+1;
176 
177         int period = buffer.indexOf('.', i, indexTo);
178         if (period == -1) {
179             throw new ParseException
180                 ("Invalid protocol version number: " +
181                  buffer.substring(indexFrom, indexTo));
182         }
183         int major;
184         try {
185             major = Integer.parseInt(buffer.substringTrimmed(i, period));
186         } catch (NumberFormatException e) {
187             throw new ParseException
188                 ("Invalid protocol major version number: " +
189                  buffer.substring(indexFrom, indexTo));
190         }
191         i = period + 1;
192 
193         int blank = buffer.indexOf(' ', i, indexTo);
194         if (blank == -1) {
195             blank = indexTo;
196         }
197         int minor;
198         try {
199             minor = Integer.parseInt(buffer.substringTrimmed(i, blank));
200         } catch (NumberFormatException e) {
201             throw new ParseException(
202                 "Invalid protocol minor version number: " +
203                 buffer.substring(indexFrom, indexTo));
204         }
205 
206         cursor.updatePos(blank);
207 
208         return createProtocolVersion(major, minor);
209 
210     } // parseProtocolVersion
211 
212 
213     /**
214      * Creates a protocol version.
215      * Called from {@link #parseProtocolVersion}.
216      *
217      * @param major     the major version number, for example 1 in HTTP/1.0
218      * @param minor     the minor version number, for example 0 in HTTP/1.0
219      *
220      * @return  the protocol version
221      */
createProtocolVersion(int major, int minor)222     protected ProtocolVersion createProtocolVersion(int major, int minor) {
223         return protocol.forVersion(major, minor);
224     }
225 
226 
227 
228     // non-javadoc, see interface LineParser
hasProtocolVersion(final CharArrayBuffer buffer, final ParserCursor cursor)229     public boolean hasProtocolVersion(final CharArrayBuffer buffer,
230                                       final ParserCursor cursor) {
231 
232         if (buffer == null) {
233             throw new IllegalArgumentException("Char array buffer may not be null");
234         }
235         if (cursor == null) {
236             throw new IllegalArgumentException("Parser cursor may not be null");
237         }
238         int index = cursor.getPos();
239 
240         final String protoname = this.protocol.getProtocol();
241         final int  protolength = protoname.length();
242 
243         if (buffer.length() < protolength+4)
244             return false; // not long enough for "HTTP/1.1"
245 
246         if (index < 0) {
247             // end of line, no tolerance for trailing whitespace
248             // this works only for single-digit major and minor version
249             index = buffer.length() -4 -protolength;
250         } else if (index == 0) {
251             // beginning of line, tolerate leading whitespace
252             while ((index < buffer.length()) &&
253                     HTTP.isWhitespace(buffer.charAt(index))) {
254                  index++;
255              }
256         } // else within line, don't tolerate whitespace
257 
258 
259         if (index + protolength + 4 > buffer.length())
260             return false;
261 
262 
263         // just check protocol name and slash, no need to analyse the version
264         boolean ok = true;
265         for (int j=0; ok && (j<protolength); j++) {
266             ok = (buffer.charAt(index+j) == protoname.charAt(j));
267         }
268         if (ok) {
269             ok = (buffer.charAt(index+protolength) == '/');
270         }
271 
272         return ok;
273     }
274 
275 
276 
277     public final static
parseRequestLine(final String value, LineParser parser)278         RequestLine parseRequestLine(final String value,
279                                      LineParser parser)
280         throws ParseException {
281 
282         if (value == null) {
283             throw new IllegalArgumentException
284                 ("Value to parse may not be null.");
285         }
286 
287         if (parser == null)
288             parser = BasicLineParser.DEFAULT;
289 
290         CharArrayBuffer buffer = new CharArrayBuffer(value.length());
291         buffer.append(value);
292         ParserCursor cursor = new ParserCursor(0, value.length());
293         return parser.parseRequestLine(buffer, cursor);
294     }
295 
296 
297     /**
298      * Parses a request line.
299      *
300      * @param buffer    a buffer holding the line to parse
301      *
302      * @return  the parsed request line
303      *
304      * @throws ParseException        in case of a parse error
305      */
parseRequestLine(final CharArrayBuffer buffer, final ParserCursor cursor)306     public RequestLine parseRequestLine(final CharArrayBuffer buffer,
307                                         final ParserCursor cursor)
308         throws ParseException {
309 
310         if (buffer == null) {
311             throw new IllegalArgumentException("Char array buffer may not be null");
312         }
313         if (cursor == null) {
314             throw new IllegalArgumentException("Parser cursor may not be null");
315         }
316 
317         int indexFrom = cursor.getPos();
318         int indexTo = cursor.getUpperBound();
319 
320         try {
321             skipWhitespace(buffer, cursor);
322             int i = cursor.getPos();
323 
324             int blank = buffer.indexOf(' ', i, indexTo);
325             if (blank < 0) {
326                 throw new ParseException("Invalid request line: " +
327                         buffer.substring(indexFrom, indexTo));
328             }
329             String method = buffer.substringTrimmed(i, blank);
330             cursor.updatePos(blank);
331 
332             skipWhitespace(buffer, cursor);
333             i = cursor.getPos();
334 
335             blank = buffer.indexOf(' ', i, indexTo);
336             if (blank < 0) {
337                 throw new ParseException("Invalid request line: " +
338                         buffer.substring(indexFrom, indexTo));
339             }
340             String uri = buffer.substringTrimmed(i, blank);
341             cursor.updatePos(blank);
342 
343             ProtocolVersion ver = parseProtocolVersion(buffer, cursor);
344 
345             skipWhitespace(buffer, cursor);
346             if (!cursor.atEnd()) {
347                 throw new ParseException("Invalid request line: " +
348                         buffer.substring(indexFrom, indexTo));
349             }
350 
351             return createRequestLine(method, uri, ver);
352         } catch (IndexOutOfBoundsException e) {
353             throw new ParseException("Invalid request line: " +
354                                      buffer.substring(indexFrom, indexTo));
355         }
356     } // parseRequestLine
357 
358 
359     /**
360      * Instantiates a new request line.
361      * Called from {@link #parseRequestLine}.
362      *
363      * @param method    the request method
364      * @param uri       the requested URI
365      * @param ver       the protocol version
366      *
367      * @return  a new status line with the given data
368      */
createRequestLine(final String method, final String uri, final ProtocolVersion ver)369     protected RequestLine createRequestLine(final String method,
370                                             final String uri,
371                                             final ProtocolVersion ver) {
372         return new BasicRequestLine(method, uri, ver);
373     }
374 
375 
376 
377     public final static
parseStatusLine(final String value, LineParser parser)378         StatusLine parseStatusLine(final String value,
379                                    LineParser parser)
380         throws ParseException {
381 
382         if (value == null) {
383             throw new IllegalArgumentException
384                 ("Value to parse may not be null.");
385         }
386 
387         if (parser == null)
388             parser = BasicLineParser.DEFAULT;
389 
390         CharArrayBuffer buffer = new CharArrayBuffer(value.length());
391         buffer.append(value);
392         ParserCursor cursor = new ParserCursor(0, value.length());
393         return parser.parseStatusLine(buffer, cursor);
394     }
395 
396 
397     // non-javadoc, see interface LineParser
parseStatusLine(final CharArrayBuffer buffer, final ParserCursor cursor)398     public StatusLine parseStatusLine(final CharArrayBuffer buffer,
399                                       final ParserCursor cursor)
400         throws ParseException {
401 
402         if (buffer == null) {
403             throw new IllegalArgumentException("Char array buffer may not be null");
404         }
405         if (cursor == null) {
406             throw new IllegalArgumentException("Parser cursor may not be null");
407         }
408 
409         int indexFrom = cursor.getPos();
410         int indexTo = cursor.getUpperBound();
411 
412         try {
413             // handle the HTTP-Version
414             ProtocolVersion ver = parseProtocolVersion(buffer, cursor);
415 
416             // handle the Status-Code
417             skipWhitespace(buffer, cursor);
418             int i = cursor.getPos();
419 
420             int blank = buffer.indexOf(' ', i, indexTo);
421             if (blank < 0) {
422                 blank = indexTo;
423             }
424             int statusCode = 0;
425             try {
426                 statusCode =
427                     Integer.parseInt(buffer.substringTrimmed(i, blank));
428             } catch (NumberFormatException e) {
429                 throw new ParseException(
430                     "Unable to parse status code from status line: "
431                     + buffer.substring(indexFrom, indexTo));
432             }
433             //handle the Reason-Phrase
434             i = blank;
435             String reasonPhrase = null;
436             if (i < indexTo) {
437                 reasonPhrase = buffer.substringTrimmed(i, indexTo);
438             } else {
439                 reasonPhrase = "";
440             }
441             return createStatusLine(ver, statusCode, reasonPhrase);
442 
443         } catch (IndexOutOfBoundsException e) {
444             throw new ParseException("Invalid status line: " +
445                                      buffer.substring(indexFrom, indexTo));
446         }
447     } // parseStatusLine
448 
449 
450     /**
451      * Instantiates a new status line.
452      * Called from {@link #parseStatusLine}.
453      *
454      * @param ver       the protocol version
455      * @param status    the status code
456      * @param reason    the reason phrase
457      *
458      * @return  a new status line with the given data
459      */
createStatusLine(final ProtocolVersion ver, final int status, final String reason)460     protected StatusLine createStatusLine(final ProtocolVersion ver,
461                                           final int status,
462                                           final String reason) {
463         return new BasicStatusLine(ver, status, reason);
464     }
465 
466 
467 
468     public final static
parseHeader(final String value, LineParser parser)469         Header parseHeader(final String value,
470                            LineParser parser)
471         throws ParseException {
472 
473         if (value == null) {
474             throw new IllegalArgumentException
475                 ("Value to parse may not be null");
476         }
477 
478         if (parser == null)
479             parser = BasicLineParser.DEFAULT;
480 
481         CharArrayBuffer buffer = new CharArrayBuffer(value.length());
482         buffer.append(value);
483         return parser.parseHeader(buffer);
484     }
485 
486 
487     // non-javadoc, see interface LineParser
parseHeader(CharArrayBuffer buffer)488     public Header parseHeader(CharArrayBuffer buffer)
489         throws ParseException {
490 
491         // the actual parser code is in the constructor of BufferedHeader
492         return new BufferedHeader(buffer);
493     }
494 
495 
496     /**
497      * Helper to skip whitespace.
498      */
skipWhitespace(final CharArrayBuffer buffer, final ParserCursor cursor)499     protected void skipWhitespace(final CharArrayBuffer buffer, final ParserCursor cursor) {
500         int pos = cursor.getPos();
501         int indexTo = cursor.getUpperBound();
502         while ((pos < indexTo) &&
503                HTTP.isWhitespace(buffer.charAt(pos))) {
504             pos++;
505         }
506         cursor.updatePos(pos);
507     }
508 
509 } // class BasicLineParser
510