mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			425 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			425 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* 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;
 | |
|   }
 | |
| }
 |