Source code: org/apache/http/HeaderElement.java
1 /*
2 * $HeadURL: https://svn.apache.org/repos/asf/jakarta/httpcomponents/httpcore/tags/4.0-alpha2/src/java/org/apache/http/HeaderElement.java $
3 * $Revision: 409980 $
4 * $Date: 2006-05-28 21:45:06 +0200 (Sun, 28 May 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.util.LangUtils;
37
38 /**
39 * <p>One element of an HTTP header's value.</p>
40 * <p>
41 * Some HTTP headers (such as the set-cookie header) have values that
42 * can be decomposed into multiple elements. Such headers must be in the
43 * following form:
44 * </p>
45 * <pre>
46 * header = [ element ] *( "," [ element ] )
47 * element = name [ "=" [ value ] ] *( ";" [ param ] )
48 * param = name [ "=" [ value ] ]
49 *
50 * name = token
51 * value = ( token | quoted-string )
52 *
53 * token = 1*<any char except "=", ",", ";", <"> and
54 * white space>
55 * quoted-string = <"> *( text | quoted-char ) <">
56 * text = any char except <">
57 * quoted-char = "\" char
58 * </pre>
59 * <p>
60 * Any amount of white space is allowed between any part of the
61 * header, element or param and is ignored. A missing value in any
62 * element or param will be stored as the empty {@link String};
63 * if the "=" is also missing <var>null</var> will be stored instead.
64 * </p>
65 * <p>
66 * This class represents an individual header element, containing
67 * both a name/value pair (value may be <tt>null</tt>) and optionally
68 * a set of additional parameters.
69 * </p>
70 * <p>
71 * This class also exposes a {@link #parse} method for parsing a
72 * {@link Header} value into an array of elements.
73 * </p>
74 *
75 * @see Header
76 *
77 * @author <a href="mailto:bcholmes@interlog.com">B.C. Holmes</a>
78 * @author <a href="mailto:jericho@thinkfree.com">Park, Sung-Gu</a>
79 * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
80 * @author <a href="mailto:oleg at ural.com">Oleg Kalnichevski</a>
81 *
82 * @since 1.0
83 * @version $Revision: 409980 $ $Date: 2006-05-28 21:45:06 +0200 (Sun, 28 May 2006) $
84 */
85 public class HeaderElement {
86
87 private final String name;
88 private final String value;
89 private final NameValuePair[] parameters;
90
91 private HeaderElement(final NameValuePair[] nvps) {
92 super();
93 if (nvps.length > 0) {
94 NameValuePair nvp = nvps[0];
95 this.name = nvp.getName();
96 this.value = nvp.getValue();
97 int len = nvps.length - 1;
98 if (len > 0) {
99 this.parameters = new NameValuePair[len];
100 System.arraycopy(nvps, 1, this.parameters, 0, len);
101 } else {
102 this.parameters = new NameValuePair[] {};
103 }
104 } else {
105 this.name = "";
106 this.value = null;
107 this.parameters = new NameValuePair[] {};
108 }
109 }
110
111 /**
112 * Constructor with name, value and parameters.
113 *
114 * @param name header element name
115 * @param value header element value. May be <tt>null</tt>
116 * @param parameters header element parameters. May be <tt>null</tt>
117 */
118 public HeaderElement(
119 final String name,
120 final String value,
121 final NameValuePair[] parameters) {
122 super();
123 if (name == null) {
124 throw new IllegalArgumentException("Name may not be null");
125 }
126 this.name = name;
127 this.value = value;
128 if (parameters != null) {
129 this.parameters = (NameValuePair[])parameters.clone();
130 } else {
131 this.parameters = new NameValuePair[] {};
132 }
133 }
134
135 /**
136 * Constructor with name and value.
137 *
138 * @param name header element name
139 * @param value header element value. May be <tt>null</tt>
140 */
141 public HeaderElement(final String name, final String value) {
142 this(name, value, null);
143 }
144
145 /**
146 * Returns the name.
147 *
148 * @return String name The name
149 */
150 public String getName() {
151 return this.name;
152 }
153
154 /**
155 * Returns the value.
156 *
157 * @return String value The current value.
158 */
159 public String getValue() {
160 return this.value;
161 }
162
163 /**
164 * Get parameters, if any.
165 *
166 * @since 2.0
167 * @return parameters as an array of {@link NameValuePair}s
168 */
169 public NameValuePair[] getParameters() {
170 return (NameValuePair[])this.parameters.clone();
171 }
172
173 // --------------------------------------------------------- Public Methods
174
175 /**
176 * This parses the value part of a header. The result is an array of
177 * HeaderElement objects.
178 *
179 * @param buffer the buffer from which to parse
180 * @param indexFrom where to start parsing in the buffer
181 * @param indexTo where to stop parsing in the buffer
182 *
183 * @return array of {@link HeaderElement}s.
184 *
185 * @since 3.0
186 */
187 public static final HeaderElement[] parseAll(
188 final CharArrayBuffer buffer, final int indexFrom, final int indexTo) {
189 if (buffer == null) {
190 throw new IllegalArgumentException("Char array buffer may not be null");
191 }
192 if (indexFrom < 0) {
193 throw new IndexOutOfBoundsException();
194 }
195 if (indexTo > buffer.length()) {
196 throw new IndexOutOfBoundsException();
197 }
198 if (indexFrom > indexTo) {
199 throw new IndexOutOfBoundsException();
200 }
201 List elements = new ArrayList();
202 int cur = indexFrom;
203 int from = indexFrom;
204 boolean qouted = false;
205 boolean escaped = false;
206 while (cur < indexTo) {
207 char ch = buffer.charAt(cur);
208 if (ch == '"' && !escaped) {
209 qouted = !qouted;
210 }
211 HeaderElement element = null;
212 if ((!qouted) && (ch == ',')) {
213 element = parse(buffer, from, cur);
214 from = cur + 1;
215 } else if (cur == indexTo - 1) {
216 element = parse(buffer, from, indexTo);
217 }
218 if (element != null && !(element.getName().equals("") && element.getValue() == null)) {
219 elements.add(element);
220 }
221 if (escaped) {
222 escaped = false;
223 } else {
224 escaped = qouted && ch == '\\';
225 }
226 cur++;
227 }
228 return (HeaderElement[])
229 elements.toArray(new HeaderElement[elements.size()]);
230 }
231
232 /**
233 * This parses the value part of a header. The result is an array of
234 * HeaderElement objects.
235 *
236 * @param s the string representation of the header value
237 * (as received from the web server).
238 * @return array of {@link HeaderElement}s.
239 *
240 * @since 3.0
241 */
242 public static final HeaderElement[] parseAll(final String s) {
243 if (s == null) {
244 throw new IllegalArgumentException("String may not be null");
245 }
246 CharArrayBuffer buffer = new CharArrayBuffer(s.length());
247 buffer.append(s);
248 return parseAll(buffer, 0, buffer.length());
249 }
250
251 public static HeaderElement parse(
252 final CharArrayBuffer buffer, final int indexFrom, final int indexTo) {
253 if (buffer == null) {
254 throw new IllegalArgumentException("Char array buffer may not be null");
255 }
256 if (indexFrom < 0) {
257 throw new IndexOutOfBoundsException();
258 }
259 if (indexTo > buffer.length()) {
260 throw new IndexOutOfBoundsException();
261 }
262 if (indexFrom > indexTo) {
263 throw new IndexOutOfBoundsException();
264 }
265 NameValuePair[] nvps = NameValuePair.parseAll(buffer, indexFrom, indexTo);
266 return new HeaderElement(nvps);
267 }
268
269 public static final HeaderElement parse(final String s) {
270 if (s == null) {
271 throw new IllegalArgumentException("String may not be null");
272 }
273 CharArrayBuffer buffer = new CharArrayBuffer(s.length());
274 buffer.append(s);
275 return parse(buffer, 0, buffer.length());
276 }
277
278 public static void format(
279 final CharArrayBuffer buffer,
280 final HeaderElement element) {
281 if (buffer == null) {
282 throw new IllegalArgumentException("String buffer may not be null");
283 }
284 if (element == null) {
285 throw new IllegalArgumentException("Header element may not be null");
286 }
287 buffer.append(element.getName());
288 if (element.getValue() != null) {
289 buffer.append("=");
290 buffer.append(element.getValue());
291 }
292 NameValuePair[] params = element.getParameters();
293 for (int i = 0; i < params.length; i++) {
294 buffer.append("; ");
295 NameValuePair.format(buffer, params[i], false);
296 }
297 }
298
299 public static String format(final HeaderElement element) {
300 CharArrayBuffer buffer = new CharArrayBuffer(32);
301 format(buffer, element);
302 return buffer.toString();
303 }
304
305 public static void formatAll(
306 final CharArrayBuffer buffer,
307 final HeaderElement[] elements) {
308 if (buffer == null) {
309 throw new IllegalArgumentException("String buffer may not be null");
310 }
311 if (elements == null) {
312 throw new IllegalArgumentException("Array of header element may not be null");
313 }
314 for (int i = 0; i < elements.length; i++) {
315 if (i > 0) {
316 buffer.append(", ");
317 }
318 format(buffer, elements[i]);
319 }
320 }
321
322 public static String formatAll(final HeaderElement[] elements) {
323 CharArrayBuffer buffer = new CharArrayBuffer(64);
324 formatAll(buffer, elements);
325 return buffer.toString();
326 }
327
328 /**
329 * Returns parameter with the given name, if found. Otherwise null
330 * is returned
331 *
332 * @param name The name to search by.
333 * @return NameValuePair parameter with the given name
334 */
335 public NameValuePair getParameterByName(final String name) {
336 if (name == null) {
337 throw new IllegalArgumentException("Name may not be null");
338 }
339 NameValuePair found = null;
340 for (int i = 0; i < this.parameters.length; i++) {
341 NameValuePair current = this.parameters[ i ];
342 if (current.getName().equalsIgnoreCase(name)) {
343 found = current;
344 break;
345 }
346 }
347 return found;
348 }
349
350 public boolean equals(final Object object) {
351 if (object == null) return false;
352 if (this == object) return true;
353 if (object instanceof HeaderElement) {
354 HeaderElement that = (HeaderElement) object;
355 return this.name.equals(that.name)
356 && LangUtils.equals(this.value, that.value)
357 && LangUtils.equals(this.parameters, that.parameters);
358 } else {
359 return false;
360 }
361 }
362
363 public int hashCode() {
364 int hash = LangUtils.HASH_SEED;
365 hash = LangUtils.hashCode(hash, this.name);
366 hash = LangUtils.hashCode(hash, this.value);
367 for (int i = 0; i < this.parameters.length; i++) {
368 hash = LangUtils.hashCode(hash, this.parameters[i]);
369 }
370 return hash;
371 }
372
373 public String toString() {
374 CharArrayBuffer buffer = new CharArrayBuffer(64);
375 buffer.append(this.name);
376 if (this.value != null) {
377 buffer.append("=");
378 buffer.append(this.value);
379 }
380 for (int i = 0; i < this.parameters.length; i++) {
381 buffer.append("; ");
382 buffer.append(this.parameters[i]);
383 }
384 return buffer.toString();
385 }
386
387 }
388