1069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project/*
2069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicTokenIterator.java $
3069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * $Revision: 602520 $
4069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * $Date: 2007-12-08 09:42:26 -0800 (Sat, 08 Dec 2007) $
5069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
6069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * ====================================================================
7069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Licensed to the Apache Software Foundation (ASF) under one
8069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * or more contributor license agreements.  See the NOTICE file
9069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * distributed with this work for additional information
10069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * regarding copyright ownership.  The ASF licenses this file
11069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * to you under the Apache License, Version 2.0 (the
12069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * "License"); you may not use this file except in compliance
13069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * with the License.  You may obtain a copy of the License at
14069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
15069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *   http://www.apache.org/licenses/LICENSE-2.0
16069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
17069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Unless required by applicable law or agreed to in writing,
18069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * software distributed under the License is distributed on an
19069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * KIND, either express or implied.  See the License for the
21069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * specific language governing permissions and limitations
22069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * under the License.
23069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * ====================================================================
24069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
25069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * This software consists of voluntary contributions made by many
26069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * individuals on behalf of the Apache Software Foundation.  For more
27069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * information on the Apache Software Foundation, please see
28069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * <http://www.apache.org/>.
29069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
30069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */
31069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
32069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectpackage org.apache.http.message;
33069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
34069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport java.util.NoSuchElementException;
35069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
36069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport org.apache.http.HeaderIterator;
37069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport org.apache.http.ParseException;
38069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport org.apache.http.TokenIterator;
39069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
40069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project/**
41069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Basic implementation of a {@link TokenIterator}.
42069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * This implementation parses <tt>#token<tt> sequences as
43069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * defined by RFC 2616, section 2.
44069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * It extends that definition somewhat beyond US-ASCII.
45069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
46069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @version $Revision: 602520 $
47d42abb2fd917184764daf22f5f299e848b8701d7Narayan Kamath *
48d42abb2fd917184764daf22f5f299e848b8701d7Narayan Kamath * @deprecated Please use {@link java.net.URL#openConnection} instead.
49d42abb2fd917184764daf22f5f299e848b8701d7Narayan Kamath *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
50d42abb2fd917184764daf22f5f299e848b8701d7Narayan Kamath *     for further details.
51069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */
52d42abb2fd917184764daf22f5f299e848b8701d7Narayan Kamath@Deprecated
53069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectpublic class BasicTokenIterator implements TokenIterator {
54069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
55069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /** The HTTP separator characters. Defined in RFC 2616, section 2.2. */
56069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    // the order of the characters here is adjusted to put the
57069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    // most likely candidates at the beginning of the collection
58069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public final static String HTTP_SEPARATORS = " ,;=()<>@:\\\"/[]?{}\t";
59069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
60069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
61069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /** The iterator from which to obtain the next header. */
62069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    protected final HeaderIterator headerIt;
63069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
64069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
65069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * The value of the current header.
66069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * This is the header value that includes {@link #currentToken}.
67069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Undefined if the iteration is over.
68069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
69069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    protected String currentHeader;
70069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
71069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
72069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * The token to be returned by the next call to {@link #currentToken}.
73069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * <code>null</code> if the iteration is over.
74069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
75069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    protected String currentToken;
76069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
77069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
78069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * The position after {@link #currentToken} in {@link #currentHeader}.
79069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Undefined if the iteration is over.
80069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
81069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    protected int searchPos;
82069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
83069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
84069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
85069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Creates a new instance of {@link BasicTokenIterator}.
86069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
87069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param headerIterator    the iterator for the headers to tokenize
88069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
89069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public BasicTokenIterator(final HeaderIterator headerIterator) {
90069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (headerIterator == null) {
91069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            throw new IllegalArgumentException
92069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                ("Header iterator must not be null.");
93069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
94069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
95069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        this.headerIt = headerIterator;
96069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        this.searchPos = findNext(-1);
97069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
98069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
99069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
100069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    // non-javadoc, see interface TokenIterator
101069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public boolean hasNext() {
102069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return (this.currentToken != null);
103069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
104069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
105069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
106069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
107069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Obtains the next token from this iteration.
108069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
109069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @return  the next token in this iteration
110069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
111069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @throws NoSuchElementException   if the iteration is already over
112069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @throws ParseException   if an invalid header value is encountered
113069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
114069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public String nextToken()
115069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        throws NoSuchElementException, ParseException {
116069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
117069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (this.currentToken == null) {
118069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            throw new NoSuchElementException("Iteration already finished.");
119069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
120069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
121069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        final String result = this.currentToken;
122069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        // updates currentToken, may trigger ParseException:
123069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        this.searchPos = findNext(this.searchPos);
124069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
125069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return result;
126069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
127069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
128069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
129069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
130069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Returns the next token.
131069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Same as {@link #nextToken}, but with generic return type.
132069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
133069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @return  the next token in this iteration
134069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
135069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @throws NoSuchElementException   if there are no more tokens
136069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @throws ParseException   if an invalid header value is encountered
137069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
138069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public final Object next()
139069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        throws NoSuchElementException, ParseException {
140069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return nextToken();
141069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
142069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
143069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
144069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
145069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Removing tokens is not supported.
146069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
147069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @throws UnsupportedOperationException    always
148069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
149069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public final void remove()
150069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        throws UnsupportedOperationException {
151069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
152069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        throw new UnsupportedOperationException
153069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            ("Removing tokens is not supported.");
154069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
155069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
156069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
157069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
158069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Determines the next token.
159069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * If found, the token is stored in {@link #currentToken}.
160069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * The return value indicates the position after the token
161069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * in {@link #currentHeader}. If necessary, the next header
162069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * will be obtained from {@link #headerIt}.
163069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * If not found, {@link #currentToken} is set to <code>null</code>.
164069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
165069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param from      the position in the current header at which to
166069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *                  start the search, -1 to search in the first header
167069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
168069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @return  the position after the found token in the current header, or
169069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *          negative if there was no next token
170069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
171069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @throws ParseException   if an invalid header value is encountered
172069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
173069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    protected int findNext(int from)
174069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        throws ParseException {
175069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
176069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (from < 0) {
177069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            // called from the constructor, initialize the first header
178069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            if (!this.headerIt.hasNext()) {
179069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                return -1;
180069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            }
181069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            this.currentHeader = this.headerIt.nextHeader().getValue();
182069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            from = 0;
183069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        } else {
184069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            // called after a token, make sure there is a separator
185069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            from = findTokenSeparator(from);
186069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
187069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
188069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        int start = findTokenStart(from);
189069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (start < 0) {
190069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            this.currentToken = null;
191069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            return -1; // nothing found
192069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
193069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
194069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        int end = findTokenEnd(start);
195069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        this.currentToken = createToken(this.currentHeader, start, end);
196069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return end;
197069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
198069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
199069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
200069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
201069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Creates a new token to be returned.
202069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Called from {@link #findNext findNext} after the token is identified.
203069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * The default implementation simply calls
204069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * {@link java.lang.String#substring String.substring}.
205069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * <br/>
206069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * If header values are significantly longer than tokens, and some
207069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * tokens are permanently referenced by the application, there can
208069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * be problems with garbage collection. A substring will hold a
209069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * reference to the full characters of the original string and
210069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * therefore occupies more memory than might be expected.
211069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * To avoid this, override this method and create a new string
212069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * instead of a substring.
213069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
214069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param value     the full header value from which to create a token
215069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param start     the index of the first token character
216069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param end       the index after the last token character
217069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
218069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @return  a string representing the token identified by the arguments
219069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
220069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    protected String createToken(String value, int start, int end) {
221069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return value.substring(start, end);
222069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
223069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
224069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
225069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
226069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Determines the starting position of the next token.
227069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * This method will iterate over headers if necessary.
228069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
229069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param from      the position in the current header at which to
230069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *                  start the search
231069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
232069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @return  the position of the token start in the current header,
233069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *          negative if no token start could be found
234069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
235069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    protected int findTokenStart(int from) {
236069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (from < 0) {
237069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            throw new IllegalArgumentException
238069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                ("Search position must not be negative: " + from);
239069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
240069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
241069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        boolean found = false;
242069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        while (!found && (this.currentHeader != null)) {
243069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
244069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            final int to = this.currentHeader.length();
245069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            while (!found && (from < to)) {
246069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
247069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                final char ch = this.currentHeader.charAt(from);
248069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                if (isTokenSeparator(ch) || isWhitespace(ch)) {
249069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    // whitspace and token separators are skipped
250069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    from++;
251069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                } else if (isTokenChar(this.currentHeader.charAt(from))) {
252069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    // found the start of a token
253069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    found = true;
254069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                } else {
255069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    throw new ParseException
256069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        ("Invalid character before token (pos " + from +
257069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                         "): " + this.currentHeader);
258069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                }
259069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            }
260069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            if (!found) {
261069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                if (this.headerIt.hasNext()) {
262069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    this.currentHeader = this.headerIt.nextHeader().getValue();
263069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    from = 0;
264069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                } else {
265069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    this.currentHeader = null;
266069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                }
267069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            }
268069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        } // while headers
269069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
270069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return found ? from : -1;
271069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
272069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
273069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
274069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
275069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Determines the position of the next token separator.
276069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Because of multi-header joining rules, the end of a
277069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * header value is a token separator. This method does
278069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * therefore not need to iterate over headers.
279069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
280069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param from      the position in the current header at which to
281069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *                  start the search
282069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
283069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @return  the position of a token separator in the current header,
284069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *          or at the end
285069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
286069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @throws ParseException
287069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *         if a new token is found before a token separator.
288069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *         RFC 2616, section 2.1 explicitly requires a comma between
289069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *         tokens for <tt>#</tt>.
290069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
291069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    protected int findTokenSeparator(int from) {
292069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (from < 0) {
293069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            throw new IllegalArgumentException
294069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                ("Search position must not be negative: " + from);
295069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
296069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
297069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        boolean found = false;
298069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        final int to = this.currentHeader.length();
299069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        while (!found && (from < to)) {
300069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            final char ch = this.currentHeader.charAt(from);
301069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            if (isTokenSeparator(ch)) {
302069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                found = true;
303069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            } else if (isWhitespace(ch)) {
304069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                from++;
305069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            } else if (isTokenChar(ch)) {
306069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                throw new ParseException
307069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    ("Tokens without separator (pos " + from +
308069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                     "): " + this.currentHeader);
309069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            } else {
310069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                throw new ParseException
311069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                    ("Invalid character after token (pos " + from +
312069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                     "): " + this.currentHeader);
313069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            }
314069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
315069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
316069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return from;
317069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
318069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
319069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
320069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
321069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Determines the ending position of the current token.
322069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * This method will not leave the current header value,
323069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * since the end of the header value is a token boundary.
324069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
325069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param from      the position of the first character of the token
326069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
327069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @return  the position after the last character of the token.
328069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *          The behavior is undefined if <code>from</code> does not
329069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *          point to a token character in the current header value.
330069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
331069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    protected int findTokenEnd(int from) {
332069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (from < 0) {
333069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            throw new IllegalArgumentException
334069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                ("Token start position must not be negative: " + from);
335069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
336069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
337069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        final int to = this.currentHeader.length();
338069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        int end = from+1;
339069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        while ((end < to) && isTokenChar(this.currentHeader.charAt(end))) {
340069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            end++;
341069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
342069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
343069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return end;
344069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
345069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
346069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
347069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
348069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Checks whether a character is a token separator.
349069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * RFC 2616, section 2.1 defines comma as the separator for
350069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * <tt>#token</tt> sequences. The end of a header value will
351069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * also separate tokens, but that is not a character check.
352069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
353069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param ch        the character to check
354069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
355069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @return  <code>true</code> if the character is a token separator,
356069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *          <code>false</code> otherwise
357069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
358069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    protected boolean isTokenSeparator(char ch) {
359069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return (ch == ',');
360069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
361069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
362069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
363069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
364069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Checks whether a character is a whitespace character.
365069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * RFC 2616, section 2.2 defines space and horizontal tab as whitespace.
366069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * The optional preceeding line break is irrelevant, since header
367069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * continuation is handled transparently when parsing messages.
368069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
369069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param ch        the character to check
370069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
371069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @return  <code>true</code> if the character is whitespace,
372069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *          <code>false</code> otherwise
373069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
374069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    protected boolean isWhitespace(char ch) {
375069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
376069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        // we do not use Character.isWhitspace(ch) here, since that allows
377069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        // many control characters which are not whitespace as per RFC 2616
378069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return ((ch == '\t') || Character.isSpaceChar(ch));
379069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
380069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
381069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
382069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
383069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Checks whether a character is a valid token character.
384069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Whitespace, control characters, and HTTP separators are not
385069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * valid token characters. The HTTP specification (RFC 2616, section 2.2)
386069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * defines tokens only for the US-ASCII character set, this
387069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * method extends the definition to other character sets.
388069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
389069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param ch        the character to check
390069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
391069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @return  <code>true</code> if the character is a valid token start,
392069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *          <code>false</code> otherwise
393069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
394069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    protected boolean isTokenChar(char ch) {
395069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
396069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        // common sense extension of ALPHA + DIGIT
397069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (Character.isLetterOrDigit(ch))
398069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            return true;
399069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
400069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        // common sense extension of CTL
401069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (Character.isISOControl(ch))
402069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            return false;
403069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
404069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        // no common sense extension for this
405069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (isHttpSeparator(ch))
406069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            return false;
407069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
408069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        // RFC 2616, section 2.2 defines a token character as
409069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        // "any CHAR except CTLs or separators". The controls
410069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        // and separators are included in the checks above.
411069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        // This will yield unexpected results for Unicode format characters.
412069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        // If that is a problem, overwrite isHttpSeparator(char) to filter
413069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        // out the false positives.
414069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return true;
415069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
416069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
417069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
418069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
419069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Checks whether a character is an HTTP separator.
420069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * The implementation in this class checks only for the HTTP separators
421069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * defined in RFC 2616, section 2.2. If you need to detect other
422069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * separators beyond the US-ASCII character set, override this method.
423069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
424069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param ch        the character to check
425069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
426069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @return  <code>true</code> if the character is an HTTP separator
427069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
428069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    protected boolean isHttpSeparator(char ch) {
429069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return (HTTP_SEPARATORS.indexOf(ch) >= 0);
430069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
431069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
432069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
433069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project} // class BasicTokenIterator
434069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
435