Imported GNU Classpath 0.90

Imported GNU Classpath 0.90
       * scripts/makemake.tcl: Set gnu/java/awt/peer/swing to ignore.
       * gnu/classpath/jdwp/VMFrame.java (SIZE): New constant.
       * java/lang/VMCompiler.java: Use gnu.java.security.hash.MD5.
       * java/lang/Math.java: New override file.
       * java/lang/Character.java: Merged from Classpath.
       (start, end): Now 'int's.
       (canonicalName): New field.
       (CANONICAL_NAME, NO_SPACES_NAME, CONSTANT_NAME): New constants.
       (UnicodeBlock): Added argument.
       (of): New overload.
       (forName): New method.
       Updated unicode blocks.
       (sets): Updated.
       * sources.am: Regenerated.
       * Makefile.in: Likewise.

From-SVN: r111942
This commit is contained in:
Mark Wielaard 2006-03-10 21:46:48 +00:00
parent 27079765d0
commit 8aa540d2f7
1367 changed files with 188789 additions and 22762 deletions

View file

@ -135,21 +135,18 @@ public class Connection extends URLConnection
* @exception MalformedURLException If the given string contains invalid
* escape sequences.
*
* Sadly the same as URI.unquote, but there's nothing we can do to
* make it accessible.
*
*/
public static String unquote(String str) throws MalformedURLException
{
if (str == null)
return null;
byte[] buf = new byte[str.length()];
final int MAX_BYTES_PER_UTF_8_CHAR = 3;
byte[] buf = new byte[str.length()*MAX_BYTES_PER_UTF_8_CHAR];
int pos = 0;
for (int i = 0; i < str.length(); i++)
{
char c = str.charAt(i);
if (c > 127)
throw new MalformedURLException(str + " : Invalid character");
if (c == '%')
{
if (i + 2 >= str.length())
@ -160,6 +157,15 @@ public class Connection extends URLConnection
throw new MalformedURLException(str + " : Invalid quoted character");
buf[pos++] = (byte) (hi * 16 + lo);
}
else if (c > 127) {
try {
byte [] c_as_bytes = Character.toString(c).getBytes("utf-8");
System.arraycopy(c_as_bytes, 0, buf, pos, c_as_bytes.length);
}
catch (java.io.UnsupportedEncodingException x2) {
throw (Error) new InternalError().initCause(x2);
}
}
else
buf[pos++] = (byte) c;
}

View file

@ -84,6 +84,7 @@ final class ActiveModeDTP
}
this.connectionTimeout = connectionTimeout;
acceptThread = new Thread(this, "ActiveModeDTP");
acceptThread.setDaemon(true);
acceptThread.start();
}

View file

@ -1,5 +1,5 @@
/* FTPURLConnection.java --
Copyright (C) 2003, 2004 Free Software Foundation, Inc.
Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -38,10 +38,9 @@ exception statement from your version. */
package gnu.java.net.protocol.ftp;
import gnu.classpath.SystemProperties;
import gnu.java.net.GetLocalHostAction;
import gnu.java.security.action.GetPropertyAction;
import java.io.FileNotFoundException;
import java.io.FilterInputStream;
import java.io.FilterOutputStream;
import java.io.IOException;
@ -51,7 +50,6 @@ import java.net.InetAddress;
import java.net.URL;
import java.net.URLConnection;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.HashMap;
import java.util.Map;
@ -113,11 +111,9 @@ public class FTPURLConnection
else
{
username = "anonymous";
PrivilegedAction a = new GetPropertyAction("user.name");
String systemUsername =(String) AccessController.doPrivileged(a);
a = new GetLocalHostAction();
GetLocalHostAction a = new GetLocalHostAction();
InetAddress localhost =(InetAddress) AccessController.doPrivileged(a);
password = systemUsername + "@" +
password = SystemProperties.getProperty("user.name") + "@" +
((localhost == null) ? "localhost" : localhost.getHostName());
}
connection = new FTPConnection(host, port);
@ -167,24 +163,13 @@ public class FTPURLConnection
connect();
}
String path = url.getPath();
String filename = null;
int lsi = path.lastIndexOf('/');
if (lsi != -1)
if (connection.changeWorkingDirectory(path))
{
filename = path.substring(lsi + 1);
path = path.substring(0, lsi);
if (!connection.changeWorkingDirectory(path))
{
throw new FileNotFoundException(path);
}
}
if (filename != null && filename.length() > 0)
{
return this.new ClosingInputStream(connection.retrieve(filename));
return this.new ClosingInputStream(connection.list(null));
}
else
{
return this.new ClosingInputStream(connection.list(null));
return this.new ClosingInputStream(connection.retrieve(path));
}
}
@ -198,20 +183,8 @@ public class FTPURLConnection
{
connect();
}
String dir = url.getPath();
String filename = url.getFile();
if (!connection.changeWorkingDirectory(dir))
{
throw new FileNotFoundException(dir);
}
if (filename != null)
{
return this.new ClosingOutputStream(connection.store(filename));
}
else
{
throw new FileNotFoundException(filename);
}
String path = url.getPath();
return this.new ClosingOutputStream(connection.store(path));
}
public String getRequestProperty(String key)

