michael@0: /* michael@0: * ==================================================================== michael@0: * Licensed to the Apache Software Foundation (ASF) under one michael@0: * or more contributor license agreements. See the NOTICE file michael@0: * distributed with this work for additional information michael@0: * regarding copyright ownership. The ASF licenses this file michael@0: * to you under the Apache License, Version 2.0 (the michael@0: * "License"); you may not use this file except in compliance michael@0: * with the License. You may obtain a copy of the License at michael@0: * michael@0: * http://www.apache.org/licenses/LICENSE-2.0 michael@0: * michael@0: * Unless required by applicable law or agreed to in writing, michael@0: * software distributed under the License is distributed on an michael@0: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY michael@0: * KIND, either express or implied. See the License for the michael@0: * specific language governing permissions and limitations michael@0: * under the License. michael@0: * ==================================================================== michael@0: * michael@0: * This software consists of voluntary contributions made by many michael@0: * individuals on behalf of the Apache Software Foundation. For more michael@0: * information on the Apache Software Foundation, please see michael@0: * . michael@0: * michael@0: */ michael@0: michael@0: package ch.boye.httpclientandroidlib.message; michael@0: michael@0: import ch.boye.httpclientandroidlib.HttpVersion; michael@0: import ch.boye.httpclientandroidlib.ProtocolVersion; michael@0: import ch.boye.httpclientandroidlib.ParseException; michael@0: import ch.boye.httpclientandroidlib.RequestLine; michael@0: import ch.boye.httpclientandroidlib.StatusLine; michael@0: import ch.boye.httpclientandroidlib.Header; michael@0: import ch.boye.httpclientandroidlib.protocol.HTTP; michael@0: import ch.boye.httpclientandroidlib.util.CharArrayBuffer; michael@0: michael@0: /** michael@0: * Basic parser for lines in the head section of an HTTP message. michael@0: * There are individual methods for parsing a request line, a michael@0: * status line, or a header line. michael@0: * The lines to parse are passed in memory, the parser does not depend michael@0: * on any specific IO mechanism. michael@0: * Instances of this class are stateless and thread-safe. michael@0: * Derived classes MUST maintain these properties. michael@0: * michael@0: *

michael@0: * Note: This class was created by refactoring parsing code located in michael@0: * various other classes. The author tags from those other classes have michael@0: * been replicated here, although the association with the parsing code michael@0: * taken from there has not been traced. michael@0: *

michael@0: * michael@0: * @since 4.0 michael@0: */ michael@0: public class BasicLineParser implements LineParser { michael@0: michael@0: /** michael@0: * A default instance of this class, for use as default or fallback. michael@0: * Note that {@link BasicLineParser} is not a singleton, there can michael@0: * be many instances of the class itself and of derived classes. michael@0: * The instance here provides non-customized, default behavior. michael@0: */ michael@0: public final static BasicLineParser DEFAULT = new BasicLineParser(); michael@0: michael@0: michael@0: /** michael@0: * A version of the protocol to parse. michael@0: * The version is typically not relevant, but the protocol name. michael@0: */ michael@0: protected final ProtocolVersion protocol; michael@0: michael@0: michael@0: /** michael@0: * Creates a new line parser for the given HTTP-like protocol. michael@0: * michael@0: * @param proto a version of the protocol to parse, or michael@0: * null for HTTP. The actual version michael@0: * is not relevant, only the protocol name. michael@0: */ michael@0: public BasicLineParser(ProtocolVersion proto) { michael@0: if (proto == null) { michael@0: proto = HttpVersion.HTTP_1_1; michael@0: } michael@0: this.protocol = proto; michael@0: } michael@0: michael@0: michael@0: /** michael@0: * Creates a new line parser for HTTP. michael@0: */ michael@0: public BasicLineParser() { michael@0: this(null); michael@0: } michael@0: michael@0: michael@0: public final static michael@0: ProtocolVersion parseProtocolVersion(String value, michael@0: LineParser parser) michael@0: throws ParseException { michael@0: michael@0: if (value == null) { michael@0: throw new IllegalArgumentException michael@0: ("Value to parse may not be null."); michael@0: } michael@0: michael@0: if (parser == null) michael@0: parser = BasicLineParser.DEFAULT; michael@0: michael@0: CharArrayBuffer buffer = new CharArrayBuffer(value.length()); michael@0: buffer.append(value); michael@0: ParserCursor cursor = new ParserCursor(0, value.length()); michael@0: return parser.parseProtocolVersion(buffer, cursor); michael@0: } michael@0: michael@0: michael@0: // non-javadoc, see interface LineParser michael@0: public ProtocolVersion parseProtocolVersion(final CharArrayBuffer buffer, michael@0: final ParserCursor cursor) michael@0: throws ParseException { michael@0: michael@0: if (buffer == null) { michael@0: throw new IllegalArgumentException("Char array buffer may not be null"); michael@0: } michael@0: if (cursor == null) { michael@0: throw new IllegalArgumentException("Parser cursor may not be null"); michael@0: } michael@0: michael@0: final String protoname = this.protocol.getProtocol(); michael@0: final int protolength = protoname.length(); michael@0: michael@0: int indexFrom = cursor.getPos(); michael@0: int indexTo = cursor.getUpperBound(); michael@0: michael@0: skipWhitespace(buffer, cursor); michael@0: michael@0: int i = cursor.getPos(); michael@0: michael@0: // long enough for "HTTP/1.1"? michael@0: if (i + protolength + 4 > indexTo) { michael@0: throw new ParseException michael@0: ("Not a valid protocol version: " + michael@0: buffer.substring(indexFrom, indexTo)); michael@0: } michael@0: michael@0: // check the protocol name and slash michael@0: boolean ok = true; michael@0: for (int j=0; ok && (j buffer.length()) michael@0: return false; michael@0: michael@0: michael@0: // just check protocol name and slash, no need to analyse the version michael@0: boolean ok = true; michael@0: for (int j=0; ok && (j