Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/http/NameValuePair.java


1   /*
2    * $HeadURL: https://svn.apache.org/repos/asf/jakarta/httpcomponents/httpcore/tags/4.0-alpha2/src/java/org/apache/http/NameValuePair.java $
3    * $Revision: 376961 $
4    * $Date: 2006-02-11 11:32:50 +0100 (Sat, 11 Feb 2006) $
5    *
6    * ====================================================================
7    *
8    *  Copyright 1999-2006 The Apache Software Foundation
9    *
10   *  Licensed under the Apache License, Version 2.0 (the "License");
11   *  you may not use this file except in compliance with the License.
12   *  You may obtain a copy of the License at
13   *
14   *      http://www.apache.org/licenses/LICENSE-2.0
15   *
16   *  Unless required by applicable law or agreed to in writing, software
17   *  distributed under the License is distributed on an "AS IS" BASIS,
18   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19   *  See the License for the specific language governing permissions and
20   *  limitations under the License.
21   * ====================================================================
22   *
23   * This software consists of voluntary contributions made by many
24   * individuals on behalf of the Apache Software Foundation.  For more
25   * information on the Apache Software Foundation, please see
26   * <http://www.apache.org/>.
27   *
28   */
29  
30  package org.apache.http;
31  
32  import java.util.ArrayList;
33  import java.util.List;
34  
35  import org.apache.http.io.CharArrayBuffer;
36  import org.apache.http.protocol.HTTP;
37  import org.apache.http.util.LangUtils;
38  
39  /**
40   * A simple class encapsulating an attribute/value pair.
41   * <p>
42   *  This class comforms to the generic grammar and formatting rules outlined in the 
43   *  <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2">Section 2.2</a>
44   *  and  
45   *  <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6">Section 3.6</a>
46   *  of <a href="http://www.w3.org/Protocols/rfc2616/rfc2616.txt">RFC 2616</a>
47   * </p>
48   * <h>2.2 Basic Rules</h>
49   * <p>
50   *  The following rules are used throughout this specification to describe basic parsing constructs. 
51   *  The US-ASCII coded character set is defined by ANSI X3.4-1986.
52   * </p>
53   * <pre>
54   *     OCTET          = <any 8-bit sequence of data>
55   *     CHAR           = <any US-ASCII character (octets 0 - 127)>
56   *     UPALPHA        = <any US-ASCII uppercase letter "A".."Z">
57   *     LOALPHA        = <any US-ASCII lowercase letter "a".."z">
58   *     ALPHA          = UPALPHA | LOALPHA
59   *     DIGIT          = <any US-ASCII digit "0".."9">
60   *     CTL            = <any US-ASCII control character
61   *                      (octets 0 - 31) and DEL (127)>
62   *     CR             = <US-ASCII CR, carriage return (13)>
63   *     LF             = <US-ASCII LF, linefeed (10)>
64   *     SP             = <US-ASCII SP, space (32)>
65   *     HT             = <US-ASCII HT, horizontal-tab (9)>
66   *     <">            = <US-ASCII double-quote mark (34)>
67   * </pre>
68   * <p>
69   *  Many HTTP/1.1 header field values consist of words separated by LWS or special 
70   *  characters. These special characters MUST be in a quoted string to be used within 
71   *  a parameter value (as defined in section 3.6).
72   * <p>
73   * <pre>
74   * token          = 1*<any CHAR except CTLs or separators>
75   * separators     = "(" | ")" | "<" | ">" | "@"
76   *                | "," | ";" | ":" | "\" | <">
77   *                | "/" | "[" | "]" | "?" | "="
78   *                | "{" | "}" | SP | HT
79   * </pre>
80   * <p>
81   *  A string of text is parsed as a single word if it is quoted using double-quote marks.
82   * </p>
83   * <pre>
84   * quoted-string  = ( <"> *(qdtext | quoted-pair ) <"> )
85   * qdtext         = <any TEXT except <">>
86   * </pre>
87   * <p>
88   *  The backslash character ("\") MAY be used as a single-character quoting mechanism only 
89   *  within quoted-string and comment constructs.
90   * </p>
91   * <pre>
92   * quoted-pair    = "\" CHAR
93   * </pre>
94   * <h>3.6 Transfer Codings</h>
95   * <p>
96   *  Parameters are in the form of attribute/value pairs.
97   * </p>
98   * <pre>
99   * parameter               = attribute "=" value
100  * attribute               = token
101  * value                   = token | quoted-string
102  * </pre> 
103  * 
104  * @author <a href="mailto:oleg at ural.com">Oleg Kalnichevski</a>
105  * 
106  */
107 public class NameValuePair {
108 
109     private final String name;
110     private final String value;
111 
112     /**
113      * Default Constructor taking a name and a value. The value may be null.
114      * 
115      * @param name The name.
116      * @param value The value.
117      */
118     public NameValuePair(final String name, final String value) {
119         super();
120         if (name == null) {
121             throw new IllegalArgumentException("Name may not be null");
122         }
123         this.name = name;
124         this.value = value;
125     }
126 
127     /**
128      * Returns the name.
129      *
130      * @return String name The name
131      */
132     public String getName() {
133         return this.name;
134     }
135 
136     /**
137      * Returns the value.
138      *
139      * @return String value The current value.
140      */
141     public String getValue() {
142         return this.value;
143     }
144 
145     public static final NameValuePair[] parseAll(
146             final CharArrayBuffer buffer, final int indexFrom, final int indexTo) {
147         if (buffer == null) {
148             throw new IllegalArgumentException("Char array buffer may not be null");
149         }
150         if (indexFrom < 0) {
151             throw new IndexOutOfBoundsException();
152         }
153         if (indexTo > buffer.length()) {
154             throw new IndexOutOfBoundsException();
155         }
156         if (indexFrom > indexTo) {
157             throw new IndexOutOfBoundsException();
158         }
159         List params = new ArrayList(); 
160         int cur = indexFrom;
161         int from = indexFrom;
162         boolean qouted = false;
163         boolean escaped = false;
164         while (cur < indexTo) {
165             char ch = buffer.charAt(cur);
166             if (ch == '"' && !escaped) {
167                 qouted = !qouted;
168             }
169             NameValuePair param = null;
170             if (!qouted && ch == ';') {
171                 param = parse(buffer, from, cur);
172                 from = cur + 1;
173             } else if (cur == indexTo - 1) {
174                 param = parse(buffer, from, indexTo);
175             }
176             if (param != null && !(param.getName().equals("") && param.getValue() == null)) {
177                 params.add(param);
178             }
179             if (escaped) {
180                 escaped = false;
181             } else {
182                 escaped = qouted && ch == '\\';
183             }
184             cur++;
185         }
186         return (NameValuePair[]) params.toArray(new NameValuePair[params.size()]);
187     }
188     
189     public static final NameValuePair[] parseAll(final String s) {
190         if (s == null) {
191             throw new IllegalArgumentException("String may not be null");
192         }
193         CharArrayBuffer buffer = new CharArrayBuffer(s.length());
194         buffer.append(s);
195         return parseAll(buffer, 0, buffer.length());
196     }
197 
198     public static NameValuePair parse(
199             final CharArrayBuffer buffer, final int indexFrom, final int indexTo) {
200         if (buffer == null) {
201             throw new IllegalArgumentException("Char array buffer may not be null");
202         }
203         if (indexFrom < 0) {
204             throw new IndexOutOfBoundsException();
205         }
206         if (indexTo > buffer.length()) {
207             throw new IndexOutOfBoundsException();
208         }
209         if (indexFrom > indexTo) {
210             throw new IndexOutOfBoundsException();
211         }
212         int eq = buffer.indexOf('=', indexFrom, indexTo);
213         if (eq < 0) {
214             return new NameValuePair(buffer.substringTrimmed(indexFrom, indexTo), null);
215         }
216         String name = buffer.substringTrimmed(indexFrom, eq);
217         int i1 = eq + 1;
218         int i2 = indexTo;
219         // Trim leading white spaces
220         while (i1 < i2 && (HTTP.isWhitespace(buffer.charAt(i1)))) {
221             i1++;
222         }
223         // Trim trailing white spaces
224         while ((i2 > i1) && (HTTP.isWhitespace(buffer.charAt(i2 - 1)))) {
225             i2--;
226         }
227         // Strip away quotes if necessary
228         if (((i2 - i1) >= 2) 
229             && (buffer.charAt(i1) == '"') 
230             && (buffer.charAt(i2 - 1) == '"')) {
231             i1++;
232             i2--;
233         }
234         String value = buffer.substring(i1, i2);
235         return new NameValuePair(name, value);
236     }
237 
238     public static final NameValuePair parse(final String s) {
239         if (s == null) {
240             throw new IllegalArgumentException("String may not be null");
241         }
242         CharArrayBuffer buffer = new CharArrayBuffer(s.length());
243         buffer.append(s);
244         return parse(buffer, 0, buffer.length());
245     }
246 
247     /**
248      * Special characters that can be used as separators in HTTP parameters.
249      * These special characters MUST be in a quoted string to be used within
250      * a parameter value 
251      */
252     private static final char[] SEPARATORS   = {
253             '(', ')', '<', '>', '@', 
254             ',', ';', ':', '\\', '"', 
255             '/', '[', ']', '?', '=',
256             '{', '}', ' ', '\t'
257             };
258     
259     /**
260      * Unsafe special characters that must be escaped using the backslash
261      * character
262      */
263     private static final char[] UNSAFE_CHARS = {
264             '"', '\\'
265             };
266     
267     private static boolean isOneOf(char[] chars, char ch) {
268         for (int i = 0; i < chars.length; i++) {
269             if (ch == chars[i]) {
270                 return true;
271             }
272         }
273         return false;
274     }
275     
276     private static boolean isUnsafeChar(char ch) {
277         return isOneOf(UNSAFE_CHARS, ch);
278     }
279     
280     private static boolean isSeparator(char ch) {
281         return isOneOf(SEPARATORS, ch);
282     }
283 
284     private static void format(
285             final CharArrayBuffer buffer, 
286             final String value, 
287             boolean alwaysUseQuotes) {
288         boolean unsafe = false;
289         if (alwaysUseQuotes) {
290             unsafe = true;
291         } else {
292             for (int i = 0; i < value.length(); i++) {
293                 if (isSeparator(value.charAt(i))) {
294                     unsafe = true;
295                     break;
296                 }
297             }
298         }
299         if (unsafe) buffer.append('"');
300         for (int i = 0; i < value.length(); i++) {
301             char ch = value.charAt(i);
302             if (isUnsafeChar(ch)) {
303                 buffer.append('\\');
304             }
305             buffer.append(ch);
306         }
307         if (unsafe) buffer.append('"');
308     }
309     
310     /**
311      * Produces textual representaion of the attribute/value pair using 
312      * formatting rules defined in RFC 2616
313      *  
314      * @param buffer output buffer 
315      * @param param the parameter to be formatted
316      * @param alwaysUseQuotes <tt>true</tt> if the parameter values must 
317      * always be enclosed in quotation marks, <tt>false</tt> otherwise
318      */
319     public static void format(
320             final CharArrayBuffer buffer, 
321             final NameValuePair param, 
322             boolean alwaysUseQuotes) {
323         if (buffer == null) {
324             throw new IllegalArgumentException("String buffer may not be null");
325         }
326         if (param == null) {
327             throw new IllegalArgumentException("Parameter may not be null");
328         }
329         buffer.append(param.getName());
330         String value = param.getValue();
331         if (value != null) {
332             buffer.append("=");
333             format(buffer, value, alwaysUseQuotes);
334         }
335     }
336     
337     /**
338      * Produces textual representaion of the attribute/value pairs using 
339      * formatting rules defined in RFC 2616
340      *  
341      * @param buffer output buffer 
342      * @param params the parameters to be formatted
343      * @param alwaysUseQuotes <tt>true</tt> if the parameter values must 
344      * always be enclosed in quotation marks, <tt>false</tt> otherwise
345      */
346     public static void formatAll(
347             final CharArrayBuffer buffer, 
348             final NameValuePair[] params, 
349             boolean alwaysUseQuotes) {
350         if (buffer == null) {
351             throw new IllegalArgumentException("String buffer may not be null");
352         }
353         if (params == null) {
354             throw new IllegalArgumentException("Array of parameter may not be null");
355         }
356         for (int i = 0; i < params.length; i++) {
357             if (i > 0) {
358                 buffer.append("; ");
359             }
360             format(buffer, params[i], alwaysUseQuotes);
361         }
362     }
363     
364     /**
365      * Produces textual representaion of the attribute/value pair using 
366      * formatting rules defined in RFC 2616
367      *  
368      * @param param the parameter to be formatted
369      * @param alwaysUseQuotes <tt>true</tt> if the parameter values must 
370      * always be enclosed in quotation marks, <tt>false</tt> otherwise
371      * 
372      * @return RFC 2616 conformant textual representaion of the 
373      * attribute/value pair
374      */
375     public static String format(final NameValuePair param, boolean alwaysUseQuotes) {
376         CharArrayBuffer buffer = new CharArrayBuffer(16);
377         format(buffer, param, alwaysUseQuotes);
378         return buffer.toString();
379     }
380     
381     /**
382      * Produces textual representaion of the attribute/value pair using 
383      * formatting rules defined in RFC 2616
384      *  
385      * @param params the parameters to be formatted
386      * @param alwaysUseQuotes <tt>true</tt> if the parameter values must 
387      * always be enclosed in quotation marks, <tt>false</tt> otherwise
388      * 
389      * @return RFC 2616 conformant textual representaion of the 
390      * attribute/value pair
391      */
392     public static String formatAll(final NameValuePair[] params, boolean alwaysUseQuotes) {
393         CharArrayBuffer buffer = new CharArrayBuffer(16);
394         formatAll(buffer, params, alwaysUseQuotes);
395         return buffer.toString();
396     }
397     
398     /**
399      * Get a string representation of this pair.
400      * 
401      * @return A string representation.
402      */
403     public String toString() {
404         CharArrayBuffer buffer = new CharArrayBuffer(16);
405         buffer.append(this.name);
406         if (this.value != null) {
407             buffer.append("=");
408             format(buffer, this.value, false);
409         }
410         return buffer.toString();
411     }
412 
413     public boolean equals(final Object object) {
414         if (object == null) return false;
415         if (this == object) return true;
416         if (object instanceof NameValuePair) {
417             NameValuePair that = (NameValuePair) object;
418             return this.name.equals(that.name)
419                   && LangUtils.equals(this.value, that.value);
420         } else {
421             return false;
422         }
423     }
424 
425     public int hashCode() {
426         int hash = LangUtils.HASH_SEED;
427         hash = LangUtils.hashCode(hash, this.name);
428         hash = LangUtils.hashCode(hash, this.value);
429         return hash;
430     }
431     
432 }