View file

@ -1,5 +1,5 @@
/* ChunkedInputStream.java --
Copyright (C) 2004 Free Software Foundation, Inc.
Copyright (C) 2004, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -38,29 +38,47 @@ exception statement from your version. */
package gnu.java.net.protocol.http;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ProtocolException;
//
// Note that we rely on the implemtation of skip() in the super class
// (InputStream) calling our read methods to account for chunk headers
// while skipping.
//
/**
* Input stream wrapper for the "chunked" transfer-coding.
*
* @author Chris Burdess (dog@gnu.org)
*/
public class ChunkedInputStream
extends FilterInputStream
extends InputStream
{
private static final byte CR = 0x0d;
private static final byte LF = 0x0a;
int size;
int count;
boolean meta;
boolean eof;
Headers headers;
/** The underlying stream. */
private InputStream in;
/** Size of the chunk we're reading. */
int size;
/** Number of bytes we've read in this chunk. */
int count;
/**
* True when we should read meta-information, false when we should
* read data.
*/
boolean meta;
/** True when we've hit EOF. */
boolean eof;
/**
* Constructor.
* @param in the response socket input stream
@ -68,7 +86,7 @@ public class ChunkedInputStream
*/
public ChunkedInputStream(InputStream in, Headers headers)
{
super(in);
this.in = in;
this.headers = headers;
size = -1;
count = 0;
@ -84,21 +102,10 @@ public class ChunkedInputStream
{
return -1;
}
int ret = (int) buf[0];
if (ret < 0)
{
ret += 0x100;
}
return ret;
return 0xff & buf[0];
}
public int read(byte[] buffer)
throws IOException
{
return read(buffer, 0, buffer.length);
}
public int read(byte[] buffer, int offset, int length)
public synchronized int read(byte[] buffer, int offset, int length)
throws IOException
{
if (eof)
@ -120,7 +127,18 @@ public class ChunkedInputStream
}
else if (c == 0x0a && last == 0x0d) // CRLF
{
size = Integer.parseInt(buf.toString(), 16);
try
{
size = Integer.parseInt(buf.toString(), 16);
}
catch (NumberFormatException nfe)
{
IOException ioe = new IOException("Bad chunk header");
ioe.initCause(nfe);
// Unrecoverable. Don't try to read more.
in.close();
throw ioe;
}
break;
}
else if (!seenSemi && c >= 0x30)
@ -142,17 +160,22 @@ public class ChunkedInputStream
}
else
{
int diff = length - offset;
int max = size - count;
max = (diff < max) ? diff : max;
int len = (max > 0) ? in.read(buffer, offset, max) : 0;
int canRead = Math.min(size - count, length);
int len = in.read(buffer, offset, canRead);
if (len == -1)
{
// This is an error condition but it isn't clear what we
// should do with it.
eof = true;
return -1;
}
count += len;
if (count == size)
{
// Read CRLF
int c1 = in.read();
int c2 = in.read();
if (c1 == -1 && c2 == -1)
if (c1 == -1 || c2 == -1)
{
// EOF before CRLF: bad, but ignore
eof = true;
@ -167,6 +190,37 @@ public class ChunkedInputStream
return len;
}
}
/**
* This method returns the number of bytes that can be read from
* this stream before a read might block. Even if the underlying
* InputStream has data available past the end of the current chunk,
* we have no way of knowing how large the next chunk header will
* be. So we cannot report available data past the current chunk.
*
* @return The number of bytes that can be read before a read might
* block
*
* @exception IOException If an error occurs
*/
public int available() throws IOException
{
if (meta)
return 0;
return Math.min(in.available(), size - count);
}
/**
* This method closes the ChunkedInputStream by closing the underlying
* InputStream.
*
* @exception IOException If an error occurs
*/
public void close() throws IOException
{
in.close();
}
}

