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);
}
}