1/*
2 * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicHeaderValueParser.java $
3 * $Revision: 595670 $
4 * $Date: 2007-11-16 06:15:01 -0800 (Fri, 16 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
32package org.apache.http.message;
33
34
35import java.util.List;
36import java.util.ArrayList;
37
38import org.apache.http.HeaderElement;
39import org.apache.http.NameValuePair;
40import org.apache.http.ParseException;
41import org.apache.http.protocol.HTTP;
42import org.apache.http.util.CharArrayBuffer;
43
44
45
46/**
47 * Basic implementation for parsing header values into elements.
48 * Instances of this class are stateless and thread-safe.
49 * Derived classes are expected to maintain these properties.
50 *
51 * @author <a href="mailto:bcholmes@interlog.com">B.C. Holmes</a>
52 * @author <a href="mailto:jericho@thinkfree.com">Park, Sung-Gu</a>
53 * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
54 * @author <a href="mailto:oleg at ural.com">Oleg Kalnichevski</a>
55 * @author and others
56 *
57 *
58 * <!-- empty lines above to avoid 'svn diff' context problems -->
59 * @version $Revision: 595670 $
60 *
61 * @since 4.0
62 *
63 * @deprecated Please use {@link java.net.URL#openConnection} instead.
64 *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
65 *     for further details.
66 */
67@Deprecated
68public class BasicHeaderValueParser implements HeaderValueParser {
69
70    /**
71     * A default instance of this class, for use as default or fallback.
72     * Note that {@link BasicHeaderValueParser} is not a singleton, there
73     * can be many instances of the class itself and of derived classes.
74     * The instance here provides non-customized, default behavior.
75     */
76    public final static
77        BasicHeaderValueParser DEFAULT = new BasicHeaderValueParser();
78
79    private final static char PARAM_DELIMITER                = ';';
80    private final static char ELEM_DELIMITER                 = ',';
81    private final static char[] ALL_DELIMITERS               = new char[] {
82                                                                PARAM_DELIMITER,
83                                                                ELEM_DELIMITER
84                                                                };
85
86    // public default constructor
87
88
89    /**
90     * Parses elements with the given parser.
91     *
92     * @param value     the header value to parse
93     * @param parser    the parser to use, or <code>null</code> for default
94     *
95     * @return  array holding the header elements, never <code>null</code>
96     */
97    public final static
98        HeaderElement[] parseElements(final String value,
99                                      HeaderValueParser parser)
100        throws ParseException {
101
102        if (value == null) {
103            throw new IllegalArgumentException
104                ("Value to parse may not be null");
105        }
106
107        if (parser == null)
108            parser = BasicHeaderValueParser.DEFAULT;
109
110        CharArrayBuffer buffer = new CharArrayBuffer(value.length());
111        buffer.append(value);
112        ParserCursor cursor = new ParserCursor(0, value.length());
113        return parser.parseElements(buffer, cursor);
114    }
115
116
117    // non-javadoc, see interface HeaderValueParser
118    public HeaderElement[] parseElements(final CharArrayBuffer buffer,
119                                         final ParserCursor cursor) {
120
121        if (buffer == null) {
122            throw new IllegalArgumentException("Char array buffer may not be null");
123        }
124        if (cursor == null) {
125            throw new IllegalArgumentException("Parser cursor may not be null");
126        }
127
128        List elements = new ArrayList();
129        while (!cursor.atEnd()) {
130            HeaderElement element = parseHeaderElement(buffer, cursor);
131            if (!(element.getName().length() == 0 && element.getValue() == null)) {
132                elements.add(element);
133            }
134        }
135        return (HeaderElement[])
136            elements.toArray(new HeaderElement[elements.size()]);
137    }
138
139
140    /**
141     * Parses an element with the given parser.
142     *
143     * @param value     the header element to parse
144     * @param parser    the parser to use, or <code>null</code> for default
145     *
146     * @return  the parsed header element
147     */
148    public final static
149        HeaderElement parseHeaderElement(final String value,
150                                         HeaderValueParser parser)
151        throws ParseException {
152
153        if (value == null) {
154            throw new IllegalArgumentException
155                ("Value to parse may not be null");
156        }
157
158        if (parser == null)
159            parser = BasicHeaderValueParser.DEFAULT;
160
161        CharArrayBuffer buffer = new CharArrayBuffer(value.length());
162        buffer.append(value);
163        ParserCursor cursor = new ParserCursor(0, value.length());
164        return parser.parseHeaderElement(buffer, cursor);
165    }
166
167
168    // non-javadoc, see interface HeaderValueParser
169    public HeaderElement parseHeaderElement(final CharArrayBuffer buffer,
170                                            final ParserCursor cursor) {
171
172        if (buffer == null) {
173            throw new IllegalArgumentException("Char array buffer may not be null");
174        }
175        if (cursor == null) {
176            throw new IllegalArgumentException("Parser cursor may not be null");
177        }
178
179        NameValuePair nvp = parseNameValuePair(buffer, cursor);
180        NameValuePair[] params = null;
181        if (!cursor.atEnd()) {
182            char ch = buffer.charAt(cursor.getPos() - 1);
183            if (ch != ELEM_DELIMITER) {
184                params = parseParameters(buffer, cursor);
185            }
186        }
187        return createHeaderElement(nvp.getName(), nvp.getValue(), params);
188    }
189
190
191    /**
192     * Creates a header element.
193     * Called from {@link #parseHeaderElement}.
194     *
195     * @return  a header element representing the argument
196     */
197    protected HeaderElement createHeaderElement(
198            final String name,
199            final String value,
200            final NameValuePair[] params) {
201        return new BasicHeaderElement(name, value, params);
202    }
203
204
205    /**
206     * Parses parameters with the given parser.
207     *
208     * @param value     the parameter list to parse
209     * @param parser    the parser to use, or <code>null</code> for default
210     *
211     * @return  array holding the parameters, never <code>null</code>
212     */
213    public final static
214        NameValuePair[] parseParameters(final String value,
215                                        HeaderValueParser parser)
216        throws ParseException {
217
218        if (value == null) {
219            throw new IllegalArgumentException
220                ("Value to parse may not be null");
221        }
222
223        if (parser == null)
224            parser = BasicHeaderValueParser.DEFAULT;
225
226        CharArrayBuffer buffer = new CharArrayBuffer(value.length());
227        buffer.append(value);
228        ParserCursor cursor = new ParserCursor(0, value.length());
229        return parser.parseParameters(buffer, cursor);
230    }
231
232
233
234    // non-javadoc, see interface HeaderValueParser
235    public NameValuePair[] parseParameters(final CharArrayBuffer buffer,
236                                           final ParserCursor cursor) {
237
238        if (buffer == null) {
239            throw new IllegalArgumentException("Char array buffer may not be null");
240        }
241        if (cursor == null) {
242            throw new IllegalArgumentException("Parser cursor may not be null");
243        }
244
245        int pos = cursor.getPos();
246        int indexTo = cursor.getUpperBound();
247
248        while (pos < indexTo) {
249            char ch = buffer.charAt(pos);
250            if (HTTP.isWhitespace(ch)) {
251                pos++;
252            } else {
253                break;
254            }
255        }
256        cursor.updatePos(pos);
257        if (cursor.atEnd()) {
258            return new NameValuePair[] {};
259        }
260
261        List params = new ArrayList();
262        while (!cursor.atEnd()) {
263            NameValuePair param = parseNameValuePair(buffer, cursor);
264            params.add(param);
265            char ch = buffer.charAt(cursor.getPos() - 1);
266            if (ch == ELEM_DELIMITER) {
267                break;
268            }
269        }
270
271        return (NameValuePair[])
272            params.toArray(new NameValuePair[params.size()]);
273    }
274
275    /**
276     * Parses a name-value-pair with the given parser.
277     *
278     * @param value     the NVP to parse
279     * @param parser    the parser to use, or <code>null</code> for default
280     *
281     * @return  the parsed name-value pair
282     */
283    public final static
284       NameValuePair parseNameValuePair(final String value,
285                                        HeaderValueParser parser)
286        throws ParseException {
287
288        if (value == null) {
289            throw new IllegalArgumentException
290                ("Value to parse may not be null");
291        }
292
293        if (parser == null)
294            parser = BasicHeaderValueParser.DEFAULT;
295
296        CharArrayBuffer buffer = new CharArrayBuffer(value.length());
297        buffer.append(value);
298        ParserCursor cursor = new ParserCursor(0, value.length());
299        return parser.parseNameValuePair(buffer, cursor);
300    }
301
302
303    // non-javadoc, see interface HeaderValueParser
304    public NameValuePair parseNameValuePair(final CharArrayBuffer buffer,
305                                            final ParserCursor cursor) {
306        return parseNameValuePair(buffer, cursor, ALL_DELIMITERS);
307    }
308
309    private static boolean isOneOf(final char ch, final char[] chs) {
310        if (chs != null) {
311            for (int i = 0; i < chs.length; i++) {
312                if (ch == chs[i]) {
313                    return true;
314                }
315            }
316        }
317        return false;
318    }
319
320    public NameValuePair parseNameValuePair(final CharArrayBuffer buffer,
321                                            final ParserCursor cursor,
322                                            final char[] delimiters) {
323
324        if (buffer == null) {
325            throw new IllegalArgumentException("Char array buffer may not be null");
326        }
327        if (cursor == null) {
328            throw new IllegalArgumentException("Parser cursor may not be null");
329        }
330
331        boolean terminated = false;
332
333        int pos = cursor.getPos();
334        int indexFrom = cursor.getPos();
335        int indexTo = cursor.getUpperBound();
336
337        // Find name
338        String name = null;
339        while (pos < indexTo) {
340            char ch = buffer.charAt(pos);
341            if (ch == '=') {
342                break;
343            }
344            if (isOneOf(ch, delimiters)) {
345                terminated = true;
346                break;
347            }
348            pos++;
349        }
350
351        if (pos == indexTo) {
352            terminated = true;
353            name = buffer.substringTrimmed(indexFrom, indexTo);
354        } else {
355            name = buffer.substringTrimmed(indexFrom, pos);
356            pos++;
357        }
358
359        if (terminated) {
360            cursor.updatePos(pos);
361            return createNameValuePair(name, null);
362        }
363
364        // Find value
365        String value = null;
366        int i1 = pos;
367
368        boolean qouted = false;
369        boolean escaped = false;
370        while (pos < indexTo) {
371            char ch = buffer.charAt(pos);
372            if (ch == '"' && !escaped) {
373                qouted = !qouted;
374            }
375            if (!qouted && !escaped && isOneOf(ch, delimiters)) {
376                terminated = true;
377                break;
378            }
379            if (escaped) {
380                escaped = false;
381            } else {
382                escaped = qouted && ch == '\\';
383            }
384            pos++;
385        }
386
387        int i2 = pos;
388        // Trim leading white spaces
389        while (i1 < i2 && (HTTP.isWhitespace(buffer.charAt(i1)))) {
390            i1++;
391        }
392        // Trim trailing white spaces
393        while ((i2 > i1) && (HTTP.isWhitespace(buffer.charAt(i2 - 1)))) {
394            i2--;
395        }
396        // Strip away quotes if necessary
397        if (((i2 - i1) >= 2)
398            && (buffer.charAt(i1) == '"')
399            && (buffer.charAt(i2 - 1) == '"')) {
400            i1++;
401            i2--;
402        }
403        value = buffer.substring(i1, i2);
404        if (terminated) {
405            pos++;
406        }
407        cursor.updatePos(pos);
408        return createNameValuePair(name, value);
409    }
410
411    /**
412     * Creates a name-value pair.
413     * Called from {@link #parseNameValuePair}.
414     *
415     * @param name      the name
416     * @param value     the value, or <code>null</code>
417     *
418     * @return  a name-value pair representing the arguments
419     */
420    protected NameValuePair createNameValuePair(final String name, final String value) {
421        return new BasicNameValuePair(name, value);
422    }
423
424}
425
426