View file

@ -1,5 +1,5 @@
/* HTTPConnection.java --
Copyright (C) 2004, 2005 Free Software Foundation, Inc.
Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -38,7 +38,6 @@ exception statement from your version. */
package gnu.java.net.protocol.http;
import gnu.classpath.Configuration;
import gnu.classpath.SystemProperties;
import gnu.java.net.EmptyX509TrustManager;
@ -53,8 +52,9 @@ import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import javax.net.ssl.HandshakeCompletedListener;
@ -164,7 +164,7 @@ public class HTTPConnection
/**
* The pool that this connection is a member of (if any).
*/
private LinkedHashMap pool;
private Pool pool;
/**
* Creates a new HTTP connection.
@ -266,7 +266,8 @@ public class HTTPConnection
/**
* Returns the HTTP version string supported by this connection.
* @see #version
* @see #majorVersion
* @see #minorVersion
*/
public String getVersion()
{
@ -330,28 +331,228 @@ public class HTTPConnection
return cookieManager;
}
/**
* Manages a pool of HTTPConections. The pool will have a maximum
* size determined by the value of the maxConn parameter passed to
* the {@link #get} method. This value inevitably comes from the
* http.maxConnections system property. If the
* classpath.net.http.keepAliveTTL system property is set, that will
* be the maximum time (in seconds) that an idle connection will be
* maintained.
*/
static class Pool
{
/**
* Singleton instance of the pool.
*/
static Pool instance = new Pool();
/**
* The pool
*/
final LinkedList connectionPool = new LinkedList();
/**
* Maximum size of the pool.
*/
int maxConnections;
/**
* If greater than zero, the maximum time a connection will remain
* int the pool.
*/
int connectionTTL;
/**
* A thread that removes connections older than connectionTTL.
*/
class Reaper
implements Runnable
{
public void run()
{
synchronized (Pool.this)
{
try
{
do
{
while (connectionPool.size() > 0)
{
long currentTime = System.currentTimeMillis();
HTTPConnection c =
(HTTPConnection)connectionPool.getFirst();
long waitTime = c.timeLastUsed
+ connectionTTL - currentTime;
if (waitTime <= 0)
removeOldest();
else
try
{
Pool.this.wait(waitTime);
}
catch (InterruptedException _)
{
// Ignore the interrupt.
}
}
// After the pool is empty, wait TTL to see if it
// is used again. This is because in the
// situation where a single thread is making HTTP
// requests to the same server it can remove the
// connection from the pool before the Reaper has
// a chance to start. This would cause the Reaper
// to exit if it were not for this extra delay.
// The result would be starting a Reaper thread
// for each HTTP request. With the delay we get
// at most one Reaper created each TTL.
try
{
Pool.this.wait(connectionTTL);
}
catch (InterruptedException _)
{
// Ignore the interrupt.
}
}
while (connectionPool.size() > 0);
}
finally
{
reaper = null;
}
}
}
}
Reaper reaper;
/**
* Private constructor to ensure singleton.
*/
private Pool()
{
}
/**
* Tests for a matching connection.
*
* @param c connection to match.
* @param h the host name.
* @param p the port.
* @param sec true if using https.
*
* @return true if c matches h, p, and sec.
*/
private static boolean matches(HTTPConnection c,
String h, int p, boolean sec)
{
return h.equals(c.hostname) && (p == c.port) && (sec == c.secure);
}
/**
* Get a pooled HTTPConnection. If there is an existing idle
* connection to the requested server it is returned. Otherwise a
* new connection is created.
*
* @param host the name of the host to connect to
* @param port the port on the host to connect to
* @param secure whether to use a secure connection
*
* @return the HTTPConnection.
*/
synchronized HTTPConnection get(String host,
int port,
boolean secure)
{
String ttl =
SystemProperties.getProperty("classpath.net.http.keepAliveTTL");
connectionTTL = (ttl != null && ttl.length() > 0) ?
1000 * Math.max(1, Integer.parseInt(ttl)) : 10000;
String mc = SystemProperties.getProperty("http.maxConnections");
maxConnections = (mc != null && mc.length() > 0) ?
Math.max(Integer.parseInt(mc), 1) : 5;
if (maxConnections < 1)
maxConnections = 1;
HTTPConnection c = null;
ListIterator it = connectionPool.listIterator(0);
while (it.hasNext())
{
HTTPConnection cc = (HTTPConnection)it.next();
if (matches(cc, host, port, secure))
{
c = cc;
it.remove();
break;
}
}
if (c == null)
{
c = new HTTPConnection(host, port, secure);
c.setPool(this);
}
return c;
}
/**
* Put an idle HTTPConnection back into the pool. If this causes
* the pool to be come too large, the oldest connection is removed
* and closed.
*
*/
synchronized void put(HTTPConnection c)
{
c.timeLastUsed = System.currentTimeMillis();
connectionPool.addLast(c);
// maxConnections must always be >= 1
while (connectionPool.size() >= maxConnections)
removeOldest();
if (connectionTTL > 0 && null == reaper) {
// If there is a connectionTTL, then the reaper has removed
// any stale connections, so we don't have to check for stale
// now. We do have to start a reaper though, as there is not
// one running now.
reaper = new Reaper();
Thread t = new Thread(reaper, "HTTPConnection.Reaper");
t.setDaemon(true);
t.start();
}
}
/**
* Remove the oldest connection from the pool and close it.
*/
void removeOldest()
{
HTTPConnection cx = (HTTPConnection)connectionPool.removeFirst();
try
{
cx.closeConnection();
}
catch (IOException ioe)
{
// Ignore it. We are just cleaning up.
}
}
}
/**
* The number of times this HTTPConnection has be used via keep-alive.
*/
int useCount;
/**
* Generates a key for connections in the connection pool.
*
* @param h the host name.
* @param p the port.
* @param sec true if using https.
*
* @return the key.
* If this HTTPConnection is in the pool, the time it was put there.
*/
static Object getPoolKey(String h, int p, boolean sec)
{
StringBuilder buf = new StringBuilder(sec ? "https://" : "http://");
buf.append(h);
buf.append(':');
buf.append(p);
return buf.toString();
}
long timeLastUsed;
/**
* Set the connection pool that this HTTPConnection is a member of.
@ -360,7 +561,7 @@ public class HTTPConnection
*
* @param p the pool.
*/
void setPool(LinkedHashMap p)
void setPool(Pool p)
{
pool = p;
}
@ -374,25 +575,20 @@ public class HTTPConnection
{
if (pool != null)
{
synchronized (pool)
useCount++;
pool.put(this);
}
else
{
// If there is no pool, just close.
try
{
useCount++;
Object key = HTTPConnection.getPoolKey(hostname, port, secure);
pool.put(key, this);
while (pool.size() >= HTTPURLConnection.maxConnections)
{
// maxConnections must always be >= 1
Object lru = pool.keySet().iterator().next();
HTTPConnection c = (HTTPConnection)pool.remove(lru);
try
{
c.closeConnection();
}
catch (IOException ioe)
{
// Ignore it. We are just cleaning up.
}
}
closeConnection();
}
catch (IOException ioe)
{
// Ignore it. We are just cleaning up.
}
}
}

View file

@ -1,5 +1,5 @@
/* HTTPURLConnection.java --
Copyright (C) 2004, 2005 Free Software Foundation, Inc.
Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -38,6 +38,8 @@ exception statement from your version. */
package gnu.java.net.protocol.http;
import gnu.classpath.SystemProperties;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
@ -45,11 +47,11 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.net.ProtocolException;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
@ -70,13 +72,6 @@ public class HTTPURLConnection
extends HttpsURLConnection
implements HandshakeCompletedListener
{
/**
* Pool of reusable connections, used if keepAlive is true.
*/
private static final LinkedHashMap connectionPool = new LinkedHashMap();
static int maxConnections;
/*
* The underlying connection.
*/
@ -108,38 +103,23 @@ public class HTTPURLConnection
{
super(url);
requestHeaders = new Headers();
AccessController.doPrivileged(this.new GetHTTPPropertiesAction());
}
class GetHTTPPropertiesAction
implements PrivilegedAction
{
public Object run()
{
proxyHostname = System.getProperty("http.proxyHost");
if (proxyHostname != null && proxyHostname.length() > 0)
{
String port = System.getProperty("http.proxyPort");
if (port != null && port.length() > 0)
{
proxyPort = Integer.parseInt(port);
}
else
{
proxyHostname = null;
proxyPort = -1;
}
}
agent = System.getProperty("http.agent");
String ka = System.getProperty("http.keepAlive");
keepAlive = !(ka != null && "false".equals(ka));
String mc = System.getProperty("http.maxConnections");
maxConnections = (mc != null && mc.length() > 0) ?
Math.max(Integer.parseInt(mc), 1) : 5;
return null;
}
proxyHostname = SystemProperties.getProperty("http.proxyHost");
if (proxyHostname != null && proxyHostname.length() > 0)
{
String port = SystemProperties.getProperty("http.proxyPort");
if (port != null && port.length() > 0)
{
proxyPort = Integer.parseInt(port);
}
else
{
proxyHostname = null;
proxyPort = -1;
}
}
agent = SystemProperties.getProperty("http.agent");
String ka = SystemProperties.getProperty("http.keepAlive");
keepAlive = !(ka != null && "false".equals(ka));
}
public void connect()
@ -254,8 +234,24 @@ public class HTTPURLConnection
}
}
if (response.getCodeClass() == 3 && getInstanceFollowRedirects())
if (response.isRedirect() && getInstanceFollowRedirects())
{
// Read the response body, if there is one. If the
// redirect points us back at the same server, we will use
// the cached connection, so we must make sure there is no
// pending data in it.
InputStream body = response.getBody();
if (body != null)
{
byte[] ignore = new byte[1024];
while (true)
{
int n = body.read(ignore, 0, ignore.length);
if (n == -1)
break;
}
}
// Follow redirect
String location = response.getHeader("Location");
if (location != null)
@ -333,16 +329,13 @@ public class HTTPURLConnection
{
responseSink = response.getBody();
if (response.getCode() == 404)
{
errorSink = responseSink;
throw new FileNotFoundException(url.toString());
}
if (response.isError())
errorSink = responseSink;
}
}
while (retry);
connected = true;
}
}
/**
* Returns a connection, from the pool if necessary.
@ -353,16 +346,7 @@ public class HTTPURLConnection
HTTPConnection connection;
if (keepAlive)
{
Object key = HTTPConnection.getPoolKey(host, port, secure);
synchronized (connectionPool)
{
connection = (HTTPConnection) connectionPool.remove(key);
if (connection == null)
{
connection = new HTTPConnection(host, port, secure);
connection.setPool(connectionPool);
}
}
connection = HTTPConnection.Pool.instance.get(host, port, secure);
}
else
{
@ -427,30 +411,32 @@ public class HTTPURLConnection
public String getRequestProperty(String key)
{
if (key == null)
return null;
return requestHeaders.getValue(key);
}
public Map getRequestProperties()
{
return requestHeaders;
if (connected)
throw new IllegalStateException("Already connected");
Map m = requestHeaders.getAsMap();
return Collections.unmodifiableMap(m);
}
public void setRequestProperty(String key, String value)
{
super.setRequestProperty(key, value);
requestHeaders.put(key, value);
}
public void addRequestProperty(String key, String value)
{
String old = requestHeaders.getValue(key);
if (old == null)
{
requestHeaders.put(key, value);
}
else
{
requestHeaders.put(key, old + "," + value);
}
super.addRequestProperty(key, value);
requestHeaders.addValue(key, value);
}
public OutputStream getOutputStream()
@ -493,6 +479,17 @@ public class HTTPURLConnection
{
throw new ProtocolException("doInput is false");
}
if (response.isError())
{
int code = response.getCode();
if (code == 404 || code == 410)
throw new FileNotFoundException(url.toString());
throw new IOException("Server returned HTTP response code " + code
+ " for URL " + url.toString());
}
return responseSink;
}
@ -514,17 +511,9 @@ public class HTTPURLConnection
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);
Map m = response.getHeaders().getAsMap();
m.put(null, Collections.singletonList(getStatusLine(response)));
return Collections.unmodifiableMap(m);
}
String getStatusLine(Response response)
@ -552,20 +541,7 @@ public class HTTPURLConnection
{
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();
return response.getHeaders().getHeaderValue(index - 1);
}
public String getHeaderFieldKey(int index)
@ -581,24 +557,8 @@ public class HTTPURLConnection
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();
// index of zero is the status line.
return response.getHeaders().getHeaderName(index - 1);
}
public String getHeaderField(String name)
@ -614,7 +574,7 @@ public class HTTPURLConnection
return null;
}
}
return (String) response.getHeader(name);
return response.getHeader(name);
}
public long getHeaderFieldDate(String name, long def)

View file

@ -1,5 +1,5 @@
/* Headers.java --
Copyright (C) 2004 Free Software Foundation, Inc.
Copyright (C) 2004, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -44,125 +44,75 @@ import java.io.IOException;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.Collection;
import java.util.ArrayList;
import java.util.Collections;
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
* 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)
*/
public class Headers
extends LinkedHashMap
class Headers
{
/**
* A list of HeaderElements
*
*/
private final ArrayList headers = new ArrayList();
static final DateFormat dateFormat = new HTTPDateFormat();
static class Header
static class HeaderElement
{
String name;
String value;
final String name;
Header(String name)
HeaderElement(String name, String value)
{
if (name == null || name.length() == 0)
{
throw new IllegalArgumentException(name);
}
this.name = name;
this.value = value;
}
public int hashCode()
{
return name.toLowerCase().hashCode();
}
public boolean equals(Object other)
{
if (other instanceof Header)
{
return ((Header) other).name.equalsIgnoreCase(name);
}
return false;
}
public String toString()
{
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.
* Return an Iterator over this collection of headers.
* Iterator.getNext() returns objects of type {@link HeaderElement}.
*
* @return the Iterator.
*/
Iterator iterator()
{
return headers.iterator();
}
/**
* 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)
{
return (String) super.get(new Header(header));
for (int i = headers.size() - 1; i >= 0; i--)
{
HeaderElement e = (HeaderElement)headers.get(i);
if (e.name.equalsIgnoreCase(header))
{
return e.value;
}
}
return null;
}
/**
@ -228,51 +178,62 @@ public class Headers
}
}
public Object put(Object key, Object value)
/**
* Add a header to this set of headers. If there is an existing
* header with the same name, it is discarded.
*
* @param name the header name
* @param value the header value
*
* @see #addValue
*/
public void put(String name, String 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;
remove(name);
headers.add(headers.size(), new HeaderElement(name, value));
}
/**
* Parse the specified input stream, adding headers to this collection.
* Add all headers from a set of headers to this set. If any of the
* headers to be added have the same name as existing headers, the
* existing headers will be discarded.
*
* @param o the headers to be added
*/
public void putAll(Headers o)
{
for (Iterator it = o.iterator(); it.hasNext(); )
{
HeaderElement e = (HeaderElement)it.next();
remove(e.name);
}
for (Iterator it = o.iterator(); it.hasNext(); )
{
HeaderElement e = (HeaderElement)it.next();
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 it = headers.iterator(); it.hasNext(); )
{
HeaderElement e = (HeaderElement)it.next();
if (e.name.equalsIgnoreCase(name))
it.remove();
}
}
/**
* Parse the specified InputStream, adding headers to this collection.
*
* @param in the InputStream.
*/
public void parse(InputStream in)
throws IOException
@ -334,18 +295,90 @@ public class Headers
}
}
private void addValue(String name, String value)
/**
* 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
*/
public void addValue(String name, String value)
{
Header key = new Header(name);
String old = (String) super.get(key);
if (old == null)
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 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.
*
* @return a Map containing all the headers.
*/
public Map getAsMap()
{
LinkedHashMap m = new LinkedHashMap();
for (Iterator it = headers.iterator(); it.hasNext(); )
{
super.put(key, value);
HeaderElement e = (HeaderElement)it.next();
ArrayList l = (ArrayList)m.get(e.name);
if (l == null)
{
l = new ArrayList(1);
l.add(e.value);
m.put(e.name, l);
}
else
l.add(0, e.value);
}
else
for (Iterator it = m.entrySet().iterator(); it.hasNext(); )
{
super.put(key, old + ", " + value);
Map.Entry me = (Map.Entry)it.next();
ArrayList l = (ArrayList)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.
*
* @see #getHeaderValue
*/
public String getHeaderName(int i)
{
if (i >= headers.size() || i < 0)
return null;
return ((HeaderElement)headers.get(i)).name;
}
/**
* Get the value of the Nth header.
*
* @param i the header index.
*
* @return the header value.
*
* @see #getHeaderName
*/
public String getHeaderValue(int i)
{
if (i >= headers.size() || i < 0)
return null;
return ((HeaderElement)headers.get(i)).value;
}
}

View file

@ -1,5 +1,5 @@
/* Request.java --
Copyright (C) 2004, 2005 Free Software Foundation, Inc.
Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -93,11 +93,6 @@ public class Request
*/
protected RequestBodyWriter requestBodyWriter;
/**
* Request body negotiation threshold for 100-continue expectations.
*/
protected int requestBodyNegotiationThreshold;
/**
* Map of response header handlers.
*/
@ -127,7 +122,6 @@ public class Request
this.path = path;
requestHeaders = new Headers();
responseHeaderHandlers = new HashMap();
requestBodyNegotiationThreshold = 4096;
}
/**
@ -250,21 +244,6 @@ public class Request
this.authenticator = authenticator;
}
/**
* Sets the request body negotiation threshold.
* If this is set, it determines the maximum size that the request body
* may be before body negotiation occurs(via the
* <code>100-continue</code> expectation). This ensures that a large
* request body is not sent when the server wouldn't have accepted it
* anyway.
* @param threshold the body negotiation threshold, or &lt;=0 to disable
* request body negotation entirely
*/
public void setRequestBodyNegotiationThreshold(int threshold)
{
requestBodyNegotiationThreshold = threshold;
}
/**
* Dispatches this request.
* A request can only be dispatched once; calling this method a second
@ -291,10 +270,10 @@ public class Request
if (requestBodyWriter != null)
{
contentLength = requestBodyWriter.getContentLength();
if (contentLength > requestBodyNegotiationThreshold)
String expect = getHeader("Expect");
if (expect != null && expect.equals("100-continue"))
{
expectingContinue = true;
setHeader("Expect", "100-continue");
}
else
{
@ -323,12 +302,10 @@ public class Request
String line = method + ' ' + requestUri + ' ' + version + CRLF;
out.write(line.getBytes(US_ASCII));
// Request headers
for (Iterator i = requestHeaders.keySet().iterator();
i.hasNext(); )
for (Iterator i = requestHeaders.iterator(); i.hasNext(); )
{
String name =(String) i.next();
String value =(String) requestHeaders.get(name);
line = name + HEADER_SEP + value + CRLF;
Headers.HeaderElement elt = (Headers.HeaderElement)i.next();
line = elt.name + HEADER_SEP + elt.value + CRLF;
out.write(line.getBytes(US_ASCII));
}
out.write(CRLF.getBytes(US_ASCII));
@ -459,23 +436,17 @@ public class Request
void notifyHeaderHandlers(Headers headers)
{
for (Iterator i = headers.entrySet().iterator(); i.hasNext(); )
for (Iterator i = headers.iterator(); i.hasNext(); )
{
Map.Entry entry = (Map.Entry) i.next();
String name =(String) entry.getKey();
Headers.HeaderElement entry = (Headers.HeaderElement) i.next();
// Handle Set-Cookie
if ("Set-Cookie".equalsIgnoreCase(name))
{
String value = (String) entry.getValue();
handleSetCookie(value);
}
if ("Set-Cookie".equalsIgnoreCase(entry.name))
handleSetCookie(entry.value);
ResponseHeaderHandler handler =
(ResponseHeaderHandler) responseHeaderHandlers.get(name);
(ResponseHeaderHandler) responseHeaderHandlers.get(entry.name);
if (handler != null)
{
String value = (String) entry.getValue();
handler.setValue(value);
}
handler.setValue(entry.value);
}
}
@ -528,6 +499,9 @@ public class Request
throw new ProtocolException("Unsupported Content-Encoding: " +
contentCoding);
}
// Remove the Content-Encoding header because the content is
// no longer compressed.
responseHeaders.remove("Content-Encoding");
}
return in;
}

View file

@ -1,5 +1,5 @@
/* Response.java --
Copyright (C) 2004 Free Software Foundation, Inc.
Copyright (C) 2004, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -188,6 +188,28 @@ public class Response
{
return headers.getDateValue(name);
}
/**
* Tests whether this response indicates a redirection.
*
* @return <code>true</code> if, <code>false</code> otherwise.
*/
public boolean isRedirect()
{
return (code != 304 && getCodeClass() == 3);
}
/**
* Tests whether this response indicates an error.
* Errors are the response codes <code>4xx</code> - Client error and
* <code>5xx</code> - Server error.
*
* @return <code>true</code> if, <code>false</code> otherwise.
*/
public boolean isError()
{
return (getCodeClass() == 4 || getCodeClass() == 5);
}
/**
* Returns an InputStream that returns the body of the response.

View file

@ -41,7 +41,7 @@ package gnu.java.net.protocol.http;
/**
* Callback interface for objects that wish to be notified of response
* header values.
* @see Request#setHeaderHandler(String)
* @see Request#setResponseHeaderHandler(String, ResponseHeaderHandler)
*
* @author Chris Burdess (dog@gnu.org)
*/

View file

@ -1,5 +1,5 @@
/* Connection - jar url connection for java.net
Copyright (C) 1999, 2002, 2003, 2005 Free Software Foundation, Inc.
Copyright (C) 1999, 2002, 2003, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -39,6 +39,7 @@ exception statement from your version. */
package gnu.java.net.protocol.jar;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@ -145,7 +146,7 @@ public final class Connection extends JarURLConnection
jar_entry = (JarEntry) jar_file.getEntry (entry_name);
if(jar_entry == null)
throw new IOException ("No entry for " + entry_name + " exists.");
throw new FileNotFoundException("No entry for " + entry_name + " exists.");
}
connected = true;
@ -159,9 +160,6 @@ public final class Connection extends JarURLConnection
if (! doInput)
throw new ProtocolException("Can't open InputStream if doInput is false");
if (jar_entry == null)
throw new IOException (jar_url + " couldn't be found.");
return jar_file.getInputStream (jar_entry);
}