summaryrefslogtreecommitdiff
path: root/libjava/classpath/gnu/java/net/protocol/http/Headers.java
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/classpath/gnu/java/net/protocol/http/Headers.java')
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/Headers.java424
1 files changed, 424 insertions, 0 deletions
diff --git a/libjava/classpath/gnu/java/net/protocol/http/Headers.java b/libjava/classpath/gnu/java/net/protocol/http/Headers.java
new file mode 100644
index 000000000..faf5eb195
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/Headers.java
@@ -0,0 +1,424 @@
+/* Headers.java --
+ Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.java.net.protocol.http;
+
+import gnu.java.lang.CPStringBuilder;
+
+import gnu.java.net.LineInputStream;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.Iterable;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A collection of HTTP header names and associated values. The
+ * values are {@link ArrayList ArrayLists} of Strings. Retrieval of
+ * values is case insensitive. An iteration over the collection
+ * returns the header names in the order they were received.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ * @author David Daney (ddaney@avtrex.com)
+ */
+class Headers implements Iterable<Headers.HeaderElement>
+{
+ /**
+ * A list of HeaderElements
+ */
+ private final ArrayList<HeaderElement> headers
+ = new ArrayList<HeaderElement>();
+
+ /**
+ * The HTTP dateformat used to parse date header fields.
+ */
+ private static final DateFormat dateFormat = new HTTPDateFormat();
+
+ /**
+ * Class for a Header element consisting of
+ * a name and value String.
+ */
+ static class HeaderElement
+ {
+ String name;
+ String value;
+
+ HeaderElement(String name, String value)
+ {
+ this.name = name;
+ this.value = value;
+ }
+ }
+
+ /**
+ * Default constructor.
+ */
+ public Headers()
+ {
+ // nothing to do
+ }
+
+ /**
+ * Return an Iterator over this collection of headers.
+ * Iterator.getNext() returns objects of type {@link HeaderElement}.
+ *
+ * @return the Iterator.
+ */
+ public Iterator<HeaderElement> iterator()
+ {
+ return headers.iterator();
+ }
+
+ /**
+ * Returns the value of the specified header as a string. If
+ * multiple values are present, the last one is returned.
+ *
+ * @param header the header name (case insensitive search)
+ * @return The header value or <code>null</code> if not found.
+ */
+ public String getValue(String header)
+ {
+ for (int i = headers.size() - 1; i >= 0; i--)
+ {
+ HeaderElement e = headers.get(i);
+ if (e.name.equalsIgnoreCase(header))
+ {
+ return e.value;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the value of the specified header as an integer. If
+ * multiple values are present, the last one is returned.
+ *
+ * @param header the header name (case insensitive search)
+ * @return The header value or <code>-1</code> if not present or
+ * not an integer value.
+ */
+ public int getIntValue(String header)
+ {
+ String val = getValue(header);
+ if (val == null)
+ {
+ return -1;
+ }
+ try
+ {
+ return Integer.parseInt(val);
+ }
+ catch (NumberFormatException e)
+ {
+ // fall through
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the value of the specified header as a long. If
+ * multiple values are present, the last one is returned.
+ *
+ * @param header the header name (case insensitive search)
+ * @return The header value or <code>-1</code> if not present or
+ * not a long value.
+ */
+ public long getLongValue(String header)
+ {
+ String val = getValue(header);
+ if (val == null)
+ {
+ return -1;
+ }
+ try
+ {
+ return Long.parseLong(val);
+ }
+ catch (NumberFormatException e)
+ {
+ // fall through
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the value of the specified header as a date. If
+ * multiple values are present, the last one is returned.
+ *
+ * @param header the header name (case insensitive search)
+ * @return The header value or <code>null</code> if not present or
+ * not a date value.
+ */
+ public Date getDateValue(String header)
+ {
+ String val = getValue(header);
+ if (val == null)
+ {
+ return null;
+ }
+ try
+ {
+ return dateFormat.parse(val);
+ }
+ catch (ParseException e)
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Add a header to this set of headers. If there is an existing
+ * header with the same name it's value is replaced with the new value.
+ * If multiple headers of the same name exist only the last one's value
+ * is replaced.
+ *
+ * @param name the header name
+ * @param value the header value
+ *
+ * @see #addValue(String, String)
+ */
+ public void put(String name, String value)
+ {
+ for (int i = headers.size() - 1; i >= 0; i--)
+ {
+ HeaderElement e = headers.get(i);
+ if (e.name.equalsIgnoreCase(name))
+ {
+ e.value = value;
+ return;
+ }
+ }
+
+ // nothing was replaced so add it as new HeaderElement
+ addValue(name, value);
+ }
+
+ /**
+ * Add all headers from a set of headers to this set. Any existing header
+ * with the same (case insensitive) name as one of the new headers will
+ * be overridden.
+ *
+ * @param o the headers to be added
+ */
+ public void putAll(Headers o)
+ {
+ for (Iterator<HeaderElement> it = o.iterator(); it.hasNext(); )
+ {
+ HeaderElement e = it.next();
+ remove(e.name);
+ addValue(e.name, e.value);
+ }
+ }
+
+ /**
+ * Remove a header from this set of headers. If there is more than
+ * one instance of a header of the given name, they are all removed.
+ *
+ * @param name the header name
+ */
+ public void remove(String name)
+ {
+ for (Iterator<HeaderElement> it = headers.iterator(); it.hasNext(); )
+ {
+ HeaderElement e = it.next();
+ if (e.name.equalsIgnoreCase(name))
+ it.remove();
+ }
+ }
+
+ /**
+ * Parse the specified InputStream, adding headers to this collection.
+ *
+ * @param in the InputStream.
+ * @throws IOException if I/O error occured.
+ */
+ public void parse(InputStream in)
+ throws IOException
+ {
+ LineInputStream lin = (in instanceof LineInputStream) ?
+ (LineInputStream) in : new LineInputStream(in);
+
+ String name = null;
+ CPStringBuilder value = new CPStringBuilder();
+ while (true)
+ {
+ String line = lin.readLine();
+ if (line == null)
+ {
+ if (name != null)
+ {
+ addValue(name, value.toString());
+ }
+ break;
+ }
+ int len = line.length();
+ if (len < 2)
+ {
+ if (name != null)
+ {
+ addValue(name, value.toString());
+ }
+ break;
+ }
+ char c1 = line.charAt(0);
+ if (c1 == ' ' || c1 == '\t')
+ {
+ // Continuation
+ int last = len - 1;
+ if (line.charAt(last) != '\r')
+ ++last;
+ value.append(line.substring(0, last));
+ }
+ else
+ {
+ if (name != null)
+ {
+ addValue(name, value.toString());
+ }
+
+ int di = line.indexOf(':');
+ name = line.substring(0, di);
+ value.setLength(0);
+ do
+ {
+ di++;
+ }
+ while (di < len && line.charAt(di) == ' ');
+ int last = len - 1;
+ if (line.charAt(last) != '\r')
+ ++last;
+ value.append(line.substring(di, last));
+ }
+ }
+ }
+
+
+ /**
+ * Add a header to this set of headers. If there is an existing
+ * header with the same name, it is not effected.
+ *
+ * @param name the header name
+ * @param value the header value
+ *
+ * @see #put(String, String)
+ */
+ public void addValue(String name, String value)
+ {
+ headers.add(headers.size(), new HeaderElement(name, value));
+ }
+
+ /**
+ * Get a new Map containing all the headers. The keys of the Map
+ * are Strings (the header names). The headers will be included
+ * case-sensitive in the map so that querying must be done with the
+ * correct case of the needed header name. The values of the Map are
+ * unmodifiable Lists containing Strings (the header values).
+ *
+ * <p>
+ * The returned map is modifiable. Changing it will not effect this
+ * collection of Headers in any way.</p>
+ *
+ * @return a Map containing all the headers.
+ */
+ public Map<String,List<String>> getAsMap()
+ {
+ LinkedHashMap<String,List<String>> m = new LinkedHashMap<String,List<String>>();
+ for (Iterator<HeaderElement> it = headers.iterator(); it.hasNext(); )
+ {
+ HeaderElement e = it.next();
+ ArrayList<String> l = (ArrayList<String>)m.get(e.name);
+ if (l == null)
+ {
+ l = new ArrayList<String>(1);
+ l.add(e.value);
+ m.put(e.name, l);
+ }
+ else
+ l.add(0, e.value);
+ }
+ for (Iterator<Map.Entry<String,List<String>>> it = m.entrySet().iterator(); it.hasNext(); )
+ {
+ Map.Entry<String,List<String>> me = it.next();
+ List<String> l = me.getValue();
+ me.setValue(Collections.unmodifiableList(l));
+ }
+ return m;
+ }
+
+ /**
+ * Get the name of the Nth header.
+ *
+ * @param i the header index.
+ *
+ * @return The header name, or <code>null</code> if index outside of range.
+ *
+ * @see #getHeaderValue(int)
+ */
+ public String getHeaderName(int i)
+ {
+ if (i >= headers.size() || i < 0)
+ return null;
+
+ return headers.get(i).name;
+ }
+
+ /**
+ * Get the value of the Nth header.
+ *
+ * @param i the header index.
+ *
+ * @return the header value, or <code>null</code> if index outside of range.
+ *
+ * @see #getHeaderName(int)
+ */
+ public String getHeaderValue(int i)
+ {
+ if (i >= headers.size() || i < 0)
+ return null;
+
+ return headers.get(i).value;
+ }
+}