PR libgcj/26487 shows problems with our existing header handling.

I hacked up the attached patch, which needs more testing (please test it!)

The basic problem is that the headers were being held in a map which scrambled them up if there were more than one header of the same name.

My change was to just hold the headers in a list. This makes some searching operations less efficient, but seems the best way to keep the headers from being combined.

Let me know what you think.

2006-02-28  David Daney  <[EMAIL PROTECTED]>

        * gnu/java/net/protocol/http/HTTPURLConnection.java
        (getRequestProperties): Rewrote.
        (addRequestProperty): Rewrote.
        (getHeaderFields): Rewrote.
        (getHeaderField): Rewrote.
        (getHeaderFieldKey): Rewrote.
        (getHeaderField): Removed useless cast.
        * gnu/java/net/protocol/http/Headers.java: Entire class rewritten.
        * gnu/java/net/protocol/http/Request.java (dispatch): Use new Headers
        interface.
        (notifyHeaderHandlers): Use new Headers interface.
? cis.changelog
? cl
? d
? headers.d
Index: gnu/java/net/protocol/http/HTTPURLConnection.java
===================================================================
RCS file: 
/sources/classpath/classpath/gnu/java/net/protocol/http/HTTPURLConnection.java,v
retrieving revision 1.22
diff -c -p -r1.22 HTTPURLConnection.java
*** gnu/java/net/protocol/http/HTTPURLConnection.java   27 Feb 2006 23:37:20 
-0000      1.22
--- gnu/java/net/protocol/http/HTTPURLConnection.java   28 Feb 2006 21:39:22 
-0000
*************** public class HTTPURLConnection
*** 422,441 ****
      if (connected)
        throw new IllegalStateException("Already connected");
      
!     HashMap m = new HashMap(requestHeaders);
!     Iterator it = m.entrySet().iterator();
!     while (it.hasNext())
!       {
!         Map.Entry e = (Map.Entry)it.next();
!         String s = (String)e.getValue();
!         String sa[] = s.split(",");
!         ArrayList l = new ArrayList(sa.length);
!         for (int i = 0; i < sa.length; i++)
!           {
!             l.add(sa[i].trim());
!           }
!         e.setValue(Collections.unmodifiableList(l));
!       }
      return Collections.unmodifiableMap(m);
    }
  
--- 422,428 ----
      if (connected)
        throw new IllegalStateException("Already connected");
      
!     Map m = requestHeaders.getAsMap();
      return Collections.unmodifiableMap(m);
    }
  
*************** public class HTTPURLConnection
*** 449,464 ****
    public void addRequestProperty(String key, String value)
    {
      super.addRequestProperty(key, value);
!     
!     String old = requestHeaders.getValue(key);
!     if (old == null)
!       {
!         requestHeaders.put(key, value);
!       }
!     else
!       {
!         requestHeaders.put(key, old + "," + value);
!       }
    }
  
    public OutputStream getOutputStream()
--- 436,442 ----
    public void addRequestProperty(String key, String value)
    {
      super.addRequestProperty(key, value);
!     requestHeaders.addValue(key, value);
    }
  
    public OutputStream getOutputStream()
*************** public class HTTPURLConnection
*** 533,549 ****
              return null;
            }
        }
!     Headers headers = response.getHeaders();
!     LinkedHashMap ret = new LinkedHashMap();
!     ret.put(null, Collections.singletonList(getStatusLine(response)));
!     for (Iterator i = headers.entrySet().iterator(); i.hasNext(); )
!       {
!         Map.Entry entry = (Map.Entry) i.next();
!         String key = (String) entry.getKey();
!         String value = (String) entry.getValue();
!         ret.put(key, Collections.singletonList(value));
!       }
!     return Collections.unmodifiableMap(ret);
    }
  
    String getStatusLine(Response response)
--- 511,519 ----
              return null;
            }
        }
!     Map m = response.getHeaders().getAsMap();
!     m.put(null, Collections.singletonList(getStatusLine(response)));
!     return Collections.unmodifiableMap(m);
    }
  
    String getStatusLine(Response response)
*************** public class HTTPURLConnection
*** 571,590 ****
        {
          return getStatusLine(response);
        }
!     Iterator i = response.getHeaders().entrySet().iterator();
!     Map.Entry entry;
!     int count = 1;
!     do
!       {
!         if (!i.hasNext())
!           {
!             return null;
!           }
!         entry = (Map.Entry) i.next();
!         count++;
!       }
!     while (count <= index);
!     return (String) entry.getValue();
    }
  
    public String getHeaderFieldKey(int index)
--- 541,547 ----
        {
          return getStatusLine(response);
        }
!     return response.getHeaders().getHeaderValue(index - 1);
    }
  
    public String getHeaderFieldKey(int index)
*************** public class HTTPURLConnection
*** 600,623 ****
              return null;
            }
        }
!     if (index == 0)
!       {
!         return null;
!       }
!     Iterator i = response.getHeaders().entrySet().iterator();
!     Map.Entry entry;
!     int count = 1;
!     do
!       {
!         if (!i.hasNext())
!           {
!             return null;
!           }
!         entry = (Map.Entry) i.next();
!         count++;
!       }
!     while (count <= index);
!     return (String) entry.getKey();
    }
  
    public String getHeaderField(String name)
--- 557,564 ----
              return null;
            }
        }
!     // index of zero is the status line.
!     return response.getHeaders().getHeaderName(index - 1);
    }
  
    public String getHeaderField(String name)
*************** public class HTTPURLConnection
*** 633,639 ****
              return null;
            }
        }
!     return (String) response.getHeader(name);
    }
  
    public long getHeaderFieldDate(String name, long def)
--- 574,580 ----
              return null;
            }
        }
!     return response.getHeader(name);
    }
  
    public long getHeaderFieldDate(String name, long def)
Index: gnu/java/net/protocol/http/Headers.java
===================================================================
RCS file: /sources/classpath/classpath/gnu/java/net/protocol/http/Headers.java,v
retrieving revision 1.5
diff -c -p -r1.5 Headers.java
*** gnu/java/net/protocol/http/Headers.java     12 Oct 2005 19:48:25 -0000      
1.5
--- gnu/java/net/protocol/http/Headers.java     28 Feb 2006 21:39:22 -0000
***************
*** 1,5 ****
  /* Headers.java --
!    Copyright (C) 2004 Free Software Foundation, Inc.
  
  This file is part of GNU Classpath.
  
--- 1,5 ----
  /* Headers.java --
!    Copyright (C) 2004, 2006 Free Software Foundation, Inc.
  
  This file is part of GNU Classpath.
  
*************** import java.io.IOException;
*** 44,68 ****
  import java.io.InputStream;
  import java.text.DateFormat;
  import java.text.ParseException;
! import java.util.Collection;
  import java.util.Date;
  import java.util.Iterator;
  import java.util.LinkedHashMap;
- import java.util.LinkedHashSet;
  import java.util.Map;
  import java.util.Set;
  
  /**
!  * A collection of HTTP header names and associated values.
!  * Retrieval of values is case insensitive. An iteration over the keys
!  * returns the header names in the order they were received.
   *
   * @author Chris Burdess ([EMAIL PROTECTED])
   */
  public class Headers
-   extends LinkedHashMap
  {
! 
    static final DateFormat dateFormat = new HTTPDateFormat();
  
    static class Header
--- 44,73 ----
  import java.io.InputStream;
  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.Map;
  import java.util.Set;
  
  /**
!  * A collection of HTTP header names and associated values.  The
!  * values are [EMAIL PROTECTED] ArrayList ArrayLists} of Strings.  Retrieval 
of
!  * values is case insensitive. An iteration over the keys returns the
!  * header names in the order they were received.
   *
   * @author Chris Burdess ([EMAIL PROTECTED])
   */
  public class Headers
  {
!   /**
!    * A list of HeaderElements
!    *
!    */
!   final ArrayList headers = new ArrayList();
!   
    static final DateFormat dateFormat = new HTTPDateFormat();
  
    static class Header
*************** public class Headers
*** 97,168 ****
      {
        return name;
      }
-     
    }
  
!   static class HeaderEntry
!     implements Map.Entry
    {
  
!     final Map.Entry entry;
! 
!     HeaderEntry(Map.Entry entry)
!     {
!       this.entry = entry;
!     }
! 
!     public Object getKey()
!     {
!       return ((Header) entry.getKey()).name;
!     }
! 
!     public Object getValue()
!     {
!       return entry.getValue();
!     }
! 
!     public Object setValue(Object value)
      {
!       return entry.setValue(value);
      }
! 
!     public int hashCode()
!     {
!       return entry.hashCode();
!     }
! 
!     public boolean equals(Object other)
      {
!       return entry.equals(other);
      }
- 
-     public String toString()
-     {
-       return getKey().toString() + "=" + getValue();
-     }
-     
    }
  
    public Headers()
    {
    }
  
!   public boolean containsKey(Object key)
!   {
!     return super.containsKey(new Header((String) key));
!   }
! 
!   public Object get(Object key)
!   {
!     return super.get(new Header((String) key));
!   }
  
    /**
!    * Returns the value of the specified header as a string.
     */
    public String getValue(String header)
    {
!     return (String) super.get(new Header(header));
    }
  
    /**
--- 102,157 ----
      {
        return name;
      }
    }
  
!   static class HeaderElement
    {
+     Header key;
+     String value;
  
!     HeaderElement(String key, String value)
      {
!       this.key = new Header(key);
!       this.value = value;
      }
!     HeaderElement(Header key, String value)
      {
!       this.key = key;
!       this.value = value;
      }
    }
  
    public Headers()
    {
    }
  
! //   public boolean containsKey(Object key)
! //   {
! //     return super.containsKey(new Header((String) key));
! //   }
! 
! //   public Object get(Object key)
! //   {
! //     return super.get(new Header((String) key));
! //   }
  
    /**
!    * Returns the value of the specified header as a string.  If
!    * multiple values are present, the last one is returned.
     */
    public String getValue(String header)
    {
!     Header h = new Header(header);
!     
!     for (int i = headers.size() - 1; i >= 0; i--)
!       {
!         HeaderElement e = (HeaderElement)headers.get(i);
!         if (e.key.equals(h))
!           {
!             return e.value;
!           }
!       }
!     return null;
    }
  
    /**
*************** public class Headers
*** 228,276 ****
        }
    }
  
!   public Object put(Object key, Object value)
!   {
!     return super.put(new Header((String) key), value);
!   }
  
!   public Object remove(Object key)
    {
!     return super.remove(new Header((String) key));
    }
  
!   public void putAll(Map t)
    {
!     for (Iterator i = t.keySet().iterator(); i.hasNext(); )
        {
!         String key = (String) i.next();
!         String value = (String) t.get(key);
!         put(key, value);
        }
    }
!   
!   public Set keySet()
    {
!     Set keys = super.keySet();
!     Set ret = new LinkedHashSet();
!     for (Iterator i = keys.iterator(); i.hasNext(); )
        {
!         ret.add(((Header) i.next()).name);
        }
-     return ret;
    }
  
!   public Set entrySet()
    {
!     Set entries = super.entrySet();
!     Set ret = new LinkedHashSet();
!     for (Iterator i = entries.iterator(); i.hasNext(); )
!       {
!         Map.Entry entry = (Map.Entry) i.next();
!         ret.add(new HeaderEntry(entry));
!       }
!     return ret;
    }
! 
    /**
     * Parse the specified input stream, adding headers to this collection.
     */
--- 217,264 ----
        }
    }
  
! //   public Object put(Object key, Object value)
! //   {
! //     ArrayList v = (ArrayList)value;
! //     return super.put(new Header((String) key), v);
! //   }
  
!   public void put(String key, String value)
    {
!     remove(key);
!     Header k = new Header(key);
!     headers.add(headers.size(), new HeaderElement(k, value));
    }
  
!   public void putAll(Headers o)
    {
!     for (Iterator it = o.headers.iterator(); it.hasNext(); )
        {
!         HeaderElement e = (HeaderElement)it.next();
!         put(e.key.toString(), e.value);
        }
    }
! 
!   public void remove(String key)
    {
!     Header k = new Header(key);
!     for (Iterator it = headers.iterator(); it.hasNext(); )
        {
!         HeaderElement e = (HeaderElement)it.next();
!         if (e.key.equals(k))
!           it.remove();
        }
    }
  
!   public void putAll(Map t)
    {
! //     for (Iterator i = t.keySet().iterator(); i.hasNext(); )
! //       {
! //         String key = (String) i.next();
! //         put(key, t.get(key));
! //       }
    }
!   
    /**
     * Parse the specified input stream, adding headers to this collection.
     */
*************** public class Headers
*** 334,351 ****
        }
    }
    
!   private void addValue(String name, String value)
    {
!     Header key = new Header(name);
!     String old = (String) super.get(key);
!     if (old == null)
        {
!         super.put(key, value);
        }
!     else
        {
!         super.put(key, old + ", " + value);
        }
    }
    
  }
--- 322,373 ----
        }
    }
    
!   public void addValue(String name, String value)
!   {
!     Header k = new Header(name);
!     headers.add(headers.size(), new HeaderElement(k, value));
!   }
! 
!   public Map getAsMap()
    {
!     LinkedHashMap m = new LinkedHashMap();
!     for (Iterator it = headers.iterator(); it.hasNext(); )
        {
!         HeaderElement e = (HeaderElement)it.next();
!         String k = e.key.toString().toLowerCase();
!         ArrayList l = (ArrayList)m.get(k);
!         if (l == null)
!           {
!             l = new ArrayList(1);
!             l.add(e.value);
!             m.put(k, l);
!           }
!         else
!           l.add(e.value);
        }
!     for (Iterator it = m.entrySet().iterator(); it.hasNext(); )
        {
!         Map.Entry me = (Map.Entry)it.next();
!         ArrayList l = (ArrayList)me.getValue();
!         me.setValue(Collections.unmodifiableList(l));
        }
+     return m;
+   }
+   
+   public String getHeaderName(int i)
+   {
+     if (i >= headers.size() || i < 0)
+       return null;
+     
+     return ((HeaderElement)headers.get(i)).key.toString();
+   }
+ 
+   public String getHeaderValue(int i)
+   {
+     if (i >= headers.size() || i < 0)
+       return null;
+     
+     return ((HeaderElement)headers.get(i)).value;
    }
    
  }
Index: gnu/java/net/protocol/http/Request.java
===================================================================
RCS file: /sources/classpath/classpath/gnu/java/net/protocol/http/Request.java,v
retrieving revision 1.8
diff -c -p -r1.8 Request.java
*** gnu/java/net/protocol/http/Request.java     9 Feb 2006 09:23:38 -0000       
1.8
--- gnu/java/net/protocol/http/Request.java     28 Feb 2006 21:39:22 -0000
*************** public class Request
*** 302,313 ****
              String line = method + ' ' + requestUri + ' ' + version + CRLF;
              out.write(line.getBytes(US_ASCII));
              // Request headers
!             for (Iterator i = requestHeaders.keySet().iterator();
!                  i.hasNext(); )
                {
!                 String name =(String) i.next();
!                 String value =(String) requestHeaders.get(name);
!                 line = name + HEADER_SEP + value + CRLF;
                  out.write(line.getBytes(US_ASCII));
                }
              out.write(CRLF.getBytes(US_ASCII));
--- 302,312 ----
              String line = method + ' ' + requestUri + ' ' + version + CRLF;
              out.write(line.getBytes(US_ASCII));
              // Request headers
!             for (Iterator i = requestHeaders.headers.iterator(); i.hasNext(); 
)
                {
!                 Headers.HeaderElement elt = (Headers.HeaderElement)i.next();
!                 String name = elt.key.toString();
!                 line = name + HEADER_SEP + elt.value + CRLF;
                  out.write(line.getBytes(US_ASCII));
                }
              out.write(CRLF.getBytes(US_ASCII));
*************** public class Request
*** 438,460 ****
  
    void notifyHeaderHandlers(Headers headers)
    {
!     for (Iterator i = headers.entrySet().iterator(); i.hasNext(); )
        {
!         Map.Entry entry = (Map.Entry) i.next();
!         String name =(String) entry.getKey();
          // Handle Set-Cookie
          if ("Set-Cookie".equalsIgnoreCase(name))
!           {
!             String value = (String) entry.getValue();
!             handleSetCookie(value);
!           }
          ResponseHeaderHandler handler =
            (ResponseHeaderHandler) responseHeaderHandlers.get(name);
          if (handler != null)
!           {
!             String value = (String) entry.getValue();
!             handler.setValue(value);
!           }
        }
    }
  
--- 437,454 ----
  
    void notifyHeaderHandlers(Headers headers)
    {
!     for (Iterator i = headers.headers.iterator(); i.hasNext(); )
        {
!         Headers.HeaderElement entry = (Headers.HeaderElement) i.next();
!         String name = entry.key.toString();
          // Handle Set-Cookie
          if ("Set-Cookie".equalsIgnoreCase(name))
!             handleSetCookie(entry.value);
! 
          ResponseHeaderHandler handler =
            (ResponseHeaderHandler) responseHeaderHandlers.get(name);
          if (handler != null)
!             handler.setValue(entry.value);
        }
    }
  

Reply via email to