2 Copyright (C) 2004, 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package gnu
.java
.net
.protocol
.http
;
41 import gnu
.java
.lang
.CPStringBuilder
;
43 import gnu
.java
.net
.LineInputStream
;
45 import java
.io
.IOException
;
46 import java
.io
.InputStream
;
47 import java
.lang
.Iterable
;
48 import java
.text
.DateFormat
;
49 import java
.text
.ParseException
;
50 import java
.util
.ArrayList
;
51 import java
.util
.Collections
;
52 import java
.util
.Date
;
53 import java
.util
.Iterator
;
54 import java
.util
.LinkedHashMap
;
55 import java
.util
.List
;
59 * A collection of HTTP header names and associated values. The
60 * values are {@link ArrayList ArrayLists} of Strings. Retrieval of
61 * values is case insensitive. An iteration over the collection
62 * returns the header names in the order they were received.
64 * @author Chris Burdess (dog@gnu.org)
65 * @author David Daney (ddaney@avtrex.com)
67 class Headers
implements Iterable
<Headers
.HeaderElement
>
70 * A list of HeaderElements
72 private final ArrayList
<HeaderElement
> headers
73 = new ArrayList
<HeaderElement
>();
76 * The HTTP dateformat used to parse date header fields.
78 private static final DateFormat dateFormat
= new HTTPDateFormat();
81 * Class for a Header element consisting of
82 * a name and value String.
84 static class HeaderElement
89 HeaderElement(String name
, String value
)
97 * Default constructor.
105 * Return an Iterator over this collection of headers.
106 * Iterator.getNext() returns objects of type {@link HeaderElement}.
108 * @return the Iterator.
110 public Iterator
<HeaderElement
> iterator()
112 return headers
.iterator();
116 * Returns the value of the specified header as a string. If
117 * multiple values are present, the last one is returned.
119 * @param header the header name (case insensitive search)
120 * @return The header value or <code>null</code> if not found.
122 public String
getValue(String header
)
124 for (int i
= headers
.size() - 1; i
>= 0; i
--)
126 HeaderElement e
= headers
.get(i
);
127 if (e
.name
.equalsIgnoreCase(header
))
136 * Returns the value of the specified header as an integer. If
137 * multiple values are present, the last one is returned.
139 * @param header the header name (case insensitive search)
140 * @return The header value or <code>-1</code> if not present or
141 * not an integer value.
143 public int getIntValue(String header
)
145 String val
= getValue(header
);
152 return Integer
.parseInt(val
);
154 catch (NumberFormatException e
)
162 * Returns the value of the specified header as a long. If
163 * multiple values are present, the last one is returned.
165 * @param header the header name (case insensitive search)
166 * @return The header value or <code>-1</code> if not present or
169 public long getLongValue(String header
)
171 String val
= getValue(header
);
178 return Long
.parseLong(val
);
180 catch (NumberFormatException e
)
188 * Returns the value of the specified header as a date. If
189 * multiple values are present, the last one is returned.
191 * @param header the header name (case insensitive search)
192 * @return The header value or <code>null</code> if not present or
195 public Date
getDateValue(String header
)
197 String val
= getValue(header
);
204 return dateFormat
.parse(val
);
206 catch (ParseException e
)
213 * Add a header to this set of headers. If there is an existing
214 * header with the same name it's value is replaced with the new value.
215 * If multiple headers of the same name exist only the last one's value
218 * @param name the header name
219 * @param value the header value
221 * @see #addValue(String, String)
223 public void put(String name
, String value
)
225 for (int i
= headers
.size() - 1; i
>= 0; i
--)
227 HeaderElement e
= headers
.get(i
);
228 if (e
.name
.equalsIgnoreCase(name
))
235 // nothing was replaced so add it as new HeaderElement
236 addValue(name
, value
);
240 * Add all headers from a set of headers to this set. Any existing header
241 * with the same (case insensitive) name as one of the new headers will
244 * @param o the headers to be added
246 public void putAll(Headers o
)
248 for (Iterator
<HeaderElement
> it
= o
.iterator(); it
.hasNext(); )
250 HeaderElement e
= it
.next();
252 addValue(e
.name
, e
.value
);
257 * Remove a header from this set of headers. If there is more than
258 * one instance of a header of the given name, they are all removed.
260 * @param name the header name
262 public void remove(String name
)
264 for (Iterator
<HeaderElement
> it
= headers
.iterator(); it
.hasNext(); )
266 HeaderElement e
= it
.next();
267 if (e
.name
.equalsIgnoreCase(name
))
273 * Parse the specified InputStream, adding headers to this collection.
275 * @param in the InputStream.
276 * @throws IOException if I/O error occured.
278 public void parse(InputStream in
)
281 LineInputStream lin
= (in
instanceof LineInputStream
) ?
282 (LineInputStream
) in
: new LineInputStream(in
);
285 CPStringBuilder value
= new CPStringBuilder();
288 String line
= lin
.readLine();
293 addValue(name
, value
.toString());
297 int len
= line
.length();
302 addValue(name
, value
.toString());
306 char c1
= line
.charAt(0);
307 if (c1
== ' ' || c1
== '\t')
311 if (line
.charAt(last
) != '\r')
313 value
.append(line
.substring(0, last
));
319 addValue(name
, value
.toString());
322 int di
= line
.indexOf(':');
323 name
= line
.substring(0, di
);
329 while (di
< len
&& line
.charAt(di
) == ' ');
331 if (line
.charAt(last
) != '\r')
333 value
.append(line
.substring(di
, last
));
340 * Add a header to this set of headers. If there is an existing
341 * header with the same name, it is not effected.
343 * @param name the header name
344 * @param value the header value
346 * @see #put(String, String)
348 public void addValue(String name
, String value
)
350 headers
.add(headers
.size(), new HeaderElement(name
, value
));
354 * Get a new Map containing all the headers. The keys of the Map
355 * are Strings (the header names). The headers will be included
356 * case-sensitive in the map so that querying must be done with the
357 * correct case of the needed header name. The values of the Map are
358 * unmodifiable Lists containing Strings (the header values).
361 * The returned map is modifiable. Changing it will not effect this
362 * collection of Headers in any way.</p>
364 * @return a Map containing all the headers.
366 public Map
<String
,List
<String
>> getAsMap()
368 LinkedHashMap
<String
,List
<String
>> m
= new LinkedHashMap
<String
,List
<String
>>();
369 for (Iterator
<HeaderElement
> it
= headers
.iterator(); it
.hasNext(); )
371 HeaderElement e
= it
.next();
372 ArrayList
<String
> l
= (ArrayList
<String
>)m
.get(e
.name
);
375 l
= new ArrayList
<String
>(1);
382 for (Iterator
<Map
.Entry
<String
,List
<String
>>> it
= m
.entrySet().iterator(); it
.hasNext(); )
384 Map
.Entry
<String
,List
<String
>> me
= it
.next();
385 List
<String
> l
= me
.getValue();
386 me
.setValue(Collections
.unmodifiableList(l
));
392 * Get the name of the Nth header.
394 * @param i the header index.
396 * @return The header name, or <code>null</code> if index outside of range.
398 * @see #getHeaderValue(int)
400 public String
getHeaderName(int i
)
402 if (i
>= headers
.size() || i
< 0)
405 return headers
.get(i
).name
;
409 * Get the value of the Nth header.
411 * @param i the header index.
413 * @return the header value, or <code>null</code> if index outside of range.
415 * @see #getHeaderName(int)
417 public String
getHeaderValue(int i
)
419 if (i
>= headers
.size() || i
< 0)
422 return headers
.get(i
).value
;