summaryrefslogtreecommitdiff
path: root/libjava/classpath/gnu/java/net
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/classpath/gnu/java/net')
-rw-r--r--libjava/classpath/gnu/java/net/BASE64.java190
-rw-r--r--libjava/classpath/gnu/java/net/CRLFInputStream.java174
-rw-r--r--libjava/classpath/gnu/java/net/CRLFOutputStream.java183
-rw-r--r--libjava/classpath/gnu/java/net/EmptyX509TrustManager.java70
-rw-r--r--libjava/classpath/gnu/java/net/GetLocalHostAction.java65
-rw-r--r--libjava/classpath/gnu/java/net/HeaderFieldHelper.java138
-rw-r--r--libjava/classpath/gnu/java/net/LineInputStream.java198
-rw-r--r--libjava/classpath/gnu/java/net/PlainDatagramSocketImpl.java321
-rw-r--r--libjava/classpath/gnu/java/net/PlainSocketImpl.java498
-rw-r--r--libjava/classpath/gnu/java/net/URLParseError.java57
-rw-r--r--libjava/classpath/gnu/java/net/package.html46
-rw-r--r--libjava/classpath/gnu/java/net/protocol/file/Connection.java319
-rw-r--r--libjava/classpath/gnu/java/net/protocol/file/Handler.java91
-rw-r--r--libjava/classpath/gnu/java/net/protocol/file/package.html46
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/ActiveModeDTP.java251
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/BlockInputStream.java150
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/BlockOutputStream.java111
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/CompressedInputStream.java215
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/CompressedOutputStream.java228
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/DTP.java92
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/DTPInputStream.java88
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/DTPOutputStream.java85
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/FTPConnection.java1348
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/FTPException.java76
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/FTPResponse.java112
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/FTPURLConnection.java398
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/Handler.java70
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/PassiveModeDTP.java201
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/StreamInputStream.java95
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/StreamOutputStream.java85
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/package.html60
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/Authenticator.java59
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/ByteArrayRequestBodyWriter.java107
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/ByteArrayResponseBodyReader.java123
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/ChunkedInputStream.java172
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/Cookie.java160
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/CookieManager.java65
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/Credentials.java88
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/HTTPConnection.java681
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/HTTPDateFormat.java441
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/HTTPURLConnection.java688
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/Handler.java73
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/Headers.java369
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/Request.java915
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/RequestBodyWriter.java69
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/Response.java185
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/ResponseBodyReader.java70
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/ResponseHeaderHandler.java57
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/SimpleCookieManager.java140
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/event/ConnectionEvent.java81
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/event/ConnectionListener.java58
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/event/RequestEvent.java107
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/event/RequestListener.java70
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/event/package.html46
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/package.html76
-rw-r--r--libjava/classpath/gnu/java/net/protocol/https/Handler.java76
-rw-r--r--libjava/classpath/gnu/java/net/protocol/jar/Connection.java170
-rw-r--r--libjava/classpath/gnu/java/net/protocol/jar/Handler.java173
-rw-r--r--libjava/classpath/gnu/java/net/protocol/jar/package.html46
59 files changed, 11426 insertions, 0 deletions
diff --git a/libjava/classpath/gnu/java/net/BASE64.java b/libjava/classpath/gnu/java/net/BASE64.java
new file mode 100644
index 00000000000..901aa0c35fc
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/BASE64.java
@@ -0,0 +1,190 @@
+/* BASE.java --
+ Copyright (C) 2003, 2004, 2005 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;
+
+/**
+ * Encodes and decodes text according to the BASE64 encoding.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public final class BASE64
+{
+ private static final byte[] src = {
+ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
+ 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54,
+ 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64,
+ 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
+ 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x2b, 0x2f
+ };
+
+ private static final byte[] dst;
+ static
+ {
+ dst = new byte[0x100];
+ for (int i = 0x0; i < 0xff; i++)
+ {
+ dst[i] = -1;
+ }
+ for (int i = 0; i < src.length; i++)
+ {
+ dst[src[i]] = (byte) i;
+ }
+ }
+
+ private BASE64()
+ {
+ }
+
+ /**
+ * Encode the specified byte array using the BASE64 algorithm.
+ *
+ * @param bs the source byte array
+ */
+ public static byte[] encode(byte[] bs)
+ {
+ int si = 0, ti = 0; // source/target array indices
+ byte[] bt = new byte[((bs.length + 2) * 4) / 3]; // target byte array
+ for (; si < bs.length; si += 3)
+ {
+ int buflen = bs.length - si;
+ if (buflen == 1)
+ {
+ byte b = bs[si];
+ int i = 0;
+ bt[ti++] = src[b >>> 2 & 0x3f];
+ bt[ti++] = src[(b << 4 & 0x30) + (i >>> 4 & 0xf)];
+ }
+ else if (buflen == 2)
+ {
+ byte b1 = bs[si], b2 = bs[si + 1];
+ int i = 0;
+ bt[ti++] = src[b1 >>> 2 & 0x3f];
+ bt[ti++] = src[(b1 << 4 & 0x30) + (b2 >>> 4 & 0xf)];
+ bt[ti++] = src[(b2 << 2 & 0x3c) + (i >>> 6 & 0x3)];
+ }
+ else
+ {
+ byte b1 = bs[si], b2 = bs[si + 1], b3 = bs[si + 2];
+ bt[ti++] = src[b1 >>> 2 & 0x3f];
+ bt[ti++] = src[(b1 << 4 & 0x30) + (b2 >>> 4 & 0xf)];
+ bt[ti++] = src[(b2 << 2 & 0x3c) + (b3 >>> 6 & 0x3)];
+ bt[ti++] = src[b3 & 0x3f];
+ }
+ }
+ if (ti < bt.length)
+ {
+ byte[] tmp = new byte[ti];
+ System.arraycopy(bt, 0, tmp, 0, ti);
+ bt = tmp;
+ }
+ /*while (ti < bt.length)
+ {
+ bt[ti++] = 0x3d;
+ }*/
+ return bt;
+ }
+
+ /**
+ * Decode the specified byte array using the BASE64 algorithm.
+ *
+ * @param bs the source byte array
+ */
+ public static byte[] decode(byte[] bs)
+ {
+ int srclen = bs.length;
+ while (srclen > 0 && bs[srclen - 1] == 0x3d)
+ {
+ srclen--; /* strip padding character */
+ }
+ byte[] buffer = new byte[srclen];
+ int buflen = 0;
+ int si = 0;
+ int len = srclen - si;
+ while (len > 0)
+ {
+ byte b0 = dst[bs[si++] & 0xff];
+ byte b2 = dst[bs[si++] & 0xff];
+ buffer[buflen++] = (byte) (b0 << 2 & 0xfc | b2 >>> 4 & 0x3);
+ if (len > 2)
+ {
+ b0 = b2;
+ b2 = dst[bs[si++] & 0xff];
+ buffer[buflen++] = (byte) (b0 << 4 & 0xf0 | b2 >>> 2 & 0xf);
+ if (len > 3)
+ {
+ b0 = b2;
+ b2 = dst[bs[si++] & 0xff];
+ buffer[buflen++] = (byte) (b0 << 6 & 0xc0 | b2 & 0x3f);
+ }
+ }
+ len = srclen - si;
+ }
+ byte[] bt = new byte[buflen];
+ System.arraycopy(buffer, 0, bt, 0, buflen);
+ return bt;
+ }
+
+ public static void main(String[] args)
+ {
+ boolean decode = false;
+ for (int i = 0; i < args.length; i++)
+ {
+ if (args[i].equals("-d"))
+ {
+ decode = true;
+ }
+ else
+ {
+ try
+ {
+ byte[] in = args[i].getBytes("US-ASCII");
+ byte[] out = decode ? decode(in) : encode(in);
+ System.out.println(args[i] + " = " +
+ new String(out, "US-ASCII"));
+ }
+ catch (java.io.UnsupportedEncodingException e)
+ {
+ e.printStackTrace(System.err);
+ }
+ }
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/java/net/CRLFInputStream.java b/libjava/classpath/gnu/java/net/CRLFInputStream.java
new file mode 100644
index 00000000000..d0f9e8c4130
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/CRLFInputStream.java
@@ -0,0 +1,174 @@
+/* CRLFInputStream.java --
+ Copyright (C) 2002, 2003, 2004 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;
+
+import java.io.BufferedInputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * An input stream that filters out CR/LF pairs into LFs.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class CRLFInputStream
+ extends FilterInputStream
+{
+ /**
+ * The CR octet.
+ */
+ public static final int CR = 13;
+
+ /**
+ * The LF octet.
+ */
+ public static final int LF = 10;
+
+ private boolean doReset;
+
+ /**
+ * Constructs a CR/LF input stream connected to the specified input
+ * stream.
+ */
+ public CRLFInputStream(InputStream in)
+ {
+ super(in.markSupported() ? in : new BufferedInputStream(in));
+ }
+
+ /**
+ * Reads the next byte of data from this input stream.
+ * Returns -1 if the end of the stream has been reached.
+ * @exception IOException if an I/O error occurs
+ */
+ public int read()
+ throws IOException
+ {
+ int c = in.read();
+ if (c == CR)
+ {
+ in.mark(1);
+ int d = in.read();
+ if (d == LF)
+ {
+ c = d;
+ }
+ else
+ {
+ in.reset();
+ }
+ }
+ return c;
+ }
+
+ /**
+ * Reads up to b.length bytes of data from this input stream into
+ * an array of bytes.
+ * Returns -1 if the end of the stream has been reached.
+ * @exception IOException if an I/O error occurs
+ */
+ public int read(byte[] b)
+ throws IOException
+ {
+ return read(b, 0, b.length);
+ }
+
+ /**
+ * Reads up to len bytes of data from this input stream into an
+ * array of bytes, starting at the specified offset.
+ * Returns -1 if the end of the stream has been reached.
+ * @exception IOException if an I/O error occurs
+ */
+ public int read(byte[] b, int off, int len)
+ throws IOException
+ {
+ in.mark(len + 1);
+ int l = in.read(b, off, len);
+ if (l > 0)
+ {
+ int i = indexOfCRLF(b, off, l);
+ if (doReset)
+ {
+ in.reset();
+ if (i != -1)
+ {
+ l = in.read(b, off, i + 1); // read to CR
+ in.read(); // skip LF
+ b[i] = LF; // fix CR as LF
+ }
+ else
+ {
+ l = in.read(b, off, len); // CR(s) but no LF
+ }
+ }
+ }
+ return l;
+ }
+
+ private int indexOfCRLF(byte[] b, int off, int len)
+ throws IOException
+ {
+ doReset = false;
+ int lm1 = len - 1;
+ for (int i = off; i < len; i++)
+ {
+ if (b[i] == CR)
+ {
+ int d;
+ if (i == lm1)
+ {
+ d = in.read();
+ doReset = true;
+ }
+ else
+ {
+ d = b[i + 1];
+ }
+ if (d == LF)
+ {
+ doReset = true;
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/CRLFOutputStream.java b/libjava/classpath/gnu/java/net/CRLFOutputStream.java
new file mode 100644
index 00000000000..f27e0f218ad
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/CRLFOutputStream.java
@@ -0,0 +1,183 @@
+/* CRLFOutputStream.java --
+ Copyright (C) 2002, 2003, 2004 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;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+
+/**
+ * An output stream that filters LFs into CR/LF pairs.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class CRLFOutputStream
+ extends FilterOutputStream
+{
+ static final String US_ASCII = "US-ASCII";
+
+ /**
+ * The CR octet.
+ */
+ public static final int CR = 13;
+
+ /**
+ * The LF octet.
+ */
+ public static final int LF = 10;
+
+ /**
+ * The CR/LF pair.
+ */
+ public static final byte[] CRLF = { CR, LF };
+
+ /**
+ * The last byte read.
+ */
+ protected int last;
+
+ /**
+ * Constructs a CR/LF output stream connected to the specified output stream.
+ */
+ public CRLFOutputStream(OutputStream out)
+ {
+ super(out);
+ last = -1;
+ }
+
+ /**
+ * Writes a character to the underlying stream.
+ * @exception IOException if an I/O error occurred
+ */
+ public void write(int ch) throws IOException
+ {
+ if (ch == CR)
+ {
+ out.write(CRLF);
+ }
+ else if (ch == LF)
+ {
+ if (last != CR)
+ {
+ out.write(CRLF);
+ }
+ }
+ else
+ {
+ out.write(ch);
+ }
+ last = ch;
+ }
+
+ /**
+ * Writes a byte array to the underlying stream.
+ * @exception IOException if an I/O error occurred
+ */
+ public void write(byte[] b)
+ throws IOException
+ {
+ write(b, 0, b.length);
+ }
+
+ /**
+ * Writes a portion of a byte array to the underlying stream.
+ * @exception IOException if an I/O error occurred
+ */
+ public void write(byte[] b, int off, int len)
+ throws IOException
+ {
+ int d = off;
+ len += off;
+ for (int i = off; i < len; i++)
+ {
+ switch (b[i])
+ {
+ case CR:
+ out.write (b, d, i - d);
+ out.write (CRLF, 0, 2);
+ d = i + 1;
+ break;
+ case LF:
+ if (last != CR)
+ {
+ out.write (b, d, i - d);
+ out.write (CRLF, 0, 2);
+ }
+ d = i + 1;
+ break;
+ }
+ last = b[i];
+ }
+ if (len - d > 0)
+ {
+ out.write (b, d, len - d);
+ }
+ }
+
+ /**
+ * Writes the specified ASCII string to the underlying stream.
+ * @exception IOException if an I/O error occurred
+ */
+ public void write(String text)
+ throws IOException
+ {
+ try
+ {
+ byte[] bytes = text.getBytes(US_ASCII);
+ write(bytes, 0, bytes.length);
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ throw new IOException("The US-ASCII encoding is not supported " +
+ "on this system");
+ }
+ }
+
+ /**
+ * Writes a newline to the underlying stream.
+ * @exception IOException if an I/O error occurred
+ */
+ public void writeln()
+ throws IOException
+ {
+ out.write(CRLF, 0, 2);
+ }
+}
+
diff --git a/libjava/classpath/gnu/java/net/EmptyX509TrustManager.java b/libjava/classpath/gnu/java/net/EmptyX509TrustManager.java
new file mode 100644
index 00000000000..b8faf41add7
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/EmptyX509TrustManager.java
@@ -0,0 +1,70 @@
+/* EmptyX509TrustManager.java --
+ Copyright (C) 2004 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;
+
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.X509TrustManager;
+
+/**
+ * Empty implementation of an X509 trust manager.
+ * This implementation does not check any certificates in the chain.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class EmptyX509TrustManager
+ implements X509TrustManager
+{
+ public void checkClientTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException
+ {
+ }
+
+ public void checkServerTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException
+ {
+ }
+
+ public X509Certificate[] getAcceptedIssuers()
+ {
+ return new X509Certificate[0];
+ }
+}
+
diff --git a/libjava/classpath/gnu/java/net/GetLocalHostAction.java b/libjava/classpath/gnu/java/net/GetLocalHostAction.java
new file mode 100644
index 00000000000..7483b025773
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/GetLocalHostAction.java
@@ -0,0 +1,65 @@
+/* GetLocalHostAction.java --
+ Copyright (C) 2003, 2004 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;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.security.PrivilegedAction;
+
+/**
+ * Privileged action to retrieve the local host InetAddress.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class GetLocalHostAction
+ implements PrivilegedAction
+{
+ public Object run()
+ {
+ try
+ {
+ return InetAddress.getLocalHost();
+ }
+ catch (UnknownHostException e)
+ {
+ return null;
+ }
+ }
+}
+
diff --git a/libjava/classpath/gnu/java/net/HeaderFieldHelper.java b/libjava/classpath/gnu/java/net/HeaderFieldHelper.java
new file mode 100644
index 00000000000..0fb8d953d21
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/HeaderFieldHelper.java
@@ -0,0 +1,138 @@
+/* HeaderFieldHelper.java -- Helps manage headers fields
+ Copyright (C) 1998, 2003 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;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+/**
+ * This class manages header field keys and values.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class HeaderFieldHelper
+{
+ private Vector headerFieldKeys;
+ private Vector headerFieldValues;
+
+ public HeaderFieldHelper()
+ {
+ this (10);
+ }
+
+ public HeaderFieldHelper (int size)
+ {
+ headerFieldKeys = new Vector (size);
+ headerFieldValues = new Vector (size);
+ }
+
+ public void addHeaderField (String key, String value)
+ {
+ headerFieldKeys.addElement (key);
+ headerFieldValues.addElement (value);
+ }
+
+ public String getHeaderFieldKeyByIndex (int index)
+ {
+ String key = null;
+
+ try
+ {
+ key = (String) headerFieldKeys.elementAt (index);
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ }
+
+ return key;
+ }
+
+ public String getHeaderFieldValueByIndex(int index)
+ {
+ String value = null;
+
+ try
+ {
+ value = (String) headerFieldValues.elementAt (index);
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ }
+
+ return value;
+ }
+
+ public String getHeaderFieldValueByKey(String key)
+ {
+ String value = null;
+
+ try
+ {
+ value = (String) headerFieldValues.elementAt
+ (headerFieldKeys.indexOf(key));
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ }
+
+ return value;
+ }
+
+ public Map getHeaderFields()
+ {
+ HashMap headers = new HashMap();
+ int max = headerFieldKeys.size();
+
+ for (int index = 0; index < max; index++)
+ {
+ headers.put(headerFieldKeys.elementAt(index),
+ headerFieldValues.elementAt(index));
+ }
+
+ return headers;
+ }
+
+ public int getNumberOfEntries()
+ {
+ return headerFieldKeys.size();
+ }
+
+} // class HeaderFieldHelper
+
diff --git a/libjava/classpath/gnu/java/net/LineInputStream.java b/libjava/classpath/gnu/java/net/LineInputStream.java
new file mode 100644
index 00000000000..5ca068618da
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/LineInputStream.java
@@ -0,0 +1,198 @@
+/* LineInputStream.java --
+ Copyright (C) 2002, 2003, 2004 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;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * An input stream that can read lines of input.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class LineInputStream
+ extends FilterInputStream
+{
+ /*
+ * Line buffer.
+ */
+ private ByteArrayOutputStream buf;
+
+ /*
+ * Encoding to use when translating bytes to characters.
+ */
+ private String encoding;
+
+ /*
+ * End-of-stream flag.
+ */
+ private boolean eof;
+
+ /**
+ * Whether we can use block reads.
+ */
+ private final boolean blockReads;
+
+ /**
+ * Constructor using the US-ASCII character encoding.
+ * @param in the underlying input stream
+ */
+ public LineInputStream(InputStream in)
+ {
+ this(in, "US-ASCII");
+ }
+
+ /**
+ * Constructor.
+ * @param in the underlying input stream
+ * @param encoding the character encoding to use
+ */
+ public LineInputStream(InputStream in, String encoding)
+ {
+ super(in);
+ buf = new ByteArrayOutputStream();
+ this.encoding = encoding;
+ eof = false;
+ blockReads = in.markSupported();
+ }
+
+ /**
+ * Read a line of input.
+ */
+ public String readLine()
+ throws IOException
+ {
+ if (eof)
+ {
+ return null;
+ }
+ do
+ {
+ if (blockReads)
+ {
+ // Use mark and reset to read chunks of bytes
+ final int MIN_LENGTH = 1024;
+ int len, pos;
+
+ len = in.available();
+ len = (len < MIN_LENGTH) ? MIN_LENGTH : len;
+ byte[] b = new byte[len];
+ in.mark(len);
+ // Read into buffer b
+ len = in.read(b, 0, len);
+ // Handle EOF
+ if (len == -1)
+ {
+ eof = true;
+ if (buf.size() == 0)
+ {
+ return null;
+ }
+ else
+ {
+ // We don't care about resetting buf
+ return buf.toString(encoding);
+ }
+ }
+ // Get index of LF in b
+ pos = indexOf(b, len, (byte) 0x0a);
+ if (pos != -1)
+ {
+ // Write pos bytes to buf
+ buf.write(b, 0, pos);
+ // Reset stream, and read pos + 1 bytes
+ in.reset();
+ pos += 1;
+ while (pos > 0)
+ {
+ len = in.read(b, 0, pos);
+ pos = (len == -1) ? -1 : pos - len;
+ }
+ // Return line
+ String ret = buf.toString(encoding);
+ buf.reset();
+ return ret;
+ }
+ else
+ {
+ // Append everything to buf and fall through to re-read.
+ buf.write(b, 0, len);
+ }
+ }
+ else
+ {
+ // We must use character reads in order not to read too much
+ // from the underlying stream.
+ int c = in.read();
+ switch (c)
+ {
+ case -1:
+ eof = true;
+ if (buf.size() == 0)
+ {
+ return null;
+ }
+ // Fall through and return contents of buffer.
+ case 0x0a: // LF
+ String ret = buf.toString(encoding);
+ buf.reset();
+ return ret;
+ default:
+ buf.write(c);
+ }
+ }
+ }
+ while (true);
+ }
+
+ private int indexOf(byte[] b, int len, byte c)
+ {
+ for (int pos = 0; pos < len; pos++)
+ {
+ if (b[pos] == c)
+ {
+ return pos;
+ }
+ }
+ return -1;
+ }
+}
+
diff --git a/libjava/classpath/gnu/java/net/PlainDatagramSocketImpl.java b/libjava/classpath/gnu/java/net/PlainDatagramSocketImpl.java
new file mode 100644
index 00000000000..339b5561cf2
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/PlainDatagramSocketImpl.java
@@ -0,0 +1,321 @@
+/* PlainDatagramSocketImpl.java -- Default DatagramSocket implementation
+ Copyright (C) 1998, 1999, 2001, 2003, 2004, 2005 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;
+
+import gnu.classpath.Configuration;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocketImpl;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketAddress;
+import java.net.SocketException;
+
+/**
+ * Written using on-line Java Platform 1.2 API Specification, as well
+ * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
+ * Status: Believed complete and correct.
+ */
+
+/**
+ * This is the default socket implementation for datagram sockets.
+ * It makes native calls to C routines that implement BSD style
+ * SOCK_DGRAM sockets in the AF_INET family.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Warren Levy (warrenl@cygnus.com)
+ */
+public final class PlainDatagramSocketImpl extends DatagramSocketImpl
+{
+ // Static initializer to load native library
+ static
+ {
+ if (Configuration.INIT_LOAD_LIBRARY)
+ {
+ System.loadLibrary("javanet");
+ }
+ }
+
+ /**
+ * Option id for the IP_TTL (time to live) value.
+ */
+ private static final int IP_TTL = 0x1E61; // 7777
+
+ /**
+ * This is the actual underlying file descriptor
+ */
+ int native_fd = -1;
+
+ /**
+ * Lock object to serialize threads wanting to receive
+ */
+ private final Object RECEIVE_LOCK = new Object();
+
+ /**
+ * Lock object to serialize threads wanting to send
+ */
+ private final Object SEND_LOCK = new Object();
+
+ /**
+ * Default do nothing constructor
+ */
+ public PlainDatagramSocketImpl()
+ {
+ }
+
+ protected void finalize() throws Throwable
+ {
+ synchronized (this)
+ {
+ if (native_fd != -1)
+ close();
+ }
+ super.finalize();
+ }
+
+ public int getNativeFD()
+ {
+ return native_fd;
+ }
+
+ /**
+ * Binds this socket to a particular port and interface
+ *
+ * @param port The port to bind to
+ * @param addr The address to bind to
+ *
+ * @exception SocketException If an error occurs
+ */
+ protected synchronized native void bind(int port, InetAddress addr)
+ throws SocketException;
+
+ /**
+ * Creates a new datagram socket
+ *
+ * @exception SocketException If an error occurs
+ */
+ protected synchronized native void create() throws SocketException;
+
+ /**
+ * Sets the Time to Live value for the socket
+ *
+ * @param ttl The new TTL value
+ *
+ * @exception IOException If an error occurs
+ */
+ protected synchronized void setTimeToLive(int ttl) throws IOException
+ {
+ setOption(IP_TTL, new Integer(ttl));
+ }
+
+ /**
+ * Gets the Time to Live value for the socket
+ *
+ * @return The TTL value
+ *
+ * @exception IOException If an error occurs
+ */
+ protected synchronized int getTimeToLive() throws IOException
+ {
+ Object obj = getOption(IP_TTL);
+
+ if (! (obj instanceof Integer))
+ throw new IOException("Internal Error");
+
+ return ((Integer) obj).intValue();
+ }
+
+ /**
+ * Sends a packet of data to a remote host
+ *
+ * @param addr The address to send to
+ * @param port The port to send to
+ * @param buf The buffer to send
+ * @param offset The offset of the data in the buffer to send
+ * @param len The length of the data to send
+ *
+ * @exception IOException If an error occurs
+ */
+ private native void sendto (InetAddress addr, int port,
+ byte[] buf, int offset, int len)
+ throws IOException;
+
+ /**
+ * Sends a packet of data to a remote host
+ *
+ * @param packet The packet to send
+ *
+ * @exception IOException If an error occurs
+ */
+ protected void send(DatagramPacket packet) throws IOException
+ {
+ synchronized(SEND_LOCK)
+ {
+ sendto(packet.getAddress(), packet.getPort(), packet.getData(),
+ packet.getOffset(), packet.getLength());
+ }
+
+ }
+
+ /**
+ * Receives a UDP packet from the network
+ *
+ * @param packet The packet to fill in with the data received
+ *
+ * @exception IOException IOException If an error occurs
+ */
+ protected void receive(DatagramPacket packet)
+ throws IOException
+ {
+ synchronized(RECEIVE_LOCK)
+ {
+ receive0(packet);
+ }
+ }
+
+ /**
+ * Native call to receive a UDP packet from the network
+ *
+ * @param packet The packet to fill in with the data received
+ *
+ * @exception IOException IOException If an error occurs
+ */
+ private native void receive0(DatagramPacket packet) throws IOException;
+
+ /**
+ * Sets the value of an option on the socket
+ *
+ * @param option_id The identifier of the option to set
+ * @param val The value of the option to set
+ *
+ * @exception SocketException If an error occurs
+ */
+ public synchronized native void setOption(int option_id, Object val)
+ throws SocketException;
+
+ /**
+ * Retrieves the value of an option on the socket
+ *
+ * @param option_id The identifier of the option to retrieve
+ *
+ * @return The value of the option
+ *
+ * @exception SocketException If an error occurs
+ */
+ public synchronized native Object getOption(int option_id)
+ throws SocketException;
+
+ /**
+ * Closes the socket
+ */
+ protected synchronized native void close();
+
+ /**
+ * Gets the Time to Live value for the socket
+ *
+ * @return The TTL value
+ *
+ * @exception IOException If an error occurs
+ *
+ * @deprecated 1.2
+ */
+ protected synchronized byte getTTL() throws IOException
+ {
+ return (byte) getTimeToLive();
+ }
+
+ /**
+ * Sets the Time to Live value for the socket
+ *
+ * @param ttl The new TTL value
+ *
+ * @exception IOException If an error occurs
+ *
+ * @deprecated 1.2
+ */
+ protected synchronized void setTTL(byte ttl) throws IOException
+ {
+ setTimeToLive(((int) ttl) & 0xFF);
+ }
+
+ /**
+ * Joins a multicast group
+ *
+ * @param addr The group to join
+ *
+ * @exception IOException If an error occurs
+ */
+ protected synchronized native void join(InetAddress addr) throws IOException;
+
+ /**
+ * Leaves a multicast group
+ *
+ * @param addr The group to leave
+ *
+ * @exception IOException If an error occurs
+ */
+ protected synchronized native void leave(InetAddress addr) throws IOException;
+
+ /**
+ * What does this method really do?
+ */
+ protected synchronized int peek(InetAddress addr) throws IOException
+ {
+ throw new IOException("Not Implemented Yet");
+ }
+
+ public int peekData(DatagramPacket packet)
+ {
+ throw new InternalError
+ ("PlainDatagramSocketImpl::peekData is not implemented");
+ }
+
+ public void joinGroup(SocketAddress address, NetworkInterface netIf)
+ {
+ throw new InternalError
+ ("PlainDatagramSocketImpl::joinGroup is not implemented");
+ }
+
+ public void leaveGroup(SocketAddress address, NetworkInterface netIf)
+ {
+ throw new InternalError
+ ("PlainDatagramSocketImpl::leaveGroup is not implemented");
+ }
+}
diff --git a/libjava/classpath/gnu/java/net/PlainSocketImpl.java b/libjava/classpath/gnu/java/net/PlainSocketImpl.java
new file mode 100644
index 00000000000..05221ff88e9
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/PlainSocketImpl.java
@@ -0,0 +1,498 @@
+/* PlainSocketImpl.java -- Default socket implementation
+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ 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;
+
+import gnu.classpath.Configuration;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.net.SocketImpl;
+import java.net.SocketOptions;
+
+/**
+ * Written using on-line Java Platform 1.2 API Specification, as well
+ * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
+ * Status: Believed complete and correct.
+ */
+
+/**
+ * Unless the application installs its own SocketImplFactory, this is the
+ * default socket implemetation that will be used. It simply uses a
+ * combination of Java and native routines to implement standard BSD
+ * style sockets of family AF_INET and types SOCK_STREAM and SOCK_DGRAM
+ *
+ * @author Per Bothner (bothner@cygnus.com)
+ * @author Nic Ferrier (nferrier@tapsellferrier.co.uk)
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public final class PlainSocketImpl extends SocketImpl
+{
+ // Static initializer to load native library.
+ static
+ {
+ if (Configuration.INIT_LOAD_LIBRARY)
+ {
+ System.loadLibrary("javanet");
+ }
+ }
+
+ /**
+ * The OS file handle representing the socket.
+ * This is used for reads and writes to/from the socket and
+ * to close it.
+ *
+ * When the socket is closed this is reset to -1.
+ */
+ int native_fd = -1;
+
+ /**
+ * A cached copy of the in stream for reading from the socket.
+ */
+ private InputStream in;
+
+ /**
+ * A cached copy of the out stream for writing to the socket.
+ */
+ private OutputStream out;
+
+ /**
+ * Indicates whether a channel initiated whatever operation
+ * is being invoked on this socket.
+ */
+ private boolean inChannelOperation;
+
+ /**
+ * Indicates whether we should ignore whether any associated
+ * channel is set to non-blocking mode. Certain operations
+ * throw an <code>IllegalBlockingModeException</code> if the
+ * associated channel is in non-blocking mode, <i>except</i>
+ * if the operation is invoked by the channel itself.
+ */
+ public final boolean isInChannelOperation()
+ {
+ return inChannelOperation;
+ }
+
+ /**
+ * Sets our indicator of whether an I/O operation is being
+ * initiated by a channel.
+ */
+ public final void setInChannelOperation(boolean b)
+ {
+ inChannelOperation = b;
+ }
+
+ /**
+ * Default do nothing constructor
+ */
+ public PlainSocketImpl()
+ {
+ }
+
+ protected void finalize() throws Throwable
+ {
+ synchronized (this)
+ {
+ if (native_fd != -1)
+ try
+ {
+ close();
+ }
+ catch (IOException ex)
+ {
+ }
+ }
+ super.finalize();
+ }
+
+ public int getNativeFD()
+ {
+ return native_fd;
+ }
+
+ /**
+ * Sets the specified option on a socket to the passed in object. For
+ * options that take an integer argument, the passed in object is an
+ * Integer. The option_id parameter is one of the defined constants in
+ * this interface.
+ *
+ * @param option_id The identifier of the option
+ * @param val The value to set the option to
+ *
+ * @exception SocketException If an error occurs
+ */
+ public native void setOption(int optID, Object value) throws SocketException;
+
+ /**
+ * Returns the current setting of the specified option. The Object returned
+ * will be an Integer for options that have integer values. The option_id
+ * is one of the defined constants in this interface.
+ *
+ * @param option_id The option identifier
+ *
+ * @return The current value of the option
+ *
+ * @exception SocketException If an error occurs
+ */
+ public native Object getOption(int optID) throws SocketException;
+
+ /**
+ * Flushes the input stream and closes it. If you read from the input stream
+ * after calling this method a <code>IOException</code> will be thrown.
+ *
+ * @throws IOException if an error occurs
+ */
+ public native void shutdownInput() throws IOException;
+
+ /**
+ * Flushes the output stream and closes it. If you write to the output stream
+ * after calling this method a <code>IOException</code> will be thrown.
+ *
+ * @throws IOException if an error occurs
+ */
+ public native void shutdownOutput() throws IOException;
+
+ /**
+ * Creates a new socket that is not bound to any local address/port and
+ * is not connected to any remote address/port. This will be created as
+ * a stream socket if the stream parameter is true, or a datagram socket
+ * if the stream parameter is false.
+ *
+ * @param stream true for a stream socket, false for a datagram socket
+ */
+ protected synchronized native void create(boolean stream) throws IOException;
+
+ /**
+ * Connects to the remote hostname and port specified as arguments.
+ *
+ * @param hostname The remote hostname to connect to
+ * @param port The remote port to connect to
+ *
+ * @exception IOException If an error occurs
+ */
+ protected synchronized void connect(String host, int port) throws IOException
+ {
+ connect(InetAddress.getByName(host), port);
+ }
+
+ /**
+ * Connects to the remote address and port specified as arguments.
+ *
+ * @param addr The remote address to connect to
+ * @param port The remote port to connect to
+ *
+ * @exception IOException If an error occurs
+ */
+ protected native void connect(InetAddress addr, int port) throws IOException;
+
+ /**
+ * Connects to the remote socket address with a specified timeout.
+ *
+ * @param timeout The timeout to use for this connect, 0 means infinite.
+ *
+ * @exception IOException If an error occurs
+ */
+ protected synchronized void connect(SocketAddress address, int timeout) throws IOException
+ {
+ InetSocketAddress sockAddr = (InetSocketAddress) address;
+ InetAddress addr = sockAddr.getAddress();
+
+ if (addr == null)
+ throw new IllegalArgumentException("address is unresolved: " + sockAddr);
+
+ int port = sockAddr.getPort();
+
+ if (timeout < 0)
+ throw new IllegalArgumentException("negative timeout");
+
+ Object oldTimeoutObj = null;
+
+ try
+ {
+ oldTimeoutObj = this.getOption (SocketOptions.SO_TIMEOUT);
+ this.setOption (SocketOptions.SO_TIMEOUT, new Integer (timeout));
+ connect (addr, port);
+ }
+ finally
+ {
+ if (oldTimeoutObj != null)
+ this.setOption (SocketOptions.SO_TIMEOUT, oldTimeoutObj);
+ }
+ }
+
+ /**
+ * Binds to the specified port on the specified addr. Note that this addr
+ * must represent a local IP address. **** How bind to INADDR_ANY? ****
+ *
+ * @param addr The address to bind to
+ * @param port The port number to bind to
+ *
+ * @exception IOException If an error occurs
+ */
+ protected synchronized native void bind(InetAddress addr, int port)
+ throws IOException;
+
+ /**
+ * Starts listening for connections on a socket. The queuelen parameter
+ * is how many pending connections will queue up waiting to be serviced
+ * before being accept'ed. If the queue of pending requests exceeds this
+ * number, additional connections will be refused.
+ *
+ * @param queuelen The length of the pending connection queue
+ *
+ * @exception IOException If an error occurs
+ */
+ protected synchronized native void listen(int queuelen)
+ throws IOException;
+
+ /**
+ * Accepts a new connection on this socket and returns in in the
+ * passed in SocketImpl.
+ *
+ * @param impl The SocketImpl object to accept this connection.
+ */
+ protected synchronized native void accept(SocketImpl impl)
+ throws IOException;
+
+ /**
+ * Returns the number of bytes that the caller can read from this socket
+ * without blocking.
+ *
+ * @return The number of readable bytes before blocking
+ *
+ * @exception IOException If an error occurs
+ */
+ protected native int available() throws IOException;
+
+ /**
+ * Closes the socket. This will cause any InputStream or OutputStream
+ * objects for this Socket to be closed as well.
+ * <p>
+ * Note that if the SO_LINGER option is set on this socket, then the
+ * operation could block.
+ *
+ * @exception IOException If an error occurs
+ */
+ protected native void close() throws IOException;
+
+ public void sendUrgentData(int data)
+ {
+ throw new InternalError ("PlainSocketImpl::sendUrgentData not implemented");
+ }
+
+ /**
+ * Internal method used by SocketInputStream for reading data from
+ * the connection. Reads up to len bytes of data into the buffer
+ * buf starting at offset bytes into the buffer.
+ *
+ * @return The actual number of bytes read or -1 if end of stream.
+ *
+ * @exception IOException If an error occurs
+ */
+ protected native int read(byte[] buf, int offset, int len)
+ throws IOException;
+
+ /**
+ * Internal method used by SocketOuputStream for writing data to
+ * the connection. Writes up to len bytes of data from the buffer
+ * buf starting at offset bytes into the buffer.
+ *
+ * @exception IOException If an error occurs
+ */
+ protected native void write(byte[] buf, int offset, int len)
+ throws IOException;
+
+ /**
+ * Returns an InputStream object for reading from this socket. This will
+ * be an instance of SocketInputStream.
+ *
+ * @return An input stream attached to the socket.
+ *
+ * @exception IOException If an error occurs
+ */
+ protected synchronized InputStream getInputStream() throws IOException
+ {
+ if (in == null)
+ in = new SocketInputStream();
+
+ return in;
+ }
+
+ /**
+ * Returns an OutputStream object for writing to this socket. This will
+ * be an instance of SocketOutputStream.
+ *
+ * @return An output stream attached to the socket.
+ *
+ * @exception IOException If an error occurs
+ */
+ protected synchronized OutputStream getOutputStream() throws IOException
+ {
+ if (out == null)
+ out = new SocketOutputStream();
+
+ return out;
+ }
+
+ /**
+ * This class contains an implementation of <code>InputStream</code> for
+ * sockets. It in an internal only class used by <code>PlainSocketImpl</code>.
+ *
+ * @author Nic Ferrier (nferrier@tapsellferrier.co.uk)
+ */
+ final class SocketInputStream
+ extends InputStream
+ {
+ /**
+ * Returns the number of bytes available to be read before blocking
+ */
+ public int available() throws IOException
+ {
+ return PlainSocketImpl.this.available();
+ }
+
+ /**
+ * This method not only closes the stream, it closes the underlying socket
+ * (and thus any connection) and invalidates any other Input/Output streams
+ * for the underlying impl object
+ */
+ public void close() throws IOException
+ {
+ PlainSocketImpl.this.close();
+ }
+
+ /**
+ * Reads the next byte of data and returns it as an int.
+ *
+ * @return The byte read (as an int) or -1 if end of stream);
+ *
+ * @exception IOException If an error occurs.
+ */
+ public int read() throws IOException
+ {
+ byte buf[] = new byte [1];
+ int bytes_read = read(buf, 0, 1);
+
+ if (bytes_read == -1)
+ return -1;
+
+ return buf[0] & 0xFF;
+ }
+
+ /**
+ * Reads up to len bytes of data into the caller supplied buffer starting
+ * at offset bytes from the start of the buffer
+ *
+ * @param buf The buffer
+ * @param offset Offset into the buffer to start reading from
+ * @param len The number of bytes to read
+ *
+ * @return The number of bytes actually read or -1 if end of stream
+ *
+ * @exception IOException If an error occurs.
+ */
+ public int read (byte[] buf, int offset, int len) throws IOException
+ {
+ int bytes_read = PlainSocketImpl.this.read (buf, offset, len);
+
+ if (bytes_read == 0)
+ return -1;
+
+ return bytes_read;
+ }
+ }
+
+ /**
+ * This class is used internally by <code>PlainSocketImpl</code> to be the
+ * <code>OutputStream</code> subclass returned by its
+ * <code>getOutputStream method</code>. It expects only to be used in that
+ * context.
+ *
+ * @author Nic Ferrier (nferrier@tapsellferrier.co.uk)
+ */
+ final class SocketOutputStream
+ extends OutputStream
+ {
+ /**
+ * This method closes the stream and the underlying socket connection. This
+ * action also effectively closes any other InputStream or OutputStream
+ * object associated with the connection.
+ *
+ * @exception IOException If an error occurs
+ */
+ public void close() throws IOException
+ {
+ PlainSocketImpl.this.close();
+ }
+
+ /**
+ * Writes a byte (passed in as an int) to the given output stream
+ *
+ * @param b The byte to write
+ *
+ * @exception IOException If an error occurs
+ */
+ public void write(int b) throws IOException
+ {
+ byte buf[] = { (byte) b };
+ write(buf, 0, 1);
+ }
+
+ /**
+ * Writes len number of bytes from the array buf to the stream starting
+ * at offset bytes into the buffer.
+ *
+ * @param buf The buffer
+ * @param offset Offset into the buffer to start writing from
+ * @param len The number of bytes to write
+ *
+ * @exception IOException If an error occurs.
+ */
+ public void write (byte[] buf, int offset, int len) throws IOException
+ {
+ PlainSocketImpl.this.write (buf, offset, len);
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/java/net/URLParseError.java b/libjava/classpath/gnu/java/net/URLParseError.java
new file mode 100644
index 00000000000..90907480f11
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/URLParseError.java
@@ -0,0 +1,57 @@
+/* URLParseError.java -- Helps bypassing the exception limitation for
+ URLStreamHandler.parseURL().
+ Copyright (C) 2003 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;
+
+/**
+ * This class helps the people writing protocols to report URL parse
+ * errors in parseUrl as this method cannot report other exceptions
+ * than Errors.
+ *
+ * The main drawback is that it uses the Error mechanism which should not
+ * be used for that type of error reporting.
+ *
+ * @author Guilhem Lavaux (guilhem@kaffe.org)
+ */
+public class URLParseError extends Error
+{
+ public URLParseError(String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/libjava/classpath/gnu/java/net/package.html b/libjava/classpath/gnu/java/net/package.html
new file mode 100644
index 00000000000..5641fbd92cf
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/package.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.net package.
+ Copyright (C) 2005 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. -->
+
+<html>
+<head><title>GNU Classpath - gnu.java.net</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
diff --git a/libjava/classpath/gnu/java/net/protocol/file/Connection.java b/libjava/classpath/gnu/java/net/protocol/file/Connection.java
new file mode 100644
index 00000000000..52bd0484510
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/file/Connection.java
@@ -0,0 +1,319 @@
+/* FileURLConnection.java -- URLConnection class for "file" protocol
+ Copyright (C) 1998, 1999, 2003 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.file;
+
+import gnu.classpath.SystemProperties;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FilePermission;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.net.ProtocolException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.security.Permission;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * This subclass of java.net.URLConnection models a URLConnection via
+ * the "file" protocol.
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Nic Ferrier (nferrier@tapsellferrier.co.uk)
+ * @author Warren Levy (warrenl@cygnus.com)
+ */
+public class Connection extends URLConnection
+{
+ /**
+ * Default permission for a file
+ */
+ private static final String DEFAULT_PERMISSION = "read";
+
+ private static class StaticData
+ {
+ /**
+ * HTTP-style DateFormat, used to format the last-modified header.
+ */
+ static SimpleDateFormat dateFormat
+ = new SimpleDateFormat("EEE, dd MMM yyyy hh:mm:ss 'GMT'",
+ new Locale ("En", "Us", "Unix"));
+
+ static String lineSeparator =
+ SystemProperties.getProperty("line.separator");
+ }
+
+
+ /**
+ * This is a File object for this connection
+ */
+ private File file;
+
+ /**
+ * If a directory, contains a list of files in the directory.
+ */
+ private byte[] directoryListing;
+
+ /**
+ * InputStream if we are reading from the file
+ */
+ private InputStream inputStream;
+
+ /**
+ * OutputStream if we are writing to the file
+ */
+ private OutputStream outputStream;
+
+ /**
+ * FilePermission to read the file
+ */
+ private FilePermission permission;
+
+ /**
+ * Calls superclass constructor to initialize.
+ */
+ public Connection(URL url)
+ {
+ super (url);
+
+ permission = new FilePermission(getURL().getFile(), DEFAULT_PERMISSION);
+ }
+
+ /**
+ * "Connects" to the file by opening it.
+ */
+ public void connect() throws IOException
+ {
+ // Call is ignored if already connected.
+ if (connected)
+ return;
+
+ // If not connected, then file needs to be openned.
+ file = new File (getURL().getFile());
+
+ if (! file.isDirectory())
+ {
+ if (doInput)
+ inputStream = new BufferedInputStream(new FileInputStream(file));
+
+ if (doOutput)
+ outputStream = new BufferedOutputStream(new FileOutputStream(file));
+ }
+ else
+ {
+ if (doInput)
+ {
+ inputStream = new ByteArrayInputStream(getDirectoryListing());
+ }
+
+ if (doOutput)
+ throw new ProtocolException
+ ("file: protocol does not support output on directories");
+ }
+
+ connected = true;
+ }
+
+ /**
+ * Populates the <code>directoryListing</code> field with a byte array
+ * containing a representation of the directory listing.
+ */
+ byte[] getDirectoryListing()
+ throws IOException
+ {
+ if (directoryListing == null)
+ {
+ ByteArrayOutputStream sink = new ByteArrayOutputStream();
+ // NB uses default character encoding for this system
+ Writer writer = new OutputStreamWriter(sink);
+
+ String[] files = file.list();
+
+ for (int i = 0; i < files.length; i++)
+ {
+ writer.write(files[i]);
+ writer.write(StaticData.lineSeparator);
+ }
+
+ directoryListing = sink.toByteArray();
+ }
+ return directoryListing;
+ }
+
+ /**
+ * Opens the file for reading and returns a stream for it.
+ *
+ * @return An InputStream for this connection.
+ *
+ * @exception IOException If an error occurs
+ */
+ public InputStream getInputStream()
+ throws IOException
+ {
+ if (!doInput)
+ throw new ProtocolException("Can't open InputStream if doInput is false");
+
+ if (!connected)
+ connect();
+
+ return inputStream;
+ }
+
+ /**
+ * Opens the file for writing and returns a stream for it.
+ *
+ * @return An OutputStream for this connection.
+ *
+ * @exception IOException If an error occurs.
+ */
+ public OutputStream getOutputStream()
+ throws IOException
+ {
+ if (!doOutput)
+ throw new
+ ProtocolException("Can't open OutputStream if doOutput is false");
+
+ if (!connected)
+ connect();
+
+ return outputStream;
+ }
+
+ /**
+ * Get the last modified time of the resource.
+ *
+ * @return the time since epoch that the resource was modified.
+ */
+ public long getLastModified()
+ {
+ try
+ {
+ if (!connected)
+ connect();
+
+ return file.lastModified();
+ }
+ catch (IOException e)
+ {
+ return -1;
+ }
+ }
+
+ /**
+ * Get an http-style header field. Just handle a few common ones.
+ */
+ public String getHeaderField(String field)
+ {
+ try
+ {
+ if (!connected)
+ connect();
+
+ if (field.equals("content-type"))
+ return guessContentTypeFromName(file.getName());
+ else if (field.equals("content-length"))
+ {
+ if (file.isDirectory())
+ {
+ return Integer.toString(getContentLength());
+ }
+ return Long.toString(file.length());
+ }
+ else if (field.equals("last-modified"))
+ {
+ synchronized (StaticData.dateFormat)
+ {
+ return StaticData.dateFormat.format(
+ new Date(file.lastModified()));
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ // Fall through.
+ }
+ return null;
+ }
+
+ /**
+ * Get the length of content.
+ *
+ * @return the length of the content.
+ */
+ public int getContentLength()
+ {
+ try
+ {
+ if (!connected)
+ connect();
+
+ if (file.isDirectory())
+ {
+ return getDirectoryListing().length;
+ }
+ return (int) file.length();
+ }
+ catch (IOException e)
+ {
+ return -1;
+ }
+ }
+
+ /**
+ * This method returns a <code>Permission</code> object representing the
+ * permissions required to access this URL. This method returns a
+ * <code>java.io.FilePermission</code> for the file's path with a read
+ * permission.
+ *
+ * @return A Permission object
+ */
+ public Permission getPermission() throws IOException
+ {
+ return permission;
+ }
+}
diff --git a/libjava/classpath/gnu/java/net/protocol/file/Handler.java b/libjava/classpath/gnu/java/net/protocol/file/Handler.java
new file mode 100644
index 00000000000..fc560491d19
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/file/Handler.java
@@ -0,0 +1,91 @@
+/* Handler.java -- "file" protocol handler for java.net
+ Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004 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.file;
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+
+/**
+ * This is the protocol handler for the "file" protocol.
+ * It implements the abstract openConnection() method from
+ * URLStreamHandler by returning a new FileURLConnection object (from
+ * this package). All other methods are inherited
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ * @author Warren Levy (warrenl@cygnus.com)
+ */
+public class Handler extends URLStreamHandler
+{
+ /**
+ * A do nothing constructor
+ */
+ public Handler()
+ {
+ }
+
+ /**
+ * This method returs a new FileURLConnection for the specified URL
+ *
+ * @param url The URL to return a connection for
+ *
+ * @return The URLConnection
+ *
+ * @exception IOException If an error occurs
+ */
+ protected URLConnection openConnection(URL url) throws IOException
+ {
+ // If a hostname is set, then we need to switch protocols to ftp
+ // in order to transfer this from the remote host.
+ String host = url.getHost();
+ if ((host != null) && (! host.equals("")))
+ {
+ // Reset the protocol (and implicitly the handler) for this URL.
+ // Then have the URL attempt the connection again, as it will
+ // get the changed handler the next time around.
+ // If the ftp protocol handler is not installed, an
+ // exception will be thrown from the new openConnection() call.
+ setURL (url, "ftp", url.getHost(), url.getPort(), url.getFile(),
+ url.getRef());
+ return url.openConnection();
+ }
+
+ return new Connection(url);
+ }
+} // class Handler
diff --git a/libjava/classpath/gnu/java/net/protocol/file/package.html b/libjava/classpath/gnu/java/net/protocol/file/package.html
new file mode 100644
index 00000000000..cbce7413fb9
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/file/package.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.net.protocol.file package.
+ Copyright (C) 2005 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. -->
+
+<html>
+<head><title>GNU Classpath - gnu.java.net.protocol.file</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/ActiveModeDTP.java b/libjava/classpath/gnu/java/net/protocol/ftp/ActiveModeDTP.java
new file mode 100644
index 00000000000..3755e8beb8d
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/ftp/ActiveModeDTP.java
@@ -0,0 +1,251 @@
+/* ActiveModeDTP.java --
+ Copyright (C) 2003, 2004 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.ftp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+/**
+ * An active mode FTP data transfer process.
+ * This starts a server on the specified port listening for a data
+ * connection. It converts the socket input into a file stream for reading.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+final class ActiveModeDTP
+ implements DTP, Runnable
+{
+
+ ServerSocket server;
+ Socket socket;
+ DTPInputStream in;
+ DTPOutputStream out;
+ boolean completed;
+ boolean inProgress;
+ int transferMode;
+ IOException exception;
+ Thread acceptThread;
+ int connectionTimeout;
+
+ ActiveModeDTP(InetAddress localhost, int port,
+ int connectionTimeout, int timeout)
+ throws IOException
+ {
+ completed = false;
+ inProgress = false;
+ server = new ServerSocket(port, 1, localhost);
+ if (timeout > 0)
+ {
+ server.setSoTimeout(timeout);
+ }
+ if (connectionTimeout <= 0)
+ {
+ connectionTimeout = 20000;
+ }
+ this.connectionTimeout = connectionTimeout;
+ acceptThread = new Thread(this, "ActiveModeDTP");
+ acceptThread.start();
+ }
+
+ /**
+ * Start listening.
+ */
+ public void run()
+ {
+ try
+ {
+ socket = server.accept();
+ //System.err.println("Accepted connection from "+socket.getInetAddress()+":"+socket.getPort());
+ }
+ catch (IOException e)
+ {
+ exception = e;
+ }
+ }
+
+ /**
+ * Waits until a client has connected.
+ */
+ public void waitFor()
+ throws IOException
+ {
+ try
+ {
+ acceptThread.join(connectionTimeout);
+ }
+ catch (InterruptedException e)
+ {
+ }
+ if (exception != null)
+ {
+ throw exception;
+ }
+ if (socket == null)
+ {
+ server.close();
+ throw new IOException("client did not connect before timeout");
+ }
+ acceptThread = null;
+ }
+
+ /**
+ * Returns an input stream from which a remote file can be read.
+ */
+ public InputStream getInputStream()
+ throws IOException
+ {
+ if (inProgress)
+ {
+ throw new IOException("Transfer in progress");
+ }
+ if (acceptThread != null)
+ {
+ waitFor();
+ }
+ switch (transferMode)
+ {
+ case FTPConnection.MODE_STREAM:
+ in = new StreamInputStream(this, socket.getInputStream());
+ break;
+ case FTPConnection.MODE_BLOCK:
+ in = new BlockInputStream(this, socket.getInputStream());
+ break;
+ case FTPConnection.MODE_COMPRESSED:
+ in = new CompressedInputStream(this, socket.getInputStream());
+ break;
+ default:
+ throw new IllegalStateException("invalid transfer mode");
+ }
+ in.setTransferComplete(false);
+ return in;
+ }
+
+ /**
+ * Returns an output stream to which a local file can be written for
+ * upload.
+ */
+ public OutputStream getOutputStream() throws IOException
+ {
+ if (inProgress)
+ {
+ throw new IOException("Transfer in progress");
+ }
+ if (acceptThread != null)
+ {
+ waitFor();
+ }
+ switch (transferMode)
+ {
+ case FTPConnection.MODE_STREAM:
+ out = new StreamOutputStream(this, socket.getOutputStream());
+ break;
+ case FTPConnection.MODE_BLOCK:
+ out = new BlockOutputStream(this, socket.getOutputStream());
+ break;
+ case FTPConnection.MODE_COMPRESSED:
+ out = new CompressedOutputStream(this, socket.getOutputStream());
+ break;
+ default:
+ throw new IllegalStateException("invalid transfer mode");
+ }
+ out.setTransferComplete(false);
+ return out;
+ }
+
+ public void setTransferMode(int mode)
+ {
+ transferMode = mode;
+ }
+
+ public void complete()
+ {
+ completed = true;
+ if (!inProgress)
+ {
+ transferComplete();
+ }
+ }
+
+ public boolean abort()
+ {
+ completed = true;
+ transferComplete();
+ return inProgress;
+ }
+
+ public void transferComplete()
+ {
+ if (socket == null)
+ {
+ return;
+ }
+ if (in != null)
+ {
+ in.setTransferComplete(true);
+ }
+ if (out != null)
+ {
+ out.setTransferComplete(true);
+ }
+ completed = completed || (transferMode == FTPConnection.MODE_STREAM);
+ if (completed && socket != null)
+ {
+ try
+ {
+ socket.close();
+ }
+ catch (IOException e)
+ {
+ }
+ try
+ {
+ server.close();
+ }
+ catch (IOException e)
+ {
+ }
+ }
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/BlockInputStream.java b/libjava/classpath/gnu/java/net/protocol/ftp/BlockInputStream.java
new file mode 100644
index 00000000000..63897f1d6db
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/ftp/BlockInputStream.java
@@ -0,0 +1,150 @@
+/* BlockInputStream.java --
+ Copyright (C) 2003, 2004 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.ftp;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * A DTP input stream that implements the FTP block transfer mode.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+class BlockInputStream
+ extends DTPInputStream
+{
+
+ static final int EOF = 64;
+
+ int descriptor;
+ int max = -1;
+ int count = -1;
+
+ BlockInputStream(DTP dtp, InputStream in)
+ {
+ super(dtp, in);
+ }
+
+ public int read()
+ throws IOException
+ {
+ if (transferComplete)
+ {
+ return -1;
+ }
+ if (count == -1)
+ {
+ readHeader();
+ }
+ if (max < 1)
+ {
+ close();
+ return -1;
+ }
+ int c = in.read();
+ if (c == -1)
+ {
+ dtp.transferComplete();
+ }
+ count++;
+ if (count >= max)
+ {
+ count = -1;
+ if (descriptor == EOF)
+ {
+ close();
+ }
+ }
+ return c;
+ }
+
+ public int read(byte[] buf)
+ throws IOException
+ {
+ return read(buf, 0, buf.length);
+ }
+
+ public int read(byte[] buf, int off, int len)
+ throws IOException
+ {
+ if (transferComplete)
+ {
+ return -1;
+ }
+ if (count == -1)
+ {
+ readHeader();
+ }
+ if (max < 1)
+ {
+ close();
+ return -1;
+ }
+ int l = in.read(buf, off, len);
+ if (l == -1)
+ {
+ dtp.transferComplete();
+ }
+ count += l;
+ if (count >= max)
+ {
+ count = -1;
+ if (descriptor == EOF)
+ {
+ close();
+ }
+ }
+ return l;
+ }
+
+ /**
+ * Reads the block header.
+ */
+ void readHeader()
+ throws IOException
+ {
+ descriptor = in.read();
+ int max_hi = in.read();
+ int max_lo = in.read();
+ max = (max_hi << 8) | max_lo;
+ count = 0;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/BlockOutputStream.java b/libjava/classpath/gnu/java/net/protocol/ftp/BlockOutputStream.java
new file mode 100644
index 00000000000..85481c95bd5
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/ftp/BlockOutputStream.java
@@ -0,0 +1,111 @@
+/* BlockOutputStream.java --
+ Copyright (C) 2003, 2004 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.ftp;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * A DTP output stream that implements the FTP block transfer mode.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+class BlockOutputStream
+ extends DTPOutputStream
+{
+
+ static final byte RECORD = -128; // 0x80
+ static final byte EOF = 64; // 0x40
+
+ BlockOutputStream(DTP dtp, OutputStream out)
+ {
+ super(dtp, out);
+ }
+
+ public void write(int c)
+ throws IOException
+ {
+ if (transferComplete)
+ {
+ return;
+ }
+ byte[] buf = new byte[]
+ {
+ RECORD, /* record descriptor */
+ 0x00, 0x01, /* one byte */
+ (byte) c /* the byte */
+ };
+ out.write(buf, 0, 4);
+ }
+
+ public void write(byte[] b)
+ throws IOException
+ {
+ write(b, 0, b.length);
+ }
+
+ public void write(byte[] b, int off, int len)
+ throws IOException
+ {
+ if (transferComplete)
+ {
+ return;
+ }
+ byte[] buf = new byte[len + 3];
+ buf[0] = RECORD; /* record descriptor */
+ buf[1] = (byte) ((len & 0x00ff) >> 8); /* high byte of bytecount */
+ buf[2] = (byte) (len & 0xff00); /* low byte of bytecount */
+ System.arraycopy(b, off, buf, 3, len);
+ out.write(buf, 0, len);
+ }
+
+ public void close()
+ throws IOException
+ {
+ byte[] buf = new byte[]
+ {
+ EOF, /* eof descriptor */
+ 0x00, 0x00 /* no bytes */
+ };
+ out.write(buf, 0, 3);
+ super.close();
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/CompressedInputStream.java b/libjava/classpath/gnu/java/net/protocol/ftp/CompressedInputStream.java
new file mode 100644
index 00000000000..f2e65b7d37e
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/ftp/CompressedInputStream.java
@@ -0,0 +1,215 @@
+/* CompressedInputStream.java --
+ Copyright (C) 2003, 2004 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.ftp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.ProtocolException;
+
+/**
+ * A DTP input stream that implements the FTP compressed transfer mode.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+class CompressedInputStream
+ extends DTPInputStream
+{
+
+ static final int EOF = 64;
+
+ static final int RAW = 0x00;
+ static final int COMPRESSED = 0x80;
+ static final int FILLER = 0xc0;
+
+ int descriptor;
+ int max = -1;
+ int count = -1;
+
+ int state = RAW; // RAW | STATE | FILLER
+ int rep; // the compressed byte
+ int n = 0; // the number of compressed or raw bytes
+
+ CompressedInputStream(DTP dtp, InputStream in)
+ {
+ super(dtp, in);
+ }
+
+ public int read()
+ throws IOException
+ {
+ if (transferComplete)
+ {
+ return -1;
+ }
+ if (count == -1)
+ {
+ readHeader();
+ }
+ if (max < 1)
+ {
+ close();
+ return -1;
+ }
+ if (n > 0 && (state == COMPRESSED || state == FILLER))
+ {
+ n--;
+ return rep;
+ }
+ int c = in.read();
+ if (c == -1)
+ {
+ close();
+ }
+ count++;
+ if (count >= max)
+ {
+ count = -1;
+ if (descriptor == EOF)
+ {
+ close();
+ }
+ }
+ if (c == -1)
+ {
+ return c;
+ }
+ while (n == 0) // read code header
+ {
+ state = (c & 0xc0);
+ n = (c & 0x3f);
+ c = in.read();
+ if (c == -1)
+ {
+ return -1;
+ }
+ }
+ switch (state)
+ {
+ case RAW:
+ break;
+ case COMPRESSED:
+ case FILLER:
+ rep = c;
+ break;
+ default:
+ throw new ProtocolException("Illegal state: " + state);
+ }
+ n--;
+ return c;
+ }
+
+ public int read(byte[] buf)
+ throws IOException
+ {
+ return read(buf, 0, buf.length);
+ }
+
+ public int read(byte[] buf, int off, int len)
+ throws IOException
+ {
+ if (transferComplete)
+ {
+ return -1;
+ }
+ if (count == -1)
+ {
+ readHeader();
+ }
+ if (max < 1)
+ {
+ close();
+ return -1;
+ }
+ // TODO improve performance
+ for (int i = off; i < len; i++)
+ {
+ int c = read();
+ if (c == -1)
+ {
+ close();
+ return i;
+ }
+ buf[i] = (byte) c;
+ }
+ return len;
+ /*
+ int l = in.read (buf, off, len);
+ if (l==-1)
+ {
+ close ();
+ }
+ count += l;
+ if (count>=max)
+ {
+ count = -1;
+ if (descriptor==EOF)
+ {
+ close ();
+ }
+ }
+ return l;
+ */
+ }
+
+ /**
+ * Reads the block header.
+ */
+ void readHeader()
+ throws IOException
+ {
+ descriptor = in.read();
+ int max_hi = in.read();
+ int max_lo = in.read();
+ max = (max_hi << 8) | max_lo;
+ count = 0;
+ }
+
+ /**
+ * Reads the code header.
+ */
+ void readCodeHeader()
+ throws IOException
+ {
+ int code = in.read();
+ state = (code & 0xc0);
+ n = (code & 0x3f);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/CompressedOutputStream.java b/libjava/classpath/gnu/java/net/protocol/ftp/CompressedOutputStream.java
new file mode 100644
index 00000000000..b960fb3afe8
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/ftp/CompressedOutputStream.java
@@ -0,0 +1,228 @@
+/* CompressedOutputStream.java --
+ Copyright (C) 2003, 2004 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.ftp;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * A DTP output stream that implements the FTP compressed transfer mode.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+class CompressedOutputStream
+ extends DTPOutputStream
+{
+
+ static final byte RECORD = -128; // 0x80
+ static final byte EOF = 64; // 0x40
+
+ CompressedOutputStream(DTP dtp, OutputStream out)
+ {
+ super(dtp, out);
+ }
+
+ /**
+ * Just one byte cannot be compressed.
+ * It takes 5 bytes to transmit - hardly very compressed!
+ */
+ public void write(int c)
+ throws IOException
+ {
+ if (transferComplete)
+ {
+ return;
+ }
+ byte[] buf = new byte[]
+ {
+ RECORD, /* record descriptor */
+ 0x00, 0x01, /* one byte */
+ 0x01, /* one uncompressed byte */
+ (byte) c /* the byte */
+ };
+ out.write(buf, 0, 5);
+ }
+
+ public void write(byte[] b)
+ throws IOException
+ {
+ write(b, 0, b.length);
+ }
+
+ /**
+ * The larger len is, the better.
+ */
+ public void write(byte[] b, int off, int len)
+ throws IOException
+ {
+ if (transferComplete)
+ {
+ return;
+ }
+ byte[] buf = compress(b, off, len);
+ len = buf.length;
+ buf[0] = RECORD; /* record descriptor */
+ buf[1] = (byte) ((len & 0x00ff) >> 8); /* high byte of bytecount */
+ buf[2] = (byte) (len & 0xff00); /* low byte of bytecount */
+ out.write(buf, 0, len);
+ }
+
+ /**
+ * Returns the compressed form of the given byte array.
+ * The first 3 bytes are left free for header information.
+ */
+ byte[] compress(byte[] b, int off, int len)
+ {
+ byte[] buf = new byte[len];
+ byte last = 0;
+ int pos = 0, raw_count = 0, rep_count = 1;
+ for (int i = off; i < len; i++)
+ {
+ byte c = b[i];
+ if (i > off && c == last) // compress
+ {
+ if (raw_count > 0) // flush raw bytes to buf
+ {
+ // need to add raw_count+1 bytes
+ if (pos + (raw_count + 1) > buf.length)
+ {
+ buf = realloc(buf, len);
+ }
+ pos = flush_raw(buf, pos, b, (i - raw_count) - 1,
+ raw_count);
+ raw_count = 0;
+ }
+ rep_count++; // keep looking for same byte
+ }
+ else
+ {
+ if (rep_count > 1) // flush compressed bytes to buf
+ {
+ // need to add 2 bytes
+ if (pos + 2 > buf.length)
+ {
+ buf = realloc(buf, len);
+ }
+ pos = flush_compressed(buf, pos, rep_count, last);
+ rep_count = 1;
+ }
+ raw_count++; // keep looking for raw bytes
+ }
+ if (rep_count == 127) // flush compressed bytes
+ {
+ // need to add 2 bytes
+ if (pos + 2 > buf.length)
+ {
+ buf = realloc(buf, len);
+ }
+ pos = flush_compressed(buf, pos, rep_count, last);
+ rep_count = 1;
+ }
+ if (raw_count == 127) // flush raw bytes
+ {
+ // need to add raw_count+1 bytes
+ if (pos + (raw_count + 1) > buf.length)
+ {
+ buf = realloc(buf, len);
+ }
+ pos = flush_raw(buf, pos, b, (i - raw_count), raw_count);
+ raw_count = 0;
+ }
+ last = c;
+ }
+ if (rep_count > 1) // flush compressed bytes
+ {
+ // need to add 2 bytes
+ if (pos + 2 > buf.length)
+ {
+ buf = realloc(buf, len);
+ }
+ pos = flush_compressed(buf, pos, rep_count, last);
+ rep_count = 1;
+ }
+ if (raw_count > 0) // flush raw bytes
+ {
+ // need to add raw_count+1 bytes
+ if (pos + (raw_count + 1) > buf.length)
+ {
+ buf = realloc(buf, len);
+ }
+ pos = flush_raw(buf, pos, b, (len - raw_count), raw_count);
+ raw_count = 0;
+ }
+ byte[] ret = new byte[pos + 3];
+ System.arraycopy(buf, 0, ret, 3, pos);
+ return ret;
+ }
+
+ int flush_compressed(byte[] buf, int pos, int count, byte c)
+ {
+ buf[pos++] = (byte) (0x80 | count);
+ buf[pos++] = c;
+ return pos;
+ }
+
+ int flush_raw(byte[] buf, int pos, byte[] src, int off, int len)
+ {
+ buf[pos++] = (byte) len;
+ System.arraycopy(src, off, buf, pos, len);
+ return pos + len;
+ }
+
+ byte[] realloc(byte[] buf, int len)
+ {
+ byte[] ret = new byte[buf.length + len];
+ System.arraycopy(buf, 0, ret, 0, buf.length);
+ return ret;
+ }
+
+ public void close()
+ throws IOException
+ {
+ byte[] buf = new byte[]
+ {
+ EOF, /* eof descriptor */
+ 0x00, 0x00 /* no bytes */
+ };
+ out.write(buf, 0, 3);
+ out.close();
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/DTP.java b/libjava/classpath/gnu/java/net/protocol/ftp/DTP.java
new file mode 100644
index 00000000000..25580af403a
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/ftp/DTP.java
@@ -0,0 +1,92 @@
+/* DTP.java --
+ Copyright (C) 2003, 2004 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.ftp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * An FTP data transfer process.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+interface DTP
+{
+
+ /**
+ * Returns an input stream from which a remote file can be read.
+ */
+ InputStream getInputStream()
+ throws IOException;
+
+ /**
+ * Returns an output stream to which a local file can be written for
+ * upload.
+ */
+ OutputStream getOutputStream()
+ throws IOException;
+
+ /**
+ * Sets the transfer mode to be used with this DTP.
+ */
+ void setTransferMode(int mode);
+
+ /**
+ * Marks this DTP completed.
+ * When the current transfer has finished, any resources will be released.
+ */
+ void complete();
+
+ /**
+ * Aborts any current transfer and releases all resources held by this
+ * DTP.
+ * @return true if a transfer was interrupted, false otherwise
+ */
+ boolean abort();
+
+ /**
+ * Used to notify the DTP that its current transfer is complete.
+ * This occurs either when end-of-stream is reached or a 226 response is
+ * received.
+ */
+ void transferComplete();
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/DTPInputStream.java b/libjava/classpath/gnu/java/net/protocol/ftp/DTPInputStream.java
new file mode 100644
index 00000000000..363a5590fbb
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/ftp/DTPInputStream.java
@@ -0,0 +1,88 @@
+/* DTPInputStream.java --
+ Copyright (C) 2003, 2004 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.ftp;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * An input stream that notifies a DTP on completion.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+abstract class DTPInputStream
+ extends FilterInputStream
+{
+
+ DTP dtp;
+ boolean transferComplete;
+
+ /**
+ * Constructor.
+ * @param dtp the controlling data transfer process
+ * @param in the underlying socket stream
+ */
+ DTPInputStream (DTP dtp, InputStream in)
+ {
+ super(in);
+ this.dtp = dtp;
+ transferComplete = false;
+ }
+
+ /**
+ * Marks this input stream complete.
+ * This is called by the DTP.
+ */
+ void setTransferComplete(boolean flag)
+ {
+ transferComplete = flag;
+ }
+
+ /**
+ * Notifies the controlling DTP that this stream has completed transfer.
+ */
+ public void close()
+ throws IOException
+ {
+ dtp.transferComplete();
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/DTPOutputStream.java b/libjava/classpath/gnu/java/net/protocol/ftp/DTPOutputStream.java
new file mode 100644
index 00000000000..83f0be1e30d
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/ftp/DTPOutputStream.java
@@ -0,0 +1,85 @@
+/* DTPOutputStream.java --
+ Copyright (C) 2003, 2004 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.ftp;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * An output stream that notifies a DTP on end of stream.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+abstract class DTPOutputStream extends FilterOutputStream
+{
+
+ DTP dtp;
+ boolean transferComplete;
+
+ /**
+ * Constructor.
+ * @param dtp the controlling data transfer process
+ * @param out the socket output stream
+ */
+ DTPOutputStream (DTP dtp, OutputStream out)
+ {
+ super (out);
+ this.dtp = dtp;
+ transferComplete = false;
+ }
+
+ /**
+ * Tells this stream whether transfer has completed or not.
+ * @param flag true if the process has completed, false otherwise
+ */
+ void setTransferComplete (boolean flag)
+ {
+ transferComplete = flag;
+ }
+
+ /**
+ * Notifies the controlling DTP that this stream has been terminated.
+ */
+ public void close () throws IOException
+ {
+ dtp.transferComplete ();
+ }
+
+}
diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/FTPConnection.java b/libjava/classpath/gnu/java/net/protocol/ftp/FTPConnection.java
new file mode 100644
index 00000000000..d0f48727cfa
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/ftp/FTPConnection.java
@@ -0,0 +1,1348 @@
+/* FTPConnection.java --
+ Copyright (C) 2003, 2004 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.ftp;
+
+import gnu.java.net.CRLFInputStream;
+import gnu.java.net.CRLFOutputStream;
+import gnu.java.net.EmptyX509TrustManager;
+import gnu.java.net.LineInputStream;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.BindException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ProtocolException;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.security.GeneralSecurityException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+
+/**
+ * An FTP client connection, or PI.
+ * This implements RFC 959, with the following exceptions:
+ * <ul>
+ * <li>STAT, HELP, SITE, SMNT, and ACCT commands are not supported.</li>
+ * <li>the TYPE command does not allow alternatives to the default bytesize
+ * (Non-print), and local bytesize is not supported.</li>
+ * </ul>
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class FTPConnection
+{
+
+ /**
+ * The default FTP transmission control port.
+ */
+ public static final int FTP_PORT = 21;
+
+ /**
+ * The FTP data port.
+ */
+ public static final int FTP_DATA_PORT = 20;
+
+ // -- FTP vocabulary --
+ protected static final String USER = "USER";
+ protected static final String PASS = "PASS";
+ protected static final String ACCT = "ACCT";
+ protected static final String CWD = "CWD";
+ protected static final String CDUP = "CDUP";
+ protected static final String SMNT = "SMNT";
+ protected static final String REIN = "REIN";
+ protected static final String QUIT = "QUIT";
+
+ protected static final String PORT = "PORT";
+ protected static final String PASV = "PASV";
+ protected static final String TYPE = "TYPE";
+ protected static final String STRU = "STRU";
+ protected static final String MODE = "MODE";
+
+ protected static final String RETR = "RETR";
+ protected static final String STOR = "STOR";
+ protected static final String STOU = "STOU";
+ protected static final String APPE = "APPE";
+ protected static final String ALLO = "ALLO";
+ protected static final String REST = "REST";
+ protected static final String RNFR = "RNFR";
+ protected static final String RNTO = "RNTO";
+ protected static final String ABOR = "ABOR";
+ protected static final String DELE = "DELE";
+ protected static final String RMD = "RMD";
+ protected static final String MKD = "MKD";
+ protected static final String PWD = "PWD";
+ protected static final String LIST = "LIST";
+ protected static final String NLST = "NLST";
+ protected static final String SITE = "SITE";
+ protected static final String SYST = "SYST";
+ protected static final String STAT = "STAT";
+ protected static final String HELP = "HELP";
+ protected static final String NOOP = "NOOP";
+
+ protected static final String AUTH = "AUTH";
+ protected static final String PBSZ = "PBSZ";
+ protected static final String PROT = "PROT";
+ protected static final String CCC = "CCC";
+ protected static final String TLS = "TLS";
+
+ public static final int TYPE_ASCII = 1;
+ public static final int TYPE_EBCDIC = 2;
+ public static final int TYPE_BINARY = 3;
+
+ public static final int STRUCTURE_FILE = 1;
+ public static final int STRUCTURE_RECORD = 2;
+ public static final int STRUCTURE_PAGE = 3;
+
+ public static final int MODE_STREAM = 1;
+ public static final int MODE_BLOCK = 2;
+ public static final int MODE_COMPRESSED = 3;
+
+ // -- Telnet constants --
+ private static final String US_ASCII = "US-ASCII";
+
+ /**
+ * The socket used to communicate with the server.
+ */
+ protected Socket socket;
+
+ /**
+ * The socket input stream.
+ */
+ protected LineInputStream in;
+
+ /**
+ * The socket output stream.
+ */
+ protected CRLFOutputStream out;
+
+ /**
+ * The timeout when attempting to connect a socket.
+ */
+ protected int connectionTimeout;
+
+ /**
+ * The read timeout on sockets.
+ */
+ protected int timeout;
+
+ /**
+ * If true, print debugging information.
+ */
+ protected boolean debug;
+
+ /**
+ * The current data transfer process in use by this connection.
+ */
+ protected DTP dtp;
+
+ /**
+ * The current representation type.
+ */
+ protected int representationType = TYPE_ASCII;
+
+ /**
+ * The current file structure type.
+ */
+ protected int fileStructure = STRUCTURE_FILE;
+
+ /**
+ * The current transfer mode.
+ */
+ protected int transferMode = MODE_STREAM;
+
+ /**
+ * If true, use passive mode.
+ */
+ protected boolean passive = false;
+
+ /**
+ * Creates a new connection to the server using the default port.
+ * @param hostname the hostname of the server to connect to
+ */
+ public FTPConnection(String hostname)
+ throws UnknownHostException, IOException
+ {
+ this(hostname, -1, 0, 0, false);
+ }
+
+ /**
+ * Creates a new connection to the server.
+ * @param hostname the hostname of the server to connect to
+ * @param port the port to connect to(if &lt;=0, use default port)
+ */
+ public FTPConnection(String hostname, int port)
+ throws UnknownHostException, IOException
+ {
+ this(hostname, port, 0, 0, false);
+ }
+
+ /**
+ * Creates a new connection to the server.
+ * @param hostname the hostname of the server to connect to
+ * @param port the port to connect to(if &lt;=0, use default port)
+ * @param connectionTimeout the connection timeout, in milliseconds
+ * @param timeout the I/O timeout, in milliseconds
+ * @param debug print debugging information
+ */
+ public FTPConnection(String hostname, int port,
+ int connectionTimeout, int timeout, boolean debug)
+ throws UnknownHostException, IOException
+ {
+ this.connectionTimeout = connectionTimeout;
+ this.timeout = timeout;
+ this.debug = debug;
+ if (port <= 0)
+ {
+ port = FTP_PORT;
+ }
+
+ // Set up socket
+ socket = new Socket();
+ InetSocketAddress address = new InetSocketAddress(hostname, port);
+ if (connectionTimeout > 0)
+ {
+ socket.connect(address, connectionTimeout);
+ }
+ else
+ {
+ socket.connect(address);
+ }
+ if (timeout > 0)
+ {
+ socket.setSoTimeout(timeout);
+ }
+
+ InputStream in = socket.getInputStream();
+ in = new BufferedInputStream(in);
+ in = new CRLFInputStream(in);
+ this.in = new LineInputStream(in);
+ OutputStream out = socket.getOutputStream();
+ out = new BufferedOutputStream(out);
+ this.out = new CRLFOutputStream(out);
+
+ // Read greeting
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 220: // hello
+ break;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Authenticate using the specified username and password.
+ * If the username suffices for the server, the password will not be used
+ * and may be null.
+ * @param username the username
+ * @param password the optional password
+ * @return true on success, false otherwise
+ */
+ public boolean authenticate(String username, String password)
+ throws IOException
+ {
+ String cmd = USER + ' ' + username;
+ send(cmd);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 230: // User logged in
+ return true;
+ case 331: // User name okay, need password
+ break;
+ case 332: // Need account for login
+ case 530: // No such user
+ return false;
+ default:
+ throw new FTPException(response);
+ }
+ cmd = PASS + ' ' + password;
+ send(cmd);
+ response = getResponse();
+ switch (response.getCode())
+ {
+ case 230: // User logged in
+ case 202: // Superfluous
+ return true;
+ case 332: // Need account for login
+ case 530: // Bad password
+ return false;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Negotiates TLS over the current connection.
+ * See IETF draft-murray-auth-ftp-ssl-15.txt for details.
+ * @param confidential whether to provide confidentiality for the
+ * connection
+ */
+ public boolean starttls(boolean confidential)
+ throws IOException
+ {
+ return starttls(confidential, new EmptyX509TrustManager());
+ }
+
+ /**
+ * Negotiates TLS over the current connection.
+ * See IETF draft-murray-auth-ftp-ssl-15.txt for details.
+ * @param confidential whether to provide confidentiality for the
+ * connection
+ * @param tm the trust manager used to validate the server certificate.
+ */
+ public boolean starttls(boolean confidential, TrustManager tm)
+ throws IOException
+ {
+ try
+ {
+ // Use SSLSocketFactory to negotiate a TLS session and wrap the
+ // current socket.
+ SSLContext context = SSLContext.getInstance("TLS");
+ // We don't require strong validation of the server certificate
+ TrustManager[] trust = new TrustManager[] { tm };
+ context.init(null, trust, null);
+ SSLSocketFactory factory = context.getSocketFactory();
+
+ send(AUTH + ' ' + TLS);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 500:
+ case 502:
+ case 504:
+ case 534:
+ case 431:
+ return false;
+ case 234:
+ break;
+ default:
+ throw new FTPException(response);
+ }
+
+ String hostname = socket.getInetAddress().getHostName();
+ int port = socket.getPort();
+ SSLSocket ss =
+ (SSLSocket) factory.createSocket(socket, hostname, port, true);
+ String[] protocols = { "TLSv1", "SSLv3" };
+ ss.setEnabledProtocols(protocols);
+ ss.setUseClientMode(true);
+ ss.startHandshake();
+
+ // PBSZ:PROT sequence
+ send(PBSZ + ' ' + Integer.MAX_VALUE);
+ response = getResponse();
+ switch (response.getCode())
+ {
+ case 501: // syntax error
+ case 503: // not authenticated
+ return false;
+ case 200:
+ break;
+ default:
+ throw new FTPException(response);
+ }
+ send(PROT + ' ' +(confidential ? 'P' : 'C'));
+ response = getResponse();
+ switch (response.getCode())
+ {
+ case 503: // not authenticated
+ case 504: // invalid level
+ case 536: // level not supported
+ return false;
+ case 200:
+ break;
+ default:
+ throw new FTPException(response);
+ }
+
+ if (confidential)
+ {
+ // Set up streams
+ InputStream in = ss.getInputStream();
+ in = new BufferedInputStream(in);
+ in = new CRLFInputStream(in);
+ this.in = new LineInputStream(in);
+ OutputStream out = ss.getOutputStream();
+ out = new BufferedOutputStream(out);
+ this.out = new CRLFOutputStream(out);
+ }
+ return true;
+ }
+ catch (GeneralSecurityException e)
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Changes directory to the specified path.
+ * @param path an absolute or relative pathname
+ * @return true on success, false if the specified path does not exist
+ */
+ public boolean changeWorkingDirectory(String path)
+ throws IOException
+ {
+ String cmd = CWD + ' ' + path;
+ send(cmd);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 250:
+ return true;
+ case 550:
+ return false;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Changes directory to the parent of the current working directory.
+ * @return true on success, false otherwise
+ */
+ public boolean changeToParentDirectory()
+ throws IOException
+ {
+ send(CDUP);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 250:
+ return true;
+ case 550:
+ return false;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Terminates an authenticated login.
+ * If file transfer is in progress, it remains active for result response
+ * only.
+ */
+ public void reinitialize()
+ throws IOException
+ {
+ send(REIN);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 220:
+ if (dtp != null)
+ {
+ dtp.complete();
+ dtp = null;
+ }
+ break;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Terminates the control connection.
+ * The file transfer connection remains open for result response only.
+ * This connection is invalid and no further commands may be issued.
+ */
+ public void logout()
+ throws IOException
+ {
+ send(QUIT);
+ try
+ {
+ getResponse(); // not required
+ }
+ catch (IOException e)
+ {
+ }
+ if (dtp != null)
+ {
+ dtp.complete();
+ dtp = null;
+ }
+ try
+ {
+ socket.close();
+ }
+ catch (IOException e)
+ {
+ }
+ }
+
+ /**
+ * Initialise the data transfer process.
+ */
+ protected void initialiseDTP()
+ throws IOException
+ {
+ if (dtp != null)
+ {
+ dtp.complete();
+ dtp = null;
+ }
+
+ InetAddress localhost = socket.getLocalAddress();
+ if (passive)
+ {
+ send(PASV);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 227:
+ String message = response.getMessage();
+ try
+ {
+ int start = message.indexOf(',');
+ char c = message.charAt(start - 1);
+ while (c >= 0x30 && c <= 0x39)
+ {
+ c = message.charAt((--start) - 1);
+ }
+ int mid1 = start;
+ for (int i = 0; i < 4; i++)
+ {
+ mid1 = message.indexOf(',', mid1 + 1);
+ }
+ int mid2 = message.indexOf(',', mid1 + 1);
+ if (mid1 == -1 || mid2 < mid1)
+ {
+ throw new ProtocolException("Malformed 227: " +
+ message);
+ }
+ int end = mid2;
+ c = message.charAt(end + 1);
+ while (c >= 0x30 && c <= 0x39)
+ {
+ c = message.charAt((++end) + 1);
+ }
+
+ String address =
+ message.substring(start, mid1).replace(',', '.');
+ int port_hi =
+ Integer.parseInt(message.substring(mid1 + 1, mid2));
+ int port_lo =
+ Integer.parseInt(message.substring(mid2 + 1, end + 1));
+ int port = (port_hi << 8) | port_lo;
+
+ /*System.out.println("Entering passive mode: " + address +
+ ":" + port);*/
+ dtp = new PassiveModeDTP(address, port, localhost,
+ connectionTimeout, timeout);
+ break;
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new ProtocolException(e.getMessage() + ": " +
+ message);
+ }
+ catch (NumberFormatException e)
+ {
+ throw new ProtocolException(e.getMessage() + ": " +
+ message);
+ }
+ default:
+ throw new FTPException(response);
+ }
+ }
+ else
+ {
+ // Get the local port
+ int port = socket.getLocalPort() + 1;
+ int tries = 0;
+ // Bind the active mode DTP
+ while (dtp == null)
+ {
+ try
+ {
+ dtp = new ActiveModeDTP(localhost, port,
+ connectionTimeout, timeout);
+ /*System.out.println("Listening on: " + port);*/
+ }
+ catch (BindException e)
+ {
+ port++;
+ tries++;
+ if (tries > 9)
+ {
+ throw e;
+ }
+ }
+ }
+
+ // Send PORT command
+ StringBuffer buf = new StringBuffer(PORT);
+ buf.append(' ');
+ // Construct the address/port string form
+ byte[] address = localhost.getAddress();
+ for (int i = 0; i < address.length; i++)
+ {
+ int a =(int) address[i];
+ if (a < 0)
+ {
+ a += 0x100;
+ }
+ buf.append(a);
+ buf.append(',');
+ }
+ int port_hi =(port & 0xff00) >> 8;
+ int port_lo =(port & 0x00ff);
+ buf.append(port_hi);
+ buf.append(',');
+ buf.append(port_lo);
+ send(buf.toString());
+ // Get response
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 200: // OK
+ break;
+ default:
+ dtp.abort();
+ dtp = null;
+ throw new FTPException(response);
+ }
+ }
+ dtp.setTransferMode(transferMode);
+ }
+
+ /**
+ * Set passive mode.
+ * @param flag true if we should use passive mode, false otherwise
+ */
+ public void setPassive(boolean flag)
+ throws IOException
+ {
+ if (passive != flag)
+ {
+ passive = flag;
+ initialiseDTP();
+ }
+ }
+
+ /**
+ * Returns the current representation type of the transfer data.
+ * @return TYPE_ASCII, TYPE_EBCDIC, or TYPE_BINARY
+ */
+ public int getRepresentationType()
+ {
+ return representationType;
+ }
+
+ /**
+ * Sets the desired representation type of the transfer data.
+ * @param type TYPE_ASCII, TYPE_EBCDIC, or TYPE_BINARY
+ */
+ public void setRepresentationType(int type)
+ throws IOException
+ {
+ StringBuffer buf = new StringBuffer(TYPE);
+ buf.append(' ');
+ switch (type)
+ {
+ case TYPE_ASCII:
+ buf.append('A');
+ break;
+ case TYPE_EBCDIC:
+ buf.append('E');
+ break;
+ case TYPE_BINARY:
+ buf.append('I');
+ break;
+ default:
+ throw new IllegalArgumentException(Integer.toString(type));
+ }
+ //buf.append(' ');
+ //buf.append('N');
+ send(buf.toString());
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 200:
+ representationType = type;
+ break;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Returns the current file structure type.
+ * @return STRUCTURE_FILE, STRUCTURE_RECORD, or STRUCTURE_PAGE
+ */
+ public int getFileStructure()
+ {
+ return fileStructure;
+ }
+
+ /**
+ * Sets the desired file structure type.
+ * @param structure STRUCTURE_FILE, STRUCTURE_RECORD, or STRUCTURE_PAGE
+ */
+ public void setFileStructure(int structure)
+ throws IOException
+ {
+ StringBuffer buf = new StringBuffer(STRU);
+ buf.append(' ');
+ switch (structure)
+ {
+ case STRUCTURE_FILE:
+ buf.append('F');
+ break;
+ case STRUCTURE_RECORD:
+ buf.append('R');
+ break;
+ case STRUCTURE_PAGE:
+ buf.append('P');
+ break;
+ default:
+ throw new IllegalArgumentException(Integer.toString(structure));
+ }
+ send(buf.toString());
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 200:
+ fileStructure = structure;
+ break;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Returns the current transfer mode.
+ * @return MODE_STREAM, MODE_BLOCK, or MODE_COMPRESSED
+ */
+ public int getTransferMode()
+ {
+ return transferMode;
+ }
+
+ /**
+ * Sets the desired transfer mode.
+ * @param mode MODE_STREAM, MODE_BLOCK, or MODE_COMPRESSED
+ */
+ public void setTransferMode(int mode)
+ throws IOException
+ {
+ StringBuffer buf = new StringBuffer(MODE);
+ buf.append(' ');
+ switch (mode)
+ {
+ case MODE_STREAM:
+ buf.append('S');
+ break;
+ case MODE_BLOCK:
+ buf.append('B');
+ break;
+ case MODE_COMPRESSED:
+ buf.append('C');
+ break;
+ default:
+ throw new IllegalArgumentException(Integer.toString(mode));
+ }
+ send(buf.toString());
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 200:
+ transferMode = mode;
+ if (dtp != null)
+ {
+ dtp.setTransferMode(mode);
+ }
+ break;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Retrieves the specified file.
+ * @param filename the filename of the file to retrieve
+ * @return an InputStream containing the file content
+ */
+ public InputStream retrieve(String filename)
+ throws IOException
+ {
+ if (dtp == null || transferMode == MODE_STREAM)
+ {
+ initialiseDTP();
+ }
+ /*
+ int size = -1;
+ String cmd = SIZE + ' ' + filename;
+ send(cmd);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 213:
+ size = Integer.parseInt(response.getMessage());
+ break;
+ case 550: // File not found
+ default:
+ throw new FTPException(response);
+ }
+ */
+ String cmd = RETR + ' ' + filename;
+ send(cmd);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 125: // Data connection already open; transfer starting
+ case 150: // File status okay; about to open data connection
+ return dtp.getInputStream();
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Returns a stream for uploading a file.
+ * If a file with the same filename already exists on the server, it will
+ * be overwritten.
+ * @param filename the name of the file to save the content as
+ * @return an OutputStream to write the file data to
+ */
+ public OutputStream store(String filename)
+ throws IOException
+ {
+ if (dtp == null || transferMode == MODE_STREAM)
+ {
+ initialiseDTP();
+ }
+ String cmd = STOR + ' ' + filename;
+ send(cmd);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 125: // Data connection already open; transfer starting
+ case 150: // File status okay; about to open data connection
+ return dtp.getOutputStream();
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Returns a stream for uploading a file.
+ * If a file with the same filename already exists on the server, the
+ * content specified will be appended to the existing file.
+ * @param filename the name of the file to save the content as
+ * @return an OutputStream to write the file data to
+ */
+ public OutputStream append(String filename)
+ throws IOException
+ {
+ if (dtp == null || transferMode == MODE_STREAM)
+ {
+ initialiseDTP();
+ }
+ String cmd = APPE + ' ' + filename;
+ send(cmd);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 125: // Data connection already open; transfer starting
+ case 150: // File status okay; about to open data connection
+ return dtp.getOutputStream();
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * This command may be required by some servers to reserve sufficient
+ * storage to accommodate the new file to be transferred.
+ * It should be immediately followed by a <code>store</code> or
+ * <code>append</code>.
+ * @param size the number of bytes of storage to allocate
+ */
+ public void allocate(long size)
+ throws IOException
+ {
+ String cmd = ALLO + ' ' + size;
+ send(cmd);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 200: // OK
+ case 202: // Superfluous
+ break;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Renames a file.
+ * @param oldName the current name of the file
+ * @param newName the new name
+ * @return true if successful, false otherwise
+ */
+ public boolean rename(String oldName, String newName)
+ throws IOException
+ {
+ String cmd = RNFR + ' ' + oldName;
+ send(cmd);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 450: // File unavailable
+ case 550: // File not found
+ return false;
+ case 350: // Pending
+ break;
+ default:
+ throw new FTPException(response);
+ }
+ cmd = RNTO + ' ' + newName;
+ send(cmd);
+ response = getResponse();
+ switch (response.getCode())
+ {
+ case 250: // OK
+ return true;
+ case 450:
+ case 550:
+ return false;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Aborts the transfer in progress.
+ * @return true if a transfer was in progress, false otherwise
+ */
+ public boolean abort()
+ throws IOException
+ {
+ send(ABOR);
+ FTPResponse response = getResponse();
+ // Abort client DTP
+ if (dtp != null)
+ {
+ dtp.abort();
+ }
+ switch (response.getCode())
+ {
+ case 226: // successful abort
+ return false;
+ case 426: // interrupted
+ response = getResponse();
+ if (response.getCode() == 226)
+ {
+ return true;
+ }
+ // Otherwise fall through to throw exception
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Causes the file specified to be deleted at the server site.
+ * @param filename the file to delete
+ */
+ public boolean delete(String filename)
+ throws IOException
+ {
+ String cmd = DELE + ' ' + filename;
+ send(cmd);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 250: // OK
+ return true;
+ case 450: // File unavailable
+ case 550: // File not found
+ return false;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Causes the directory specified to be deleted.
+ * This may be an absolute or relative pathname.
+ * @param pathname the directory to delete
+ */
+ public boolean removeDirectory(String pathname)
+ throws IOException
+ {
+ String cmd = RMD + ' ' + pathname;
+ send(cmd);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 250: // OK
+ return true;
+ case 550: // File not found
+ return false;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Causes the directory specified to be created at the server site.
+ * This may be an absolute or relative pathname.
+ * @param pathname the directory to create
+ */
+ public boolean makeDirectory(String pathname)
+ throws IOException
+ {
+ String cmd = MKD + ' ' + pathname;
+ send(cmd);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 257: // Directory created
+ return true;
+ case 550: // File not found
+ return false;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Returns the current working directory.
+ */
+ public String getWorkingDirectory()
+ throws IOException
+ {
+ send(PWD);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 257:
+ String message = response.getMessage();
+ if (message.charAt(0) == '"')
+ {
+ int end = message.indexOf('"', 1);
+ if (end == -1)
+ {
+ throw new ProtocolException(message);
+ }
+ return message.substring(1, end);
+ }
+ else
+ {
+ int end = message.indexOf(' ');
+ if (end == -1)
+ {
+ return message;
+ }
+ else
+ {
+ return message.substring(0, end);
+ }
+ }
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Returns a listing of information about the specified pathname.
+ * If the pathname specifies a directory or other group of files, the
+ * server should transfer a list of files in the specified directory.
+ * If the pathname specifies a file then the server should send current
+ * information on the file. A null argument implies the user's
+ * current working or default directory.
+ * @param pathname the context pathname, or null
+ */
+ public InputStream list(String pathname)
+ throws IOException
+ {
+ if (dtp == null || transferMode == MODE_STREAM)
+ {
+ initialiseDTP();
+ }
+ if (pathname == null)
+ {
+ send(LIST);
+ }
+ else
+ {
+ String cmd = LIST + ' ' + pathname;
+ send(cmd);
+ }
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 125: // Data connection already open; transfer starting
+ case 150: // File status okay; about to open data connection
+ return dtp.getInputStream();
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Returns a directory listing. The pathname should specify a
+ * directory or other system-specific file group descriptor; a null
+ * argument implies the user's current working or default directory.
+ * @param pathname the directory pathname, or null
+ * @return a list of filenames(strings)
+ */
+ public List nameList(String pathname)
+ throws IOException
+ {
+ if (dtp == null || transferMode == MODE_STREAM)
+ {
+ initialiseDTP();
+ }
+ if (pathname == null)
+ {
+ send(NLST);
+ }
+ else
+ {
+ String cmd = NLST + ' ' + pathname;
+ send(cmd);
+ }
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 125: // Data connection already open; transfer starting
+ case 150: // File status okay; about to open data connection
+ InputStream in = dtp.getInputStream();
+ in = new BufferedInputStream(in);
+ in = new CRLFInputStream(in); // TODO ensure that TYPE is correct
+ LineInputStream li = new LineInputStream(in);
+ List ret = new ArrayList();
+ for (String line = li.readLine();
+ line != null;
+ line = li.readLine())
+ {
+ ret.add(line);
+ }
+ li.close();
+ return ret;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Returns the type of operating system at the server.
+ */
+ public String system()
+ throws IOException
+ {
+ send(SYST);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 215:
+ String message = response.getMessage();
+ int end = message.indexOf(' ');
+ if (end == -1)
+ {
+ return message;
+ }
+ else
+ {
+ return message.substring(0, end);
+ }
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ /**
+ * Does nothing.
+ * This method can be used to ensure that the connection does not time
+ * out.
+ */
+ public void noop()
+ throws IOException
+ {
+ send(NOOP);
+ FTPResponse response = getResponse();
+ switch (response.getCode())
+ {
+ case 200:
+ break;
+ default:
+ throw new FTPException(response);
+ }
+ }
+
+ // -- I/O --
+
+ /**
+ * Sends the specified command line to the server.
+ * The CRLF sequence is automatically appended.
+ * @param cmd the command line to send
+ */
+ protected void send(String cmd)
+ throws IOException
+ {
+ byte[] data = cmd.getBytes(US_ASCII);
+ out.write(data);
+ out.writeln();
+ out.flush();
+ }
+
+ /**
+ * Reads the next response from the server.
+ * If the server sends the "transfer complete" code, this is handled here,
+ * and the next response is passed to the caller.
+ */
+ protected FTPResponse getResponse()
+ throws IOException
+ {
+ FTPResponse response = readResponse();
+ if (response.getCode() == 226)
+ {
+ if (dtp != null)
+ {
+ dtp.transferComplete();
+ }
+ response = readResponse();
+ }
+ return response;
+ }
+
+ /**
+ * Reads and parses the next response from the server.
+ */
+ protected FTPResponse readResponse()
+ throws IOException
+ {
+ String line = in.readLine();
+ if (line == null)
+ {
+ throw new ProtocolException( "EOF");
+ }
+ if (line.length() < 4)
+ {
+ throw new ProtocolException(line);
+ }
+ int code = parseCode(line);
+ if (code == -1)
+ {
+ throw new ProtocolException(line);
+ }
+ char c = line.charAt(3);
+ if (c == ' ')
+ {
+ return new FTPResponse(code, line.substring(4));
+ }
+ else if (c == '-')
+ {
+ StringBuffer buf = new StringBuffer(line.substring(4));
+ buf.append('\n');
+ while(true)
+ {
+ line = in.readLine();
+ if (line == null)
+ {
+ throw new ProtocolException("EOF");
+ }
+ if (line.length() >= 4 &&
+ line.charAt(3) == ' ' &&
+ parseCode(line) == code)
+ {
+ return new FTPResponse(code, line.substring(4),
+ buf.toString());
+ }
+ else
+ {
+ buf.append(line);
+ buf.append('\n');
+ }
+ }
+ }
+ else
+ {
+ throw new ProtocolException(line);
+ }
+ }
+
+ /*
+ * Parses the 3-digit numeric code at the beginning of the given line.
+ * Returns -1 on failure.
+ */
+ static final int parseCode(String line)
+ {
+ char[] c = { line.charAt(0), line.charAt(1), line.charAt(2) };
+ int ret = 0;
+ for (int i = 0; i < 3; i++)
+ {
+ int digit =((int) c[i]) - 0x30;
+ if (digit < 0 || digit > 9)
+ {
+ return -1;
+ }
+ // Computing integer powers is way too expensive in Java!
+ switch (i)
+ {
+ case 0:
+ ret +=(100 * digit);
+ break;
+ case 1:
+ ret +=(10 * digit);
+ break;
+ case 2:
+ ret += digit;
+ break;
+ }
+ }
+ return ret;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/FTPException.java b/libjava/classpath/gnu/java/net/protocol/ftp/FTPException.java
new file mode 100644
index 00000000000..14ad3813f85
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/ftp/FTPException.java
@@ -0,0 +1,76 @@
+/* FTPException.java --
+ Copyright (C) 2003. 2004 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.ftp;
+
+import java.io.IOException;
+
+/**
+ * An FTP control exception.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class FTPException
+ extends IOException
+{
+
+ /**
+ * The response that provoked this exception.
+ */
+ protected final FTPResponse response;
+
+ /**
+ * Constructs a new FTP exception.
+ * @param response the response that provoked this exception
+ */
+ public FTPException(FTPResponse response)
+ {
+ super(response.getMessage());
+ this.response = response;
+ }
+
+ /**
+ * Returns the response that provoked this exception.
+ */
+ public FTPResponse getResponse()
+ {
+ return response;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/FTPResponse.java b/libjava/classpath/gnu/java/net/protocol/ftp/FTPResponse.java
new file mode 100644
index 00000000000..ec72c732c1c
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/ftp/FTPResponse.java
@@ -0,0 +1,112 @@
+/* FTPResponse.java --
+ Copyright (C) 2003, 2004 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.ftp;
+
+/**
+ * An FTP control response.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public final class FTPResponse
+{
+
+ /**
+ * The 3-digit status code.
+ */
+ protected final int code;
+
+ /**
+ * The human-readable message.
+ */
+ protected final String message;
+
+ /**
+ * Multiline data, if present.
+ */
+ protected final String data;
+
+ /**
+ * Constructs a new FTP response.
+ * @param code the status code
+ * @param message the message
+ */
+ public FTPResponse(int code, String message)
+ {
+ this(code, message, null);
+ }
+
+ /**
+ * Constructs a new multiline FTP response.
+ * @param code the status code
+ * @param message the message
+ * @param data multiline data
+ */
+ public FTPResponse(int code, String message, String data)
+ {
+ this.code = code;
+ this.message = message;
+ this.data = data;
+ }
+
+ /**
+ * Returns the 3-digit status code.
+ */
+ public int getCode()
+ {
+ return code;
+ }
+
+ /**
+ * Returns the human-readable message.
+ */
+ public String getMessage()
+ {
+ return message;
+ }
+
+ /**
+ * Returns the multiline data, or null if there was no such data.
+ */
+ public String getData()
+ {
+ return data;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/FTPURLConnection.java b/libjava/classpath/gnu/java/net/protocol/ftp/FTPURLConnection.java
new file mode 100644
index 00000000000..62c40f19e04
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/ftp/FTPURLConnection.java
@@ -0,0 +1,398 @@
+/* FTPURLConnection.java --
+ Copyright (C) 2003, 2004 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.ftp;
+
+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;
+import java.io.InputStream;
+import java.io.OutputStream;
+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;
+
+/**
+ * An FTP URL connection.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class FTPURLConnection
+ extends URLConnection
+{
+
+ /**
+ * The connection managing the protocol exchange.
+ */
+ protected FTPConnection connection;
+
+ protected boolean passive;
+ protected int representationType;
+ protected int fileStructure;
+ protected int transferMode;
+
+ /**
+ * Constructs an FTP connection to the specified URL.
+ * @param url the URL
+ */
+ public FTPURLConnection(URL url)
+ {
+ super(url);
+ passive = true;
+ representationType = FTPConnection.TYPE_BINARY;
+ fileStructure = -1;
+ transferMode = -1;
+ }
+
+ /**
+ * Establishes the connection.
+ */
+ public void connect()
+ throws IOException
+ {
+ if (connected)
+ {
+ return;
+ }
+ String host = url.getHost();
+ int port = url.getPort();
+ String username = url.getUserInfo();
+ String password = null;
+ if (username != null)
+ {
+ int ci = username.indexOf(':');
+ if (ci != -1)
+ {
+ password = username.substring(ci + 1);
+ username = username.substring(0, ci);
+ }
+ }
+ else
+ {
+ username = "anonymous";
+ PrivilegedAction a = new GetPropertyAction("user.name");
+ String systemUsername =(String) AccessController.doPrivileged(a);
+ a = new GetLocalHostAction();
+ InetAddress localhost =(InetAddress) AccessController.doPrivileged(a);
+ password = systemUsername + "@" +
+ ((localhost == null) ? "localhost" : localhost.getHostName());
+ }
+ connection = new FTPConnection(host, port);
+ if (!connection.authenticate(username, password))
+ {
+ throw new SecurityException("Authentication failed");
+ }
+ connection.setPassive(passive);
+ if (representationType != -1)
+ {
+ connection.setRepresentationType(representationType);
+ }
+ if (fileStructure != -1)
+ {
+ connection.setFileStructure(fileStructure);
+ }
+ if (transferMode != -1)
+ {
+ connection.setTransferMode(transferMode);
+ }
+ }
+
+ /**
+ * This connection supports doInput.
+ */
+ public void setDoInput(boolean doinput)
+ {
+ doInput = doinput;
+ }
+
+ /**
+ * This connection supports doOutput.
+ */
+ public void setDoOutput(boolean dooutput)
+ {
+ doOutput = dooutput;
+ }
+
+ /**
+ * Returns an input stream that reads from this open connection.
+ */
+ public InputStream getInputStream()
+ throws IOException
+ {
+ if (!connected)
+ {
+ connect();
+ }
+ String path = url.getPath();
+ String filename = null;
+ int lsi = path.lastIndexOf('/');
+ if (lsi != -1)
+ {
+ 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));
+ }
+ else
+ {
+ return this.new ClosingInputStream(connection.list(null));
+ }
+ }
+
+ /**
+ * Returns an output stream that writes to this connection.
+ */
+ public OutputStream getOutputStream()
+ throws IOException
+ {
+ if (!connected)
+ {
+ 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);
+ }
+ }
+
+ public String getRequestProperty(String key)
+ {
+ if ("passive".equals(key))
+ {
+ return Boolean.toString(passive);
+ }
+ else if ("representationType".equals(key))
+ {
+ switch (representationType)
+ {
+ case FTPConnection.TYPE_ASCII:
+ return "ASCII";
+ case FTPConnection.TYPE_EBCDIC:
+ return "EBCDIC";
+ case FTPConnection.TYPE_BINARY:
+ return "BINARY";
+ }
+ }
+ else if ("fileStructure".equals(key))
+ {
+ switch (fileStructure)
+ {
+ case FTPConnection.STRUCTURE_FILE:
+ return "FILE";
+ case FTPConnection.STRUCTURE_RECORD:
+ return "RECORD";
+ case FTPConnection.STRUCTURE_PAGE:
+ return "PAGE";
+ }
+ }
+ else if ("transferMode".equals(key))
+ {
+ switch (transferMode)
+ {
+ case FTPConnection.MODE_STREAM:
+ return "STREAM";
+ case FTPConnection.MODE_BLOCK:
+ return "BLOCK";
+ case FTPConnection.MODE_COMPRESSED:
+ return "COMPRESSED";
+ }
+ }
+ return null;
+ }
+
+ public Map getRequestProperties()
+ {
+ Map map = new HashMap();
+ addRequestPropertyValue(map, "passive");
+ addRequestPropertyValue(map, "representationType");
+ addRequestPropertyValue(map, "fileStructure");
+ addRequestPropertyValue(map, "transferMode");
+ return map;
+ }
+
+ private void addRequestPropertyValue(Map map, String key)
+ {
+ String value = getRequestProperty(key);
+ map.put(key, value);
+ }
+
+ public void setRequestProperty(String key, String value)
+ {
+ if (connected)
+ {
+ throw new IllegalStateException();
+ }
+ if ("passive".equals(key))
+ {
+ passive = Boolean.valueOf(value).booleanValue();
+ }
+ else if ("representationType".equals(key))
+ {
+ if ("A".equalsIgnoreCase(value) ||
+ "ASCII".equalsIgnoreCase(value))
+ {
+ representationType = FTPConnection.TYPE_ASCII;
+ }
+ else if ("E".equalsIgnoreCase(value) ||
+ "EBCDIC".equalsIgnoreCase(value))
+ {
+ representationType = FTPConnection.TYPE_EBCDIC;
+ }
+ else if ("I".equalsIgnoreCase(value) ||
+ "BINARY".equalsIgnoreCase(value))
+ {
+ representationType = FTPConnection.TYPE_BINARY;
+ }
+ else
+ {
+ throw new IllegalArgumentException(value);
+ }
+ }
+ else if ("fileStructure".equals(key))
+ {
+ if ("F".equalsIgnoreCase(value) ||
+ "FILE".equalsIgnoreCase(value))
+ {
+ fileStructure = FTPConnection.STRUCTURE_FILE;
+ }
+ else if ("R".equalsIgnoreCase(value) ||
+ "RECORD".equalsIgnoreCase(value))
+ {
+ fileStructure = FTPConnection.STRUCTURE_RECORD;
+ }
+ else if ("P".equalsIgnoreCase(value) ||
+ "PAGE".equalsIgnoreCase(value))
+ {
+ fileStructure = FTPConnection.STRUCTURE_PAGE;
+ }
+ else
+ {
+ throw new IllegalArgumentException(value);
+ }
+ }
+ else if ("transferMode".equals(key))
+ {
+ if ("S".equalsIgnoreCase(value) ||
+ "STREAM".equalsIgnoreCase(value))
+ {
+ transferMode = FTPConnection.MODE_STREAM;
+ }
+ else if ("B".equalsIgnoreCase(value) ||
+ "BLOCK".equalsIgnoreCase(value))
+ {
+ transferMode = FTPConnection.MODE_BLOCK;
+ }
+ else if ("C".equalsIgnoreCase(value) ||
+ "COMPRESSED".equalsIgnoreCase(value))
+ {
+ transferMode = FTPConnection.MODE_COMPRESSED;
+ }
+ else
+ {
+ throw new IllegalArgumentException(value);
+ }
+ }
+ }
+
+ public void addRequestProperty(String key, String value)
+ {
+ setRequestProperty(key, value);
+ }
+
+ class ClosingInputStream
+ extends FilterInputStream
+ {
+
+ ClosingInputStream(InputStream in)
+ {
+ super(in);
+ }
+
+ public void close()
+ throws IOException
+ {
+ super.close();
+ connection.logout();
+ }
+
+ }
+
+ class ClosingOutputStream
+ extends FilterOutputStream
+ {
+
+ ClosingOutputStream(OutputStream out)
+ {
+ super(out);
+ }
+
+ public void close()
+ throws IOException
+ {
+ super.close();
+ connection.logout();
+ }
+
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/Handler.java b/libjava/classpath/gnu/java/net/protocol/ftp/Handler.java
new file mode 100644
index 00000000000..88491b3c15a
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/ftp/Handler.java
@@ -0,0 +1,70 @@
+/* Handler.java --
+ Copyright (C) 2003, 2004 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.ftp;
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+
+/**
+ * An FTP URL stream handler.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class Handler
+ extends URLStreamHandler
+{
+
+ protected int getDefaultPort()
+ {
+ return FTPConnection.FTP_PORT;
+ }
+
+ /**
+ * Returns an FTPURLConnection for the given URL.
+ */
+ public URLConnection openConnection(URL url)
+ throws IOException
+ {
+ return new FTPURLConnection(url);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/PassiveModeDTP.java b/libjava/classpath/gnu/java/net/protocol/ftp/PassiveModeDTP.java
new file mode 100644
index 00000000000..6f4fd634168
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/ftp/PassiveModeDTP.java
@@ -0,0 +1,201 @@
+/* PassiveModeDTP.java --
+ Copyright (C) 2003, 2004 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.ftp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+
+/**
+ * A passive mode FTP data transfer process.
+ * This connects to the host specified and proxies the resulting socket's
+ * input and output streams.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+final class PassiveModeDTP
+ implements DTP
+{
+
+ final String address;
+ final int port;
+ Socket socket;
+ DTPInputStream in;
+ DTPOutputStream out;
+ boolean completed;
+ boolean inProgress;
+ int transferMode;
+
+ PassiveModeDTP(String address, int port, InetAddress localhost,
+ int connectionTimeout, int timeout)
+ throws IOException
+ {
+ this.address = address;
+ this.port = port;
+ completed = false;
+ inProgress = false;
+ socket = new Socket();
+ InetSocketAddress remote = new InetSocketAddress(address, port);
+ InetSocketAddress local = new InetSocketAddress(localhost, port + 1);
+ socket.bind(local);
+ if (connectionTimeout > 0)
+ {
+ socket.connect(remote, connectionTimeout);
+ }
+ else
+ {
+ socket.connect(remote);
+ }
+ if (timeout > 0)
+ {
+ socket.setSoTimeout(timeout);
+ }
+ }
+
+ /**
+ * Returns an input stream from which a remote file can be read.
+ */
+ public InputStream getInputStream()
+ throws IOException
+ {
+ if (inProgress)
+ {
+ throw new IOException("Transfer in progress");
+ }
+ switch (transferMode)
+ {
+ case FTPConnection.MODE_STREAM:
+ in = new StreamInputStream(this, socket.getInputStream());
+ break;
+ case FTPConnection.MODE_BLOCK:
+ in = new BlockInputStream(this, socket.getInputStream());
+ break;
+ case FTPConnection.MODE_COMPRESSED:
+ in = new CompressedInputStream(this, socket.getInputStream());
+ break;
+ default:
+ throw new IllegalStateException("Invalid transfer mode");
+ }
+ in.setTransferComplete(false);
+ return in;
+ }
+
+ /**
+ * Returns an output stream to which a local file can be written for
+ * upload.
+ */
+ public OutputStream getOutputStream()
+ throws IOException
+ {
+ if (inProgress)
+ {
+ throw new IOException("Transfer in progress");
+ }
+ switch (transferMode)
+ {
+ case FTPConnection.MODE_STREAM:
+ out = new StreamOutputStream(this, socket.getOutputStream());
+ break;
+ case FTPConnection.MODE_BLOCK:
+ out = new BlockOutputStream(this, socket.getOutputStream());
+ break;
+ case FTPConnection.MODE_COMPRESSED:
+ out = new CompressedOutputStream(this, socket.getOutputStream());
+ break;
+ default:
+ throw new IllegalStateException("Invalid transfer mode");
+ }
+ out.setTransferComplete(false);
+ return out;
+ }
+
+ public void setTransferMode(int mode)
+ {
+ transferMode = mode;
+ }
+
+ public void complete()
+ {
+ completed = true;
+ if (!inProgress)
+ {
+ transferComplete();
+ }
+ }
+
+ public boolean abort()
+ {
+ completed = true;
+ transferComplete();
+ return inProgress;
+ }
+
+ /*
+ * Called by DTPInputStream or DTPOutputStream when end of
+ * stream is reached.
+ */
+ public void transferComplete()
+ {
+ if (in != null)
+ {
+ in.setTransferComplete(true);
+ }
+ if (out != null)
+ {
+ out.setTransferComplete(true);
+ }
+ inProgress = false;
+ completed = completed ||(transferMode == FTPConnection.MODE_STREAM);
+ if (completed && socket != null)
+ {
+ try
+ {
+ socket.close();
+ }
+ catch (IOException e)
+ {
+ }
+ }
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/StreamInputStream.java b/libjava/classpath/gnu/java/net/protocol/ftp/StreamInputStream.java
new file mode 100644
index 00000000000..93eee4e1924
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/ftp/StreamInputStream.java
@@ -0,0 +1,95 @@
+/* StreamInputStream.java --
+ Copyright (C) 2003, 2004 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.ftp;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * A DTP input stream that implements the FTP stream data transfer mode.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+class StreamInputStream
+ extends DTPInputStream
+{
+
+ StreamInputStream(DTP dtp, InputStream in)
+ {
+ super(dtp, in);
+ }
+
+ public int read()
+ throws IOException
+ {
+ if (transferComplete)
+ {
+ return -1;
+ }
+ int c = in.read();
+ if (c == -1)
+ {
+ close();
+ }
+ return c;
+ }
+
+ public int read(byte[] buf)
+ throws IOException
+ {
+ return read(buf, 0, buf.length);
+ }
+
+ public int read(byte[] buf, int off, int len)
+ throws IOException
+ {
+ if (transferComplete)
+ {
+ return -1;
+ }
+ int l = in.read(buf, off, len);
+ if (l == -1)
+ {
+ close();
+ }
+ return l;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/StreamOutputStream.java b/libjava/classpath/gnu/java/net/protocol/ftp/StreamOutputStream.java
new file mode 100644
index 00000000000..a6e28ece3d4
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/ftp/StreamOutputStream.java
@@ -0,0 +1,85 @@
+/* StreamOutputStream.java --
+ Copyright (C) 2003, 2004 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.ftp;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * A DTP output stream that implements the FTP stream transfer mode.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+class StreamOutputStream
+ extends DTPOutputStream
+{
+
+ StreamOutputStream(DTP dtp, OutputStream out)
+ {
+ super(dtp, out);
+ }
+
+ public void write(int c)
+ throws IOException
+ {
+ if (transferComplete)
+ {
+ return;
+ }
+ out.write(c);
+ }
+
+ public void write(byte[] b)
+ throws IOException
+ {
+ write(b, 0, b.length);
+ }
+
+ public void write(byte[] b, int off, int len)
+ throws IOException
+ {
+ if (transferComplete)
+ {
+ return;
+ }
+ out.write(b, off, len);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/package.html b/libjava/classpath/gnu/java/net/protocol/ftp/package.html
new file mode 100644
index 00000000000..fa3e34d7488
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/ftp/package.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.net.protocol.ftp package.
+ Copyright (C) 2004 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. -->
+
+<html>
+<head><title>GNU Classpath - gnu.java.net.protocol.ftp</title></head>
+
+<body>
+
+<p>
+This package contains an FTP client. It can handle both active and passive
+mode connections and the various transfer modes and representation types.
+</p>
+
+<p>
+Interaction with the server is via a simple stream interface. Only one
+concurrent stream (input or output) is supported.
+</p>
+
+<p>
+The control connection to the server can be protected using TLS
+(the starttls method).
+</p>
+
+</body>
+</html>
diff --git a/libjava/classpath/gnu/java/net/protocol/http/Authenticator.java b/libjava/classpath/gnu/java/net/protocol/http/Authenticator.java
new file mode 100644
index 00000000000..0d7c9881956
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/Authenticator.java
@@ -0,0 +1,59 @@
+/* Authenticator.java --
+ Copyright (C) 2004 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;
+
+/**
+ * Callback interface for managing authentication.
+ * @see Request#setAuthenticator
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public interface Authenticator
+{
+
+ /**
+ * Returns the credentials to supply for the given realm.
+ * @param realm the authentication realm
+ * @param attempt zero on first authentication attempt, increments on each
+ * unsuccessful attempt
+ */
+ Credentials getCredentials(String realm, int attempt);
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/ByteArrayRequestBodyWriter.java b/libjava/classpath/gnu/java/net/protocol/http/ByteArrayRequestBodyWriter.java
new file mode 100644
index 00000000000..35ad2bccf45
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/ByteArrayRequestBodyWriter.java
@@ -0,0 +1,107 @@
+/* ByteArrayRequestBodyWriter.java --
+ Copyright (C) 2004 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;
+
+/**
+ * A simple request body writer using a byte array.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class ByteArrayRequestBodyWriter
+ implements RequestBodyWriter
+{
+
+ /**
+ * The content.
+ */
+ protected byte[] content;
+
+ /**
+ * The position within the content at which the next read will occur.
+ */
+ protected int pos;
+
+ /**
+ * Constructs a new byte array request body writer with the specified
+ * content.
+ * @param content the content buffer
+ */
+ public ByteArrayRequestBodyWriter(byte[] content)
+ {
+ this.content = content;
+ pos = 0;
+ }
+
+ /**
+ * Returns the total number of bytes that will be written in a single pass
+ * by this writer.
+ */
+ public int getContentLength()
+ {
+ return content.length;
+ }
+
+ /**
+ * Initialises the writer.
+ * This will be called before each pass.
+ */
+ public void reset()
+ {
+ pos = 0;
+ }
+
+ /**
+ * Writes body content to the supplied buffer.
+ * @param buffer the content buffer
+ * @return the number of bytes written
+ */
+ public int write(byte[] buffer)
+ {
+ int len = content.length - pos;
+ len = (buffer.length < len) ? buffer.length : len;
+ if (len > -1)
+ {
+ System.arraycopy(content, pos, buffer, 0, len);
+ pos += len;
+ }
+ return len;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/ByteArrayResponseBodyReader.java b/libjava/classpath/gnu/java/net/protocol/http/ByteArrayResponseBodyReader.java
new file mode 100644
index 00000000000..680e45d3e49
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/ByteArrayResponseBodyReader.java
@@ -0,0 +1,123 @@
+/* Authenticator.java --ByteArrayResponseBodyReader.java --
+ Copyright (C) 2004 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;
+
+/**
+ * Simple response body reader that stores content in a byte array.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class ByteArrayResponseBodyReader
+ implements ResponseBodyReader
+{
+
+ /**
+ * The content.
+ */
+ protected byte[] content;
+
+ /**
+ * The position in the content at which the next write will occur.
+ */
+ protected int pos;
+
+ /**
+ * The length of the buffer.
+ */
+ protected int len;
+
+ /**
+ * Constructs a new byte array response body reader.
+ */
+ public ByteArrayResponseBodyReader()
+ {
+ this(4096);
+ }
+
+ /**
+ * Constructs a new byte array response body reader with the specified
+ * initial buffer size.
+ * @param size the initial buffer size
+ */
+ public ByteArrayResponseBodyReader(int size)
+ {
+ content = new byte[size];
+ pos = len = 0;
+ }
+
+ /**
+ * This reader accepts all responses.
+ */
+ public boolean accept(Request request, Response response)
+ {
+ return true;
+ }
+
+ public void read(byte[] buffer, int offset, int length)
+ {
+ int l = length - offset;
+ if (pos + l > content.length)
+ {
+ byte[] tmp = new byte[content.length * 2];
+ System.arraycopy(content, 0, tmp, 0, pos);
+ content = tmp;
+ }
+ System.arraycopy(buffer, offset, content, pos, l);
+ pos += l;
+ len = pos;
+ }
+
+ public void close()
+ {
+ pos = 0;
+ }
+
+ /**
+ * Retrieves the content of this reader as a byte array.
+ * The size of the returned array is the number of bytes read.
+ */
+ public byte[] toByteArray()
+ {
+ byte[] ret = new byte[len];
+ System.arraycopy(content, 0, ret, 0, len);
+ return ret;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/ChunkedInputStream.java b/libjava/classpath/gnu/java/net/protocol/http/ChunkedInputStream.java
new file mode 100644
index 00000000000..c0706b70840
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/ChunkedInputStream.java
@@ -0,0 +1,172 @@
+/* ChunkedInputStream.java --
+ Copyright (C) 2004 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 java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.ProtocolException;
+
+/**
+ * Input stream wrapper for the "chunked" transfer-coding.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class ChunkedInputStream
+ extends FilterInputStream
+{
+
+ private static final byte CR = 0x0d;
+ private static final byte LF = 0x0a;
+
+ int size;
+ int count;
+ boolean meta;
+ boolean eof;
+ Headers headers;
+
+ /**
+ * Constructor.
+ * @param in the response socket input stream
+ * @param headers the headers to receive additional header lines
+ */
+ public ChunkedInputStream(InputStream in, Headers headers)
+ {
+ super(in);
+ this.headers = headers;
+ size = -1;
+ count = 0;
+ meta = true;
+ }
+
+ public int read()
+ throws IOException
+ {
+ byte[] buf = new byte[1];
+ int len = read(buf, 0, 1);
+ if (len == -1)
+ {
+ return -1;
+ }
+ int ret = (int) buf[0];
+ if (ret < 0)
+ {
+ ret += 0x100;
+ }
+ return ret;
+ }
+
+ public int read(byte[] buffer)
+ throws IOException
+ {
+ return read(buffer, 0, buffer.length);
+ }
+
+ public int read(byte[] buffer, int offset, int length)
+ throws IOException
+ {
+ if (eof)
+ {
+ return -1;
+ }
+ if (meta)
+ {
+ // Read chunk header
+ int c, last = 0;
+ boolean seenSemi = false;
+ StringBuffer buf = new StringBuffer();
+ do
+ {
+ c = in.read();
+ if (c == 0x3b) // ;
+ {
+ seenSemi = true;
+ }
+ else if (c == 0x0a && last == 0x0d) // CRLF
+ {
+ size = Integer.parseInt(buf.toString(), 16);
+ break;
+ }
+ else if (!seenSemi && c >= 0x30)
+ {
+ buf.append ((char) c);
+ }
+ last = c;
+ }
+ while(c != -1);
+ count = 0;
+ meta = false;
+ }
+ if (size == 0)
+ {
+ // Read trailer
+ headers.parse(in);
+ eof = true;
+ return -1;
+ }
+ else
+ {
+ int diff = length - offset;
+ int max = size - count;
+ max = (diff < max) ? diff : max;
+ int len = (max > 0) ? in.read(buffer, offset, max) : 0;
+ count += len;
+ if (count == size)
+ {
+ // Read CRLF
+ int c1 = in.read();
+ int c2 = in.read();
+ if (c1 == -1 && c2 == -1)
+ {
+ // EOF before CRLF: bad, but ignore
+ eof = true;
+ return -1;
+ }
+ if (c1 != 0x0d || c2 != 0x0a)
+ {
+ throw new ProtocolException("expecting CRLF: " + c1 + "," + c2);
+ }
+ meta = true;
+ }
+ return len;
+ }
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/Cookie.java b/libjava/classpath/gnu/java/net/protocol/http/Cookie.java
new file mode 100644
index 00000000000..45e2f733ff3
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/Cookie.java
@@ -0,0 +1,160 @@
+/* Cookie.java --
+ Copyright (C) 2004 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 java.util.Date;
+
+/**
+ * An HTTP cookie, as specified in RFC 2109.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class Cookie
+{
+
+ /**
+ * The name of the cookie.
+ */
+ protected final String name;
+
+ /**
+ * The value of the cookie.
+ */
+ protected final String value;
+
+ /**
+ * Optional documentation of the intended use of the cookie.
+ */
+ protected final String comment;
+
+ /**
+ * The domain for which the cookie is valid.
+ */
+ protected final String domain;
+
+ /**
+ * Optional subset of URL paths within the domain for which the cookie is
+ * valid.
+ */
+ protected final String path;
+
+ /**
+ * Indicates that the user-agent should only use secure means to transmit
+ * this cookie to the server.
+ */
+ protected final boolean secure;
+
+ /**
+ * The date at which this cookie expires.
+ */
+ protected final Date expires;
+
+ public Cookie(String name, String value, String comment, String domain,
+ String path, boolean secure, Date expires)
+ {
+ this.name = name;
+ this.value = value;
+ this.comment = comment;
+ this.domain = domain;
+ this.path = path;
+ this.secure = secure;
+ this.expires = expires;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public String getValue()
+ {
+ return value;
+ }
+
+ public String getComment()
+ {
+ return comment;
+ }
+
+ public String getDomain()
+ {
+ return domain;
+ }
+
+ public String getPath()
+ {
+ return path;
+ }
+
+ public boolean isSecure()
+ {
+ return secure;
+ }
+
+ public Date getExpiryDate()
+ {
+ return expires;
+ }
+
+ public String toString()
+ {
+ return toString(true, true);
+ }
+
+ public String toString(boolean showPath, boolean showDomain)
+ {
+ StringBuffer buf = new StringBuffer();
+ buf.append(name);
+ buf.append('=');
+ buf.append(value);
+ if (showPath)
+ {
+ buf.append("; $Path=");
+ buf.append(path);
+ }
+ if (showDomain)
+ {
+ buf.append("; $Domain=");
+ buf.append(domain);
+ }
+ return buf.toString();
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/CookieManager.java b/libjava/classpath/gnu/java/net/protocol/http/CookieManager.java
new file mode 100644
index 00000000000..cc1225c497d
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/CookieManager.java
@@ -0,0 +1,65 @@
+/* CookieManager.java --
+ Copyright (C) 2004 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;
+
+/**
+ * Cookie manager interface.
+ * If an application wants to handle cookies, they should implement this
+ * interface and register the instance with each HTTPConnection they use.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public interface CookieManager
+{
+
+ /**
+ * Stores a cookie in the cookie manager.
+ * @param cookie the cookie to store
+ */
+ void setCookie(Cookie cookie);
+
+ /**
+ * Retrieves the cookies matching the specified criteria.
+ * @param host the host name
+ * @param secure whether the connection is secure
+ * @param path the path to access
+ */
+ Cookie[] getCookies(String host, boolean secure, String path);
+
+}
diff --git a/libjava/classpath/gnu/java/net/protocol/http/Credentials.java b/libjava/classpath/gnu/java/net/protocol/http/Credentials.java
new file mode 100644
index 00000000000..9e5fcd172f5
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/Credentials.java
@@ -0,0 +1,88 @@
+/* Credentials.java --
+ Copyright (C) 2004 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;
+
+/**
+ * Represents a username/password combination that can be used to
+ * authenticate to an HTTP server.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class Credentials
+{
+
+ /**
+ * The username.
+ */
+ private String username;
+
+ /**
+ * The password.
+ */
+ private String password;
+
+ /**
+ * Constructor.
+ * @param username the username
+ * @param password the password
+ */
+ public Credentials(String username, String password)
+ {
+ this.username = username;
+ this.password = password;
+ }
+
+ /**
+ * Returns the username.
+ */
+ public String getUsername()
+ {
+ return username;
+ }
+
+ /**
+ * Returns the password.
+ */
+ public String getPassword()
+ {
+ return password;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/HTTPConnection.java b/libjava/classpath/gnu/java/net/protocol/http/HTTPConnection.java
new file mode 100644
index 00000000000..6d9f447a2ac
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/HTTPConnection.java
@@ -0,0 +1,681 @@
+/* HTTPConnection.java --
+ Copyright (C) 2004, 2005 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.classpath.Configuration;
+import gnu.classpath.SystemProperties;
+import gnu.java.net.EmptyX509TrustManager;
+import gnu.java.net.protocol.http.event.ConnectionEvent;
+import gnu.java.net.protocol.http.event.ConnectionListener;
+import gnu.java.net.protocol.http.event.RequestEvent;
+import gnu.java.net.protocol.http.event.RequestListener;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.security.GeneralSecurityException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.net.ssl.HandshakeCompletedListener;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+
+/**
+ * A connection to an HTTP server.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class HTTPConnection
+{
+
+ /**
+ * The default HTTP port.
+ */
+ public static final int HTTP_PORT = 80;
+
+ /**
+ * The default HTTPS port.
+ */
+ public static final int HTTPS_PORT = 443;
+
+ private static final String userAgent = SystemProperties.getProperty("http.agent");
+
+ /**
+ * The host name of the server to connect to.
+ */
+ protected final String hostname;
+
+ /**
+ * The port to connect to.
+ */
+ protected final int port;
+
+ /**
+ * Whether the connection should use transport level security (HTTPS).
+ */
+ protected final boolean secure;
+
+ /**
+ * The connection timeout for connecting the underlying socket.
+ */
+ protected final int connectionTimeout;
+
+ /**
+ * The read timeout for reads on the underlying socket.
+ */
+ protected final int timeout;
+
+ /**
+ * The host name of the proxy to connect to.
+ */
+ protected String proxyHostname;
+
+ /**
+ * The port on the proxy to connect to.
+ */
+ protected int proxyPort;
+
+ /**
+ * The major version of HTTP supported by this client.
+ */
+ protected int majorVersion;
+
+ /**
+ * The minor version of HTTP supported by this client.
+ */
+ protected int minorVersion;
+
+ private final List connectionListeners;
+ private final List requestListeners;
+ private final List handshakeCompletedListeners;
+
+ /**
+ * The socket this connection communicates on.
+ */
+ protected Socket socket;
+
+ /**
+ * The SSL socket factory to use.
+ */
+ private SSLSocketFactory sslSocketFactory;
+
+ /**
+ * The socket input stream.
+ */
+ protected InputStream in;
+
+ /**
+ * The socket output stream.
+ */
+ protected OutputStream out;
+
+ /**
+ * Nonce values seen by this connection.
+ */
+ private Map nonceCounts;
+
+ /**
+ * The cookie manager for this connection.
+ */
+ protected CookieManager cookieManager;
+
+ /**
+ * Creates a new HTTP connection.
+ * @param hostname the name of the host to connect to
+ */
+ public HTTPConnection(String hostname)
+ {
+ this(hostname, HTTP_PORT, false, 0, 0);
+ }
+
+ /**
+ * Creates a new HTTP or HTTPS connection.
+ * @param hostname the name of the host to connect to
+ * @param secure whether to use a secure connection
+ */
+ public HTTPConnection(String hostname, boolean secure)
+ {
+ this(hostname, secure ? HTTPS_PORT : HTTP_PORT, secure, 0, 0);
+ }
+
+ /**
+ * Creates a new HTTP or HTTPS connection on the specified port.
+ * @param hostname the name of the host to connect to
+ * @param secure whether to use a secure connection
+ * @param connectionTimeout the connection timeout
+ * @param timeout the socket read timeout
+ */
+ public HTTPConnection(String hostname, boolean secure,
+ int connectionTimeout, int timeout)
+ {
+ this(hostname, secure ? HTTPS_PORT : HTTP_PORT, secure,
+ connectionTimeout, timeout);
+ }
+
+ /**
+ * Creates a new HTTP connection on the specified port.
+ * @param hostname the name of the host to connect to
+ * @param port the port on the host to connect to
+ */
+ public HTTPConnection(String hostname, int port)
+ {
+ this(hostname, port, false, 0, 0);
+ }
+
+ /**
+ * Creates a new HTTP or HTTPS connection on the specified port.
+ * @param hostname 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
+ */
+ public HTTPConnection(String hostname, int port, boolean secure)
+ {
+ this(hostname, port, secure, 0, 0);
+ }
+
+ /**
+ * Creates a new HTTP or HTTPS connection on the specified port.
+ * @param hostname 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
+ * @param connectionTimeout the connection timeout
+ * @param timeout the socket read timeout
+ */
+ public HTTPConnection(String hostname, int port, boolean secure,
+ int connectionTimeout, int timeout)
+ {
+ this.hostname = hostname;
+ this.port = port;
+ this.secure = secure;
+ this.connectionTimeout = connectionTimeout;
+ this.timeout = timeout;
+ majorVersion = minorVersion = 1;
+ connectionListeners = new ArrayList(4);
+ requestListeners = new ArrayList(4);
+ handshakeCompletedListeners = new ArrayList(2);
+ }
+
+ /**
+ * Returns the name of the host to connect to.
+ */
+ public String getHostName()
+ {
+ return hostname;
+ }
+
+ /**
+ * Returns the port on the host to connect to.
+ */
+ public int getPort()
+ {
+ return port;
+ }
+
+ /**
+ * Indicates whether to use a secure connection or not.
+ */
+ public boolean isSecure()
+ {
+ return secure;
+ }
+
+ /**
+ * Returns the HTTP version string supported by this connection.
+ * @see #version
+ */
+ public String getVersion()
+ {
+ return "HTTP/" + majorVersion + '.' + minorVersion;
+ }
+
+ /**
+ * Sets the HTTP version supported by this connection.
+ * @param majorVersion the major version
+ * @param minorVersion the minor version
+ */
+ public void setVersion(int majorVersion, int minorVersion)
+ {
+ if (majorVersion != 1)
+ {
+ throw new IllegalArgumentException("major version not supported: " +
+ majorVersion);
+ }
+ if (minorVersion < 0 || minorVersion > 1)
+ {
+ throw new IllegalArgumentException("minor version not supported: " +
+ minorVersion);
+ }
+ this.majorVersion = majorVersion;
+ this.minorVersion = minorVersion;
+ }
+
+ /**
+ * Directs this connection to use the specified proxy.
+ * @param hostname the proxy host name
+ * @param port the port on the proxy to connect to
+ */
+ public void setProxy(String hostname, int port)
+ {
+ proxyHostname = hostname;
+ proxyPort = port;
+ }
+
+ /**
+ * Indicates whether this connection is using an HTTP proxy.
+ */
+ public boolean isUsingProxy()
+ {
+ return (proxyHostname != null && proxyPort > 0);
+ }
+
+ /**
+ * Sets the cookie manager to use for this connection.
+ * @param cookieManager the cookie manager
+ */
+ public void setCookieManager(CookieManager cookieManager)
+ {
+ this.cookieManager = cookieManager;
+ }
+
+ /**
+ * Returns the cookie manager in use for this connection.
+ */
+ public CookieManager getCookieManager()
+ {
+ return cookieManager;
+ }
+
+ /**
+ * Creates a new request using this connection.
+ * @param method the HTTP method to invoke
+ * @param path the URI-escaped RFC2396 <code>abs_path</code> with
+ * optional query part
+ */
+ public Request newRequest(String method, String path)
+ {
+ if (method == null || method.length() == 0)
+ {
+ throw new IllegalArgumentException("method must have non-zero length");
+ }
+ if (path == null || path.length() == 0)
+ {
+ path = "/";
+ }
+ Request ret = new Request(this, method, path);
+ if ((secure && port != HTTPS_PORT) ||
+ (!secure && port != HTTP_PORT))
+ {
+ ret.setHeader("Host", hostname + ":" + port);
+ }
+ else
+ {
+ ret.setHeader("Host", hostname);
+ }
+ ret.setHeader("User-Agent", userAgent);
+ ret.setHeader("Connection", "keep-alive");
+ ret.setHeader("Accept-Encoding",
+ "chunked;q=1.0, gzip;q=0.9, deflate;q=0.8, " +
+ "identity;q=0.6, *;q=0");
+ if (cookieManager != null)
+ {
+ Cookie[] cookies = cookieManager.getCookies(hostname, secure, path);
+ if (cookies != null && cookies.length > 0)
+ {
+ StringBuffer buf = new StringBuffer();
+ buf.append("$Version=1");
+ for (int i = 0; i < cookies.length; i++)
+ {
+ buf.append(',');
+ buf.append(' ');
+ buf.append(cookies[i].toString());
+ }
+ ret.setHeader("Cookie", buf.toString());
+ }
+ }
+ fireRequestEvent(RequestEvent.REQUEST_CREATED, ret);
+ return ret;
+ }
+
+ /**
+ * Closes this connection.
+ */
+ public void close()
+ throws IOException
+ {
+ try
+ {
+ closeConnection();
+ }
+ finally
+ {
+ fireConnectionEvent(ConnectionEvent.CONNECTION_CLOSED);
+ }
+ }
+
+ /**
+ * Retrieves the socket associated with this connection.
+ * This creates the socket if necessary.
+ */
+ protected synchronized Socket getSocket()
+ throws IOException
+ {
+ if (socket == null)
+ {
+ String connectHostname = hostname;
+ int connectPort = port;
+ if (isUsingProxy())
+ {
+ connectHostname = proxyHostname;
+ connectPort = proxyPort;
+ }
+ socket = new Socket();
+ InetSocketAddress address =
+ new InetSocketAddress(connectHostname, connectPort);
+ if (connectionTimeout > 0)
+ {
+ socket.connect(address, connectionTimeout);
+ }
+ else
+ {
+ socket.connect(address);
+ }
+ if (timeout > 0)
+ {
+ socket.setSoTimeout(timeout);
+ }
+ if (secure)
+ {
+ try
+ {
+ SSLSocketFactory factory = getSSLSocketFactory();
+ SSLSocket ss =
+ (SSLSocket) factory.createSocket(socket, connectHostname,
+ connectPort, true);
+ String[] protocols = { "TLSv1", "SSLv3" };
+ ss.setEnabledProtocols(protocols);
+ ss.setUseClientMode(true);
+ synchronized (handshakeCompletedListeners)
+ {
+ if (!handshakeCompletedListeners.isEmpty())
+ {
+ for (Iterator i =
+ handshakeCompletedListeners.iterator();
+ i.hasNext(); )
+ {
+ HandshakeCompletedListener l =
+ (HandshakeCompletedListener) i.next();
+ ss.addHandshakeCompletedListener(l);
+ }
+ }
+ }
+ ss.startHandshake();
+ socket = ss;
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new IOException(e.getMessage());
+ }
+ }
+ in = socket.getInputStream();
+ in = new BufferedInputStream(in);
+ out = socket.getOutputStream();
+ out = new BufferedOutputStream(out);
+ }
+ return socket;
+ }
+
+ SSLSocketFactory getSSLSocketFactory()
+ throws GeneralSecurityException
+ {
+ if (sslSocketFactory == null)
+ {
+ TrustManager tm = new EmptyX509TrustManager();
+ SSLContext context = SSLContext.getInstance("SSL");
+ TrustManager[] trust = new TrustManager[] { tm };
+ context.init(null, trust, null);
+ sslSocketFactory = context.getSocketFactory();
+ }
+ return sslSocketFactory;
+ }
+
+ void setSSLSocketFactory(SSLSocketFactory factory)
+ {
+ sslSocketFactory = factory;
+ }
+
+ protected synchronized InputStream getInputStream()
+ throws IOException
+ {
+ if (socket == null)
+ {
+ getSocket();
+ }
+ return in;
+ }
+
+ protected synchronized OutputStream getOutputStream()
+ throws IOException
+ {
+ if (socket == null)
+ {
+ getSocket();
+ }
+ return out;
+ }
+
+ /**
+ * Closes the underlying socket, if any.
+ */
+ protected synchronized void closeConnection()
+ throws IOException
+ {
+ if (socket != null)
+ {
+ try
+ {
+ socket.close();
+ }
+ finally
+ {
+ socket = null;
+ }
+ }
+ }
+
+ /**
+ * Returns a URI representing the connection.
+ * This does not include any request path component.
+ */
+ protected String getURI()
+ {
+ StringBuffer buf = new StringBuffer();
+ buf.append(secure ? "https://" : "http://");
+ buf.append(hostname);
+ if (secure)
+ {
+ if (port != HTTPConnection.HTTPS_PORT)
+ {
+ buf.append(':');
+ buf.append(port);
+ }
+ }
+ else
+ {
+ if (port != HTTPConnection.HTTP_PORT)
+ {
+ buf.append(':');
+ buf.append(port);
+ }
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Get the number of times the specified nonce has been seen by this
+ * connection.
+ */
+ int getNonceCount(String nonce)
+ {
+ if (nonceCounts == null)
+ {
+ return 0;
+ }
+ return((Integer) nonceCounts.get(nonce)).intValue();
+ }
+
+ /**
+ * Increment the number of times the specified nonce has been seen.
+ */
+ void incrementNonce(String nonce)
+ {
+ int current = getNonceCount(nonce);
+ if (nonceCounts == null)
+ {
+ nonceCounts = new HashMap();
+ }
+ nonceCounts.put(nonce, new Integer(current + 1));
+ }
+
+ // -- Events --
+
+ public void addConnectionListener(ConnectionListener l)
+ {
+ synchronized (connectionListeners)
+ {
+ connectionListeners.add(l);
+ }
+ }
+
+ public void removeConnectionListener(ConnectionListener l)
+ {
+ synchronized (connectionListeners)
+ {
+ connectionListeners.remove(l);
+ }
+ }
+
+ protected void fireConnectionEvent(int type)
+ {
+ ConnectionEvent event = new ConnectionEvent(this, type);
+ ConnectionListener[] l = null;
+ synchronized (connectionListeners)
+ {
+ l = new ConnectionListener[connectionListeners.size()];
+ connectionListeners.toArray(l);
+ }
+ for (int i = 0; i < l.length; i++)
+ {
+ switch (type)
+ {
+ case ConnectionEvent.CONNECTION_CLOSED:
+ l[i].connectionClosed(event);
+ break;
+ }
+ }
+ }
+
+ public void addRequestListener(RequestListener l)
+ {
+ synchronized (requestListeners)
+ {
+ requestListeners.add(l);
+ }
+ }
+
+ public void removeRequestListener(RequestListener l)
+ {
+ synchronized (requestListeners)
+ {
+ requestListeners.remove(l);
+ }
+ }
+
+ protected void fireRequestEvent(int type, Request request)
+ {
+ RequestEvent event = new RequestEvent(this, type, request);
+ RequestListener[] l = null;
+ synchronized (requestListeners)
+ {
+ l = new RequestListener[requestListeners.size()];
+ requestListeners.toArray(l);
+ }
+ for (int i = 0; i < l.length; i++)
+ {
+ switch (type)
+ {
+ case RequestEvent.REQUEST_CREATED:
+ l[i].requestCreated(event);
+ break;
+ case RequestEvent.REQUEST_SENDING:
+ l[i].requestSent(event);
+ break;
+ case RequestEvent.REQUEST_SENT:
+ l[i].requestSent(event);
+ break;
+ }
+ }
+ }
+
+ void addHandshakeCompletedListener(HandshakeCompletedListener l)
+ {
+ synchronized (handshakeCompletedListeners)
+ {
+ handshakeCompletedListeners.add(l);
+ }
+ }
+ void removeHandshakeCompletedListener(HandshakeCompletedListener l)
+ {
+ synchronized (handshakeCompletedListeners)
+ {
+ handshakeCompletedListeners.remove(l);
+ }
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/HTTPDateFormat.java b/libjava/classpath/gnu/java/net/protocol/http/HTTPDateFormat.java
new file mode 100644
index 00000000000..2f59e43181c
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/HTTPDateFormat.java
@@ -0,0 +1,441 @@
+/* HTTPDateFormat.java --
+ Copyright (C) 2004 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 java.text.DateFormat;
+import java.text.DecimalFormat;
+import java.text.FieldPosition;
+import java.text.NumberFormat;
+import java.text.ParsePosition;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+
+/**
+ * HTTP date formatter and parser.
+ * Formats dates according to RFC 822 (updated by RFC 1123).
+ * Parses dates according to the above, <i>or</i> RFC 1036, <i>or</i> the
+ * ANSI C <code>asctime()</code> format.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class HTTPDateFormat
+ extends DateFormat
+{
+
+ static final String[] DAYS_OF_WEEK = {
+ null, "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+ };
+
+ static final String[] MONTHS = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+
+ public HTTPDateFormat()
+ {
+ calendar = new GregorianCalendar(TimeZone.getTimeZone ("GMT"));
+ numberFormat = new DecimalFormat();
+ }
+
+ /**
+ * Appends the textual value for the specified field to the given string
+ * buffer. This method should be avoided, use <code>format(Date)</code>
+ * instead.
+ * @param date the Date object
+ * @param buf the buffer to append to
+ * @param field the current field position
+ * @return the modified buffer
+ */
+ public StringBuffer format(Date date, StringBuffer buf,
+ FieldPosition field)
+ {
+ calendar.clear();
+ calendar.setTime(date);
+ buf.setLength(0);
+
+ // Day of week
+ buf.append(DAYS_OF_WEEK[calendar.get(Calendar.DAY_OF_WEEK)]);
+ buf.append(',');
+ buf.append(' ');
+
+ // Day of month
+ int day = calendar.get(Calendar.DAY_OF_MONTH);
+ buf.append(Character.forDigit(day / 10, 10));
+ buf.append(Character.forDigit(day % 10, 10));
+ buf.append(' ');
+
+ // Month
+ buf.append(MONTHS[calendar.get(Calendar.MONTH)]);
+ buf.append(' ');
+
+ // Year
+ int year = calendar.get(Calendar.YEAR);
+ if (year < 1000)
+ {
+ buf.append('0');
+ if (year < 100)
+ {
+ buf.append('0');
+ if (year < 10)
+ {
+ buf.append('0');
+ }
+ }
+ }
+ buf.append(Integer.toString(year));
+ buf.append(' ');
+
+ // Hour
+ int hour = calendar.get(Calendar.HOUR_OF_DAY);
+ buf.append(Character.forDigit(hour / 10, 10));
+ buf.append(Character.forDigit(hour % 10, 10));
+ buf.append(':');
+
+ // Minute
+ int minute = calendar.get(Calendar.MINUTE);
+ buf.append(Character.forDigit(minute / 10, 10));
+ buf.append(Character.forDigit(minute % 10, 10));
+ buf.append(':');
+
+ // Second
+ int second = calendar.get(Calendar.SECOND);
+ buf.append(Character.forDigit(second / 10, 10));
+ buf.append(Character.forDigit(second % 10, 10));
+ buf.append(' ');
+
+ // Timezone
+ // Get time offset in minutes
+ int zoneOffset =(calendar.get(Calendar.ZONE_OFFSET) +
+ calendar.get(Calendar.DST_OFFSET)) / 60000;
+
+ // Apply + or - appropriately
+ if (zoneOffset < 0)
+ {
+ zoneOffset = -zoneOffset;
+ buf.append('-');
+ }
+ else
+ {
+ buf.append('+');
+ }
+
+ // Set the 2 2-char fields as specified above
+ int tzhours = zoneOffset / 60;
+ buf.append(Character.forDigit(tzhours / 10, 10));
+ buf.append(Character.forDigit(tzhours % 10, 10));
+ int tzminutes = zoneOffset % 60;
+ buf.append(Character.forDigit(tzminutes / 10, 10));
+ buf.append(Character.forDigit(tzminutes % 10, 10));
+
+ field.setBeginIndex(0);
+ field.setEndIndex(buf.length());
+ return buf;
+ }
+
+ /**
+ * Parses the given date in the current TimeZone.
+ * @param text the formatted date to be parsed
+ * @param pos the current parse position
+ */
+ public Date parse(String text, ParsePosition pos)
+ {
+ int date, month, year, hour, minute, second;
+ String monthText;
+ int start = 0, end = -1;
+ int len = text.length();
+ calendar.clear();
+ pos.setIndex(start);
+ try
+ {
+ // Advance to date
+ if (Character.isLetter(text.charAt(start)))
+ {
+ start = skipNonWhitespace(text, start);
+ }
+ // Determine mode
+ switch(start)
+ {
+ case 3:
+ // asctime
+ start = skipWhitespace(text, start);
+ pos.setIndex(start);
+ end = skipNonWhitespace(text, start + 1);
+ monthText = text.substring(start, end);
+ month = -1;
+ for (int i = 0; i < 12; i++)
+ {
+ if (MONTHS[i].equals(monthText))
+ {
+ month = i;
+ break;
+ }
+ }
+ if (month == -1)
+ {
+ pos.setErrorIndex(end);
+ return null;
+ }
+ // Advance to date
+ start = skipWhitespace(text, end + 1);
+ pos.setIndex(start);
+ end = skipNonWhitespace(text, start + 1);
+ date = Integer.parseInt(text.substring(start, end));
+ // Advance to hour
+ start = skipWhitespace(text, end + 1);
+ pos.setIndex(start);
+ end = skipTo(text, start + 1, ':');
+ hour = Integer.parseInt(text.substring(start, end));
+ // Advance to minute
+ start = end + 1;
+ pos.setIndex(start);
+ end = skipTo(text, start + 1, ':');
+ minute = Integer.parseInt(text.substring(start, end));
+ // Advance to second
+ start = end + 1;
+ pos.setIndex(start);
+ end = skipNonWhitespace(text, start + 1);
+ second = Integer.parseInt(text.substring(start, end));
+ // Advance to year
+ start = skipWhitespace(text, end + 1);
+ pos.setIndex(start);
+ end = skipNonWhitespace(text, start + 1);
+ year = Integer.parseInt(text.substring(start, end));
+ break;
+ case 0:
+ case 4:
+ // rfc822
+ start = skipWhitespace(text, start);
+ pos.setIndex(start);
+ end = skipNonWhitespace(text, start + 1);
+ date = Integer.parseInt(text.substring(start, end));
+ // Advance to month
+ start = skipWhitespace(text, end + 1);
+ pos.setIndex(start);
+ end = skipNonWhitespace(text, start + 1);
+ monthText = text.substring(start, end);
+ month = -1;
+ for (int i = 0; i < 12; i++)
+ {
+ if (MONTHS[i].equals(monthText))
+ {
+ month = i;
+ break;
+ }
+ }
+ if (month == -1)
+ {
+ pos.setErrorIndex(end);
+ return null;
+ }
+ // Advance to year
+ start = skipWhitespace(text, end + 1);
+ pos.setIndex(start);
+ end = skipNonWhitespace(text, start + 1);
+ year = Integer.parseInt(text.substring(start, end));
+ // Advance to hour
+ start = skipWhitespace(text, end + 1);
+ pos.setIndex(start);
+ end = skipTo(text, start + 1, ':');
+ hour = Integer.parseInt(text.substring(start, end));
+ // Advance to minute
+ start = end + 1;
+ pos.setIndex(start);
+ end = skipTo(text, start + 1, ':');
+ minute = Integer.parseInt(text.substring(start, end));
+ // Advance to second
+ start = end + 1;
+ pos.setIndex(start);
+ end = start + 1;
+ while (end < len && !Character.isWhitespace(text.charAt(end)))
+ {
+ end++;
+ }
+ second = Integer.parseInt(text.substring(start, end));
+ break;
+ default:
+ // rfc850(obsolete)
+ start = skipWhitespace(text, start);
+ pos.setIndex(start);
+ end = skipTo(text, start + 1, '-');
+ date = Integer.parseInt(text.substring(start, end));
+ // Advance to month
+ start = end + 1;
+ pos.setIndex(start);
+ end = skipTo(text, start + 1, '-');
+ monthText = text.substring(start, end);
+ month = -1;
+ for (int i = 0; i < 12; i++)
+ {
+ if (MONTHS[i].equals(monthText))
+ {
+ month = i;
+ break;
+ }
+ }
+ if (month == -1)
+ {
+ pos.setErrorIndex(end);
+ return null;
+ }
+ // Advance to year
+ start = end + 1;
+ pos.setIndex(start);
+ end = skipNonWhitespace(text, start + 1);
+ year = 1900 + Integer.parseInt(text.substring(start, end));
+ // Advance to hour
+ start = skipWhitespace(text, end + 1);
+ pos.setIndex(start);
+ end = skipTo(text, start + 1, ':');
+ hour = Integer.parseInt(text.substring(start, end));
+ // Advance to minute
+ start = end + 1;
+ pos.setIndex(start);
+ end = skipTo(text, start + 1, ':');
+ minute = Integer.parseInt(text.substring(start, end));
+ // Advance to second
+ start = end + 1;
+ pos.setIndex(start);
+ end = start + 1;
+ while (end < len && !Character.isWhitespace(text.charAt(end)))
+ {
+ end++;
+ }
+ second = Integer.parseInt(text.substring(start, end));
+ }
+
+ calendar.set(Calendar.YEAR, year);
+ calendar.set(Calendar.MONTH, month);
+ calendar.set(Calendar.DAY_OF_MONTH, date);
+ calendar.set(Calendar.HOUR, hour);
+ calendar.set(Calendar.MINUTE, minute);
+ calendar.set(Calendar.SECOND, second);
+
+ if (end != len)
+ {
+ // Timezone
+ start = skipWhitespace(text, end + 1);
+ end = start + 1;
+ while (end < len && !Character.isWhitespace(text.charAt(end)))
+ {
+ end++;
+ }
+ char pm = text.charAt(start);
+ if (Character.isLetter(pm))
+ {
+ TimeZone tz =
+ TimeZone.getTimeZone(text.substring(start, end));
+ calendar.set(Calendar.ZONE_OFFSET, tz.getRawOffset());
+ }
+ else
+ {
+ int zoneOffset = 0;
+ zoneOffset += 600 * Character.digit(text.charAt(++start), 10);
+ zoneOffset += 60 * Character.digit(text.charAt(++start), 10);
+ zoneOffset += 10 * Character.digit(text.charAt(++start), 10);
+ zoneOffset += Character.digit(text.charAt(++start), 10);
+ zoneOffset *= 60000; // minutes -> ms
+ if ('-' == pm)
+ {
+ zoneOffset = -zoneOffset;
+ }
+ calendar.set(Calendar.ZONE_OFFSET, zoneOffset);
+ }
+ }
+ pos.setIndex(end);
+
+ return calendar.getTime();
+ }
+ catch (NumberFormatException e)
+ {
+ pos.setErrorIndex(Math.max(start, end));
+ }
+ catch (StringIndexOutOfBoundsException e)
+ {
+ pos.setErrorIndex(Math.max(start, end));
+ }
+ return null;
+ }
+
+ private int skipWhitespace(String text, int pos)
+ {
+ while(Character.isWhitespace(text.charAt(pos)))
+ {
+ pos++;
+ }
+ return pos;
+ }
+
+ private int skipNonWhitespace(String text, int pos)
+ {
+ while(!Character.isWhitespace(text.charAt(pos)))
+ {
+ pos++;
+ }
+ return pos;
+ }
+
+ private int skipTo(String text, int pos, char c)
+ {
+ while(text.charAt(pos) != c)
+ {
+ pos++;
+ }
+ return pos;
+ }
+
+ /**
+ * Don't allow setting the calendar.
+ */
+ public void setCalendar(Calendar newCalendar)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Don't allow setting the NumberFormat.
+ */
+ public void setNumberFormat(NumberFormat newNumberFormat)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/HTTPURLConnection.java b/libjava/classpath/gnu/java/net/protocol/http/HTTPURLConnection.java
new file mode 100644
index 00000000000..9f2055fe658
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/HTTPURLConnection.java
@@ -0,0 +1,688 @@
+/* HTTPURLConnection.java --
+ Copyright (C) 2004, 2005 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 java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+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.Collections;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.net.ssl.HandshakeCompletedEvent;
+import javax.net.ssl.HandshakeCompletedListener;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSocketFactory;
+
+/**
+ * A URLConnection that uses the HTTPConnection class.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class HTTPURLConnection
+ extends HttpsURLConnection
+ implements HandshakeCompletedListener
+{
+
+ /**
+ * Pool of reusable connections, used if keepAlive is true.
+ */
+ private static final Map connectionPool = new LinkedHashMap();
+
+ /*
+ * The underlying connection.
+ */
+ private HTTPConnection connection;
+
+ // These are package private for use in anonymous inner classes.
+ String proxyHostname;
+ int proxyPort;
+ String agent;
+ boolean keepAlive;
+ int maxConnections;
+
+ private Request request;
+ private Headers requestHeaders;
+ private ByteArrayOutputStream requestSink;
+ private boolean requestMethodSetExplicitly;
+
+ private Response response;
+ private ByteArrayInputStream responseSink;
+ private ByteArrayInputStream errorSink;
+
+ private HandshakeCompletedEvent handshakeEvent;
+
+ /**
+ * Constructor.
+ * @param url the URL
+ */
+ public HTTPURLConnection(URL url)
+ throws IOException
+ {
+ 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;
+ }
+
+ }
+
+ public void connect()
+ throws IOException
+ {
+ if (connected)
+ {
+ return;
+ }
+ String protocol = url.getProtocol();
+ boolean secure = "https".equals(protocol);
+ String host = url.getHost();
+ int port = url.getPort();
+ if (port < 0)
+ {
+ port = secure ? HTTPConnection.HTTPS_PORT :
+ HTTPConnection.HTTP_PORT;
+ }
+ String file = url.getFile();
+ String username = url.getUserInfo();
+ String password = null;
+ if (username != null)
+ {
+ int ci = username.indexOf(':');
+ if (ci != -1)
+ {
+ password = username.substring(ci + 1);
+ username = username.substring(0, ci);
+ }
+ }
+ final Credentials creds = (username == null) ? null :
+ new Credentials (username, password);
+
+ boolean retry;
+ do
+ {
+ retry = false;
+ if (connection == null)
+ {
+ connection = getConnection(host, port, secure);
+ if (secure)
+ {
+ SSLSocketFactory factory = getSSLSocketFactory();
+ HostnameVerifier verifier = getHostnameVerifier();
+ if (factory != null)
+ {
+ connection.setSSLSocketFactory(factory);
+ }
+ connection.addHandshakeCompletedListener(this);
+ // TODO verifier
+ }
+ }
+ if (proxyHostname != null)
+ {
+ if (proxyPort < 0)
+ {
+ proxyPort = secure ? HTTPConnection.HTTPS_PORT :
+ HTTPConnection.HTTP_PORT;
+ }
+ connection.setProxy(proxyHostname, proxyPort);
+ }
+ request = connection.newRequest(method, file);
+ if (!keepAlive)
+ {
+ request.setHeader("Connection", "close");
+ }
+ if (agent != null)
+ {
+ request.setHeader("User-Agent", agent);
+ }
+ request.getHeaders().putAll(requestHeaders);
+ if (requestSink != null)
+ {
+ byte[] content = requestSink.toByteArray();
+ RequestBodyWriter writer = new ByteArrayRequestBodyWriter(content);
+ request.setRequestBodyWriter(writer);
+ }
+ ByteArrayResponseBodyReader reader = new ByteArrayResponseBodyReader();
+ request.setResponseBodyReader(reader);
+ if (creds != null)
+ {
+ request.setAuthenticator(new Authenticator() {
+ public Credentials getCredentials(String realm, int attempts)
+ {
+ return (attempts < 2) ? creds : null;
+ }
+ });
+ }
+ response = request.dispatch();
+ if (response.getCodeClass() == 3 && getInstanceFollowRedirects())
+ {
+ // Follow redirect
+ String location = response.getHeader("Location");
+ if (location != null)
+ {
+ String connectionUri = connection.getURI();
+ int start = connectionUri.length();
+ if (location.startsWith(connectionUri) &&
+ location.charAt(start) == '/')
+ {
+ file = location.substring(start);
+ retry = true;
+ }
+ else if (location.startsWith("http:"))
+ {
+ connection.close();
+ connection = null;
+ secure = false;
+ start = 7;
+ int end = location.indexOf('/', start);
+ host = location.substring(start, end);
+ int ci = host.lastIndexOf(':');
+ if (ci != -1)
+ {
+ port = Integer.parseInt(host.substring (ci + 1));
+ host = host.substring(0, ci);
+ }
+ else
+ {
+ port = HTTPConnection.HTTP_PORT;
+ }
+ file = location.substring(end);
+ retry = true;
+ }
+ else if (location.startsWith("https:"))
+ {
+ connection.close();
+ connection = null;
+ secure = true;
+ start = 8;
+ int end = location.indexOf('/', start);
+ host = location.substring(start, end);
+ int ci = host.lastIndexOf(':');
+ if (ci != -1)
+ {
+ port = Integer.parseInt(host.substring (ci + 1));
+ host = host.substring(0, ci);
+ }
+ else
+ {
+ port = HTTPConnection.HTTPS_PORT;
+ }
+ file = location.substring(end);
+ retry = true;
+ }
+ else if (location.length() > 0)
+ {
+ // Malformed absolute URI, treat as file part of URI
+ if (location.charAt(0) == '/')
+ {
+ // Absolute path
+ file = location;
+ }
+ else
+ {
+ // Relative path
+ int lsi = file.lastIndexOf('/');
+ file = (lsi == -1) ? "/" : file.substring(0, lsi + 1);
+ file += location;
+ }
+ retry = true;
+ }
+ }
+ }
+ else
+ {
+ responseSink = new ByteArrayInputStream(reader.toByteArray ());
+ if (response.getCode() == 404)
+ {
+ errorSink = responseSink;
+ throw new FileNotFoundException(url.toString());
+ }
+ }
+ }
+ while (retry);
+ connected = true;
+ }
+
+ /**
+ * Returns a connection, from the pool if necessary.
+ */
+ HTTPConnection getConnection(String host, int port, boolean secure)
+ throws IOException
+ {
+ HTTPConnection connection;
+ if (keepAlive)
+ {
+ StringBuffer buf = new StringBuffer(secure ? "https://" : "http://");
+ buf.append(Thread.currentThread().hashCode());
+ buf.append('@');
+ buf.append(host);
+ buf.append(':');
+ buf.append(port);
+ String key = buf.toString();
+ synchronized (connectionPool)
+ {
+ connection = (HTTPConnection) connectionPool.get(key);
+ if (connection == null)
+ {
+ connection = new HTTPConnection(host, port, secure);
+ // Good housekeeping
+ if (connectionPool.size() == maxConnections)
+ {
+ // maxConnections must always be >= 1
+ Object lru = connectionPool.keySet().iterator().next();
+ connectionPool.remove(lru);
+ }
+ connectionPool.put(key, connection);
+ }
+ }
+ }
+ else
+ {
+ connection = new HTTPConnection(host, port, secure);
+ }
+ return connection;
+ }
+
+ public void disconnect()
+ {
+ if (connection != null)
+ {
+ try
+ {
+ connection.close();
+ }
+ catch (IOException e)
+ {
+ }
+ }
+ }
+
+ public boolean usingProxy()
+ {
+ return (proxyHostname != null);
+ }
+
+ /**
+ * Overrides the corresponding method in HttpURLConnection to permit
+ * arbitrary methods, as long as they're valid ASCII alphabetic
+ * characters. This is to permit WebDAV and other HTTP extensions to
+ * function.
+ * @param method the method
+ */
+ public void setRequestMethod(String method)
+ throws ProtocolException
+ {
+ if (connected)
+ {
+ throw new ProtocolException("Already connected");
+ }
+ // Validate
+ method = method.toUpperCase();
+ int len = method.length();
+ if (len == 0)
+ {
+ throw new ProtocolException("Empty method name");
+ }
+ for (int i = 0; i < len; i++)
+ {
+ char c = method.charAt(i);
+ if (c < 0x41 || c > 0x5a)
+ {
+ throw new ProtocolException("Illegal character '" + c +
+ "' at index " + i);
+ }
+ }
+ // OK
+ this.method = method;
+ requestMethodSetExplicitly = true;
+ }
+
+ public String getRequestProperty(String key)
+ {
+ return requestHeaders.getValue(key);
+ }
+
+ public Map getRequestProperties()
+ {
+ return requestHeaders;
+ }
+
+ public void setRequestProperty(String key, String 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);
+ }
+ }
+
+ public OutputStream getOutputStream()
+ throws IOException
+ {
+ if (connected)
+ {
+ throw new ProtocolException("Already connected");
+ }
+ if (!doOutput)
+ {
+ throw new ProtocolException("doOutput is false");
+ }
+ else if (!requestMethodSetExplicitly)
+ {
+ /*
+ * Silently change the method to POST if no method was set
+ * explicitly. This is due to broken applications depending on this
+ * behaviour (Apache XMLRPC for one).
+ */
+ method = "POST";
+ }
+ if (requestSink == null)
+ {
+ requestSink = new ByteArrayOutputStream();
+ }
+ return requestSink;
+ }
+
+ // -- Response --
+
+ public InputStream getInputStream()
+ throws IOException
+ {
+ if (!connected)
+ {
+ connect();
+ }
+ if (!doInput)
+ {
+ throw new ProtocolException("doInput is false");
+ }
+ return responseSink;
+ }
+
+ public InputStream getErrorStream()
+ {
+ return errorSink;
+ }
+
+ public Map getHeaderFields()
+ {
+ if (!connected)
+ {
+ try
+ {
+ connect();
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+ Map headers = response.getHeaders();
+ Map ret = new LinkedHashMap();
+ ret.put("", 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 ret;
+ }
+
+ String getStatusLine(Response response)
+ {
+ return "HTTP/" + response.getMajorVersion() +
+ "." + response.getMinorVersion() +
+ " " + response.getCode() +
+ " " + response.getMessage();
+ }
+
+ public String getHeaderField(int index)
+ {
+ if (!connected)
+ {
+ try
+ {
+ connect();
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+ if (index == 0)
+ {
+ 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)
+ {
+ if (!connected)
+ {
+ try
+ {
+ connect();
+ }
+ catch (IOException e)
+ {
+ 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)
+ {
+ if (!connected)
+ {
+ try
+ {
+ connect();
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+ return (String) response.getHeader(name);
+ }
+
+ public long getHeaderFieldDate(String name, long def)
+ {
+ if (!connected)
+ {
+ try
+ {
+ connect();
+ }
+ catch (IOException e)
+ {
+ return def;
+ }
+ }
+ Date date = response.getDateHeader(name);
+ return (date == null) ? def : date.getTime();
+ }
+
+ public String getContentType()
+ {
+ return getHeaderField("Content-Type");
+ }
+
+ public int getResponseCode()
+ throws IOException
+ {
+ if (!connected)
+ {
+ connect();
+ }
+ return response.getCode();
+ }
+
+ public String getResponseMessage()
+ throws IOException
+ {
+ if (!connected)
+ {
+ connect();
+ }
+ return response.getMessage();
+ }
+
+ // -- HTTPS specific --
+
+ public String getCipherSuite()
+ {
+ if (!connected)
+ {
+ throw new IllegalStateException("not connected");
+ }
+ return handshakeEvent.getCipherSuite();
+ }
+
+ public Certificate[] getLocalCertificates()
+ {
+ if (!connected)
+ {
+ throw new IllegalStateException("not connected");
+ }
+ return handshakeEvent.getLocalCertificates();
+ }
+
+ public Certificate[] getServerCertificates()
+ throws SSLPeerUnverifiedException
+ {
+ if (!connected)
+ {
+ throw new IllegalStateException("not connected");
+ }
+ return handshakeEvent.getPeerCertificates();
+ }
+
+ // HandshakeCompletedListener
+
+ public void handshakeCompleted(HandshakeCompletedEvent event)
+ {
+ handshakeEvent = event;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/Handler.java b/libjava/classpath/gnu/java/net/protocol/http/Handler.java
new file mode 100644
index 00000000000..64054251331
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/Handler.java
@@ -0,0 +1,73 @@
+/* Handler.java --
+ Copyright (C) 2004 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 java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+
+/**
+ * An HTTP URL stream handler.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class Handler
+ extends URLStreamHandler
+{
+
+ /**
+ * Returns the default HTTP port (80).
+ */
+ protected int getDefaultPort()
+ {
+ return HTTPConnection.HTTP_PORT;
+ }
+
+ /**
+ * Returns an HTTPURLConnection for the given URL.
+ */
+ public URLConnection openConnection(URL url)
+ throws IOException
+ {
+ return new HTTPURLConnection(url);
+ }
+
+}
+
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 00000000000..847ebefc1f6
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/Headers.java
@@ -0,0 +1,369 @@
+/* Headers.java --
+ Copyright (C) 2004 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.net.LineInputStream;
+
+import java.io.IOException;
+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 (dog@gnu.org)
+ */
+public class Headers
+ implements Map
+{
+
+ static final DateFormat dateFormat = new HTTPDateFormat();
+
+ static class Header
+ {
+
+ final String name;
+
+ Header(String name)
+ {
+ if (name == null || name.length() == 0)
+ {
+ throw new IllegalArgumentException(name);
+ }
+ this.name = name;
+ }
+
+ 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();
+ }
+
+ }
+
+ private LinkedHashMap headers;
+
+ public Headers()
+ {
+ headers = new LinkedHashMap();
+ }
+
+ public int size()
+ {
+ return headers.size();
+ }
+
+ public boolean isEmpty()
+ {
+ return headers.isEmpty();
+ }
+
+ public boolean containsKey(Object key)
+ {
+ return headers.containsKey(new Header((String) key));
+ }
+
+ public boolean containsValue(Object value)
+ {
+ return headers.containsValue(value);
+ }
+
+ public Object get(Object key)
+ {
+ return headers.get(new Header((String) key));
+ }
+
+ /**
+ * Returns the value of the specified header as a string.
+ */
+ public String getValue(String header)
+ {
+ return (String) headers.get(new Header(header));
+ }
+
+ /**
+ * Returns the value of the specified header as an integer,
+ * or -1 if the header is not present or not an integer.
+ */
+ public int getIntValue(String header)
+ {
+ String val = getValue(header);
+ if (val == null)
+ {
+ return -1;
+ }
+ try
+ {
+ return Integer.parseInt(val);
+ }
+ catch (NumberFormatException e)
+ {
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the value of the specified header as a date,
+ * or <code>null</code> if the header is not present or not a date.
+ */
+ public Date getDateValue(String header)
+ {
+ String val = getValue(header);
+ if (val == null)
+ {
+ return null;
+ }
+ try
+ {
+ return dateFormat.parse(val);
+ }
+ catch (ParseException e)
+ {
+ return null;
+ }
+ }
+
+ public Object put(Object key, Object value)
+ {
+ return headers.put(new Header((String) key), value);
+ }
+
+ public Object remove(Object key)
+ {
+ return headers.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);
+ headers.put(new Header(key), value);
+ }
+ }
+
+ public void clear()
+ {
+ headers.clear();
+ }
+
+ public Set keySet()
+ {
+ Set keys = headers.keySet();
+ Set ret = new LinkedHashSet();
+ for (Iterator i = keys.iterator(); i.hasNext(); )
+ {
+ ret.add(((Header) i.next()).name);
+ }
+ return ret;
+ }
+
+ public Collection values()
+ {
+ return headers.values();
+ }
+
+ public Set entrySet()
+ {
+ Set entries = headers.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;
+ }
+
+ public boolean equals(Object other)
+ {
+ return headers.equals(other);
+ }
+
+ public int hashCode()
+ {
+ return headers.hashCode();
+ }
+
+ /**
+ * Parse the specified input stream, adding headers to this collection.
+ */
+ public void parse(InputStream in)
+ throws IOException
+ {
+ LineInputStream lin = (in instanceof LineInputStream) ?
+ (LineInputStream) in : new LineInputStream(in);
+
+ String name = null;
+ StringBuffer value = new StringBuffer();
+ 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));
+ }
+ }
+ }
+
+ private void addValue(String name, String value)
+ {
+ Header key = new Header(name);
+ String old = (String) headers.get(key);
+ if (old == null)
+ {
+ headers.put(key, value);
+ }
+ else
+ {
+ headers.put(key, old + ", " + value);
+ }
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/Request.java b/libjava/classpath/gnu/java/net/protocol/http/Request.java
new file mode 100644
index 00000000000..21205e6bba8
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/Request.java
@@ -0,0 +1,915 @@
+/* Request.java --
+ Copyright (C) 2004 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.net.BASE64;
+import gnu.java.net.LineInputStream;
+import gnu.java.net.protocol.http.event.RequestEvent;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ProtocolException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.InflaterInputStream;
+
+/**
+ * A single HTTP request.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class Request
+{
+
+ /**
+ * The connection context in which this request is invoked.
+ */
+ protected final HTTPConnection connection;
+
+ /**
+ * The HTTP method to invoke.
+ */
+ protected final String method;
+
+ /**
+ * The path identifying the resource.
+ * This string must conform to the abs_path definition given in RFC2396,
+ * with an optional "?query" part, and must be URI-escaped by the caller.
+ */
+ protected final String path;
+
+ /**
+ * The headers in this request.
+ */
+ protected final Headers requestHeaders;
+
+ /**
+ * The request body provider.
+ */
+ protected RequestBodyWriter requestBodyWriter;
+
+ /**
+ * Request body negotiation threshold for 100-continue expectations.
+ */
+ protected int requestBodyNegotiationThreshold;
+
+ /**
+ * The response body reader.
+ */
+ protected ResponseBodyReader responseBodyReader;
+
+ /**
+ * Map of response header handlers.
+ */
+ protected Map responseHeaderHandlers;
+
+ /**
+ * The authenticator.
+ */
+ protected Authenticator authenticator;
+
+ /**
+ * Whether this request has been dispatched yet.
+ */
+ private boolean dispatched;
+
+ /**
+ * Constructor for a new request.
+ * @param connection the connection context
+ * @param method the HTTP method
+ * @param path the resource path including query part
+ */
+ protected Request(HTTPConnection connection, String method,
+ String path)
+ {
+ this.connection = connection;
+ this.method = method;
+ this.path = path;
+ requestHeaders = new Headers();
+ responseHeaderHandlers = new HashMap();
+ requestBodyNegotiationThreshold = 4096;
+ }
+
+ /**
+ * Returns the connection associated with this request.
+ * @see #connection
+ */
+ public HTTPConnection getConnection()
+ {
+ return connection;
+ }
+
+ /**
+ * Returns the HTTP method to invoke.
+ * @see #method
+ */
+ public String getMethod()
+ {
+ return method;
+ }
+
+ /**
+ * Returns the resource path.
+ * @see #path
+ */
+ public String getPath()
+ {
+ return path;
+ }
+
+ /**
+ * Returns the full request-URI represented by this request, as specified
+ * by HTTP/1.1.
+ */
+ public String getRequestURI()
+ {
+ return connection.getURI() + path;
+ }
+
+ /**
+ * Returns the headers in this request.
+ */
+ public Headers getHeaders()
+ {
+ return requestHeaders;
+ }
+
+ /**
+ * Returns the value of the specified header in this request.
+ * @param name the header name
+ */
+ public String getHeader(String name)
+ {
+ return requestHeaders.getValue(name);
+ }
+
+ /**
+ * Returns the value of the specified header in this request as an integer.
+ * @param name the header name
+ */
+ public int getIntHeader(String name)
+ {
+ return requestHeaders.getIntValue(name);
+ }
+
+ /**
+ * Returns the value of the specified header in this request as a date.
+ * @param name the header name
+ */
+ public Date getDateHeader(String name)
+ {
+ return requestHeaders.getDateValue(name);
+ }
+
+ /**
+ * Sets the specified header in this request.
+ * @param name the header name
+ * @param value the header value
+ */
+ public void setHeader(String name, String value)
+ {
+ requestHeaders.put(name, value);
+ }
+
+ /**
+ * Convenience method to set the entire request body.
+ * @param requestBody the request body content
+ */
+ public void setRequestBody(byte[] requestBody)
+ {
+ setRequestBodyWriter(new ByteArrayRequestBodyWriter(requestBody));
+ }
+
+ /**
+ * Sets the request body provider.
+ * @param requestBodyWriter the handler used to obtain the request body
+ */
+ public void setRequestBodyWriter(RequestBodyWriter requestBodyWriter)
+ {
+ this.requestBodyWriter = requestBodyWriter;
+ }
+
+ /**
+ * Sets the response body reader.
+ * @param responseBodyReader the handler to receive notifications of
+ * response body content
+ */
+ public void setResponseBodyReader(ResponseBodyReader responseBodyReader)
+ {
+ this.responseBodyReader = responseBodyReader;
+ }
+
+ /**
+ * Sets a callback handler to be invoked for the specified header name.
+ * @param name the header name
+ * @param handler the handler to receive the value for the header
+ */
+ public void setResponseHeaderHandler(String name,
+ ResponseHeaderHandler handler)
+ {
+ responseHeaderHandlers.put(name, handler);
+ }
+
+ /**
+ * Sets an authenticator that can be used to handle authentication
+ * automatically.
+ * @param authenticator the authenticator
+ */
+ public void setAuthenticator(Authenticator authenticator)
+ {
+ 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
+ * time results in a protocol exception.
+ * @exception IOException if an I/O error occurred
+ * @return an HTTP response object representing the result of the operation
+ */
+ public Response dispatch()
+ throws IOException
+ {
+ if (dispatched)
+ {
+ throw new ProtocolException("request already dispatched");
+ }
+ final String CRLF = "\r\n";
+ final String HEADER_SEP = ": ";
+ final String US_ASCII = "US-ASCII";
+ final String version = connection.getVersion();
+ Response response;
+ int contentLength = -1;
+ boolean retry = false;
+ int attempts = 0;
+ boolean expectingContinue = false;
+ if (requestBodyWriter != null)
+ {
+ contentLength = requestBodyWriter.getContentLength();
+ if (contentLength > requestBodyNegotiationThreshold)
+ {
+ expectingContinue = true;
+ setHeader("Expect", "100-continue");
+ }
+ else
+ {
+ setHeader("Content-Length", Integer.toString(contentLength));
+ }
+ }
+
+ try
+ {
+ // Loop while authentication fails or continue
+ do
+ {
+ retry = false;
+ // Send request
+ connection.fireRequestEvent(RequestEvent.REQUEST_SENDING, this);
+
+ // Get socket output and input streams
+ OutputStream out = connection.getOutputStream();
+ LineInputStream in =
+ new LineInputStream(connection.getInputStream());
+ // Request line
+ String requestUri = path;
+ if (connection.isUsingProxy() &&
+ !"*".equals(requestUri) &&
+ !"CONNECT".equals(method))
+ {
+ requestUri = getRequestURI();
+ }
+ 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));
+ // Request body
+ if (requestBodyWriter != null && !expectingContinue)
+ {
+ byte[] buffer = new byte[4096];
+ int len;
+ int count = 0;
+
+ requestBodyWriter.reset();
+ do
+ {
+ len = requestBodyWriter.write(buffer);
+ if (len > 0)
+ {
+ out.write(buffer, 0, len);
+ }
+ count += len;
+ }
+ while (len > -1 && count < contentLength);
+ out.write(CRLF.getBytes(US_ASCII));
+ }
+ out.flush();
+ // Sent event
+ connection.fireRequestEvent(RequestEvent.REQUEST_SENT, this);
+ // Get response
+ response = readResponse(in);
+ int sc = response.getCode();
+ if (sc == 401 && authenticator != null)
+ {
+ if (authenticate(response, attempts++))
+ {
+ retry = true;
+ }
+ }
+ else if (sc == 100 && expectingContinue)
+ {
+ requestHeaders.remove("Expect");
+ setHeader("Content-Length", Integer.toString(contentLength));
+ expectingContinue = false;
+ retry = true;
+ }
+ }
+ while (retry);
+ }
+ catch (IOException e)
+ {
+ connection.close();
+ throw e;
+ }
+ return response;
+ }
+
+ Response readResponse(LineInputStream in)
+ throws IOException
+ {
+ String line;
+ int len;
+
+ // Read response status line
+ line = in.readLine();
+ if (line == null)
+ {
+ throw new ProtocolException("Peer closed connection");
+ }
+ if (!line.startsWith("HTTP/"))
+ {
+ throw new ProtocolException(line);
+ }
+ len = line.length();
+ int start = 5, end = 6;
+ while (line.charAt(end) != '.')
+ {
+ end++;
+ }
+ int majorVersion = Integer.parseInt(line.substring(start, end));
+ start = end + 1;
+ end = start + 1;
+ while (line.charAt(end) != ' ')
+ {
+ end++;
+ }
+ int minorVersion = Integer.parseInt(line.substring(start, end));
+ start = end + 1;
+ end = start + 3;
+ int code = Integer.parseInt(line.substring(start, end));
+ String message = line.substring(end + 1, len - 1);
+ // Read response headers
+ Headers responseHeaders = new Headers();
+ responseHeaders.parse(in);
+ notifyHeaderHandlers(responseHeaders);
+ // Construct response
+ int codeClass = code / 100;
+ Response ret = new Response(majorVersion, minorVersion, code,
+ codeClass, message, responseHeaders);
+ switch (code)
+ {
+ case 204:
+ case 205:
+ case 304:
+ break;
+ default:
+ // Does response body reader want body?
+ boolean notify = (responseBodyReader != null);
+ if (notify)
+ {
+ if (!responseBodyReader.accept(this, ret))
+ {
+ notify = false;
+ }
+ }
+ readResponseBody(ret, in, notify);
+ }
+ return ret;
+ }
+
+ 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);
+ }
+ }
+ }
+
+ void readResponseBody(Response response, InputStream in,
+ boolean notify)
+ throws IOException
+ {
+ byte[] buffer = new byte[4096];
+ int contentLength = -1;
+ Headers trailer = null;
+
+ String transferCoding = response.getHeader("Transfer-Encoding");
+ if ("chunked".equalsIgnoreCase(transferCoding))
+ {
+ trailer = new Headers();
+ in = new ChunkedInputStream(in, trailer);
+ }
+ else
+ {
+ contentLength = response.getIntHeader("Content-Length");
+ }
+ String contentCoding = response.getHeader("Content-Encoding");
+ if (contentCoding != null && !"identity".equals(contentCoding))
+ {
+ if ("gzip".equals(contentCoding))
+ {
+ in = new GZIPInputStream(in);
+ }
+ else if ("deflate".equals(contentCoding))
+ {
+ in = new InflaterInputStream(in);
+ }
+ else
+ {
+ throw new ProtocolException("Unsupported Content-Encoding: " +
+ contentCoding);
+ }
+ }
+
+ // Persistent connections are the default in HTTP/1.1
+ boolean doClose = "close".equalsIgnoreCase(getHeader("Connection")) ||
+ "close".equalsIgnoreCase(response.getHeader("Connection")) ||
+ (connection.majorVersion == 1 && connection.minorVersion == 0) ||
+ (response.majorVersion == 1 && response.minorVersion == 0);
+
+ int count = contentLength;
+ int len = (count > -1) ? count : buffer.length;
+ len = (len > buffer.length) ? buffer.length : len;
+ while (len > -1)
+ {
+ len = in.read(buffer, 0, len);
+ if (len < 0)
+ {
+ // EOF
+ connection.closeConnection();
+ break;
+ }
+ if (notify)
+ {
+ responseBodyReader.read(buffer, 0, len);
+ }
+ if (count > -1)
+ {
+ count -= len;
+ if (count < 1)
+ {
+ if (doClose)
+ {
+ connection.closeConnection();
+ }
+ break;
+ }
+ }
+ }
+ if (notify)
+ {
+ responseBodyReader.close();
+ }
+ if (trailer != null)
+ {
+ response.getHeaders().putAll(trailer);
+ notifyHeaderHandlers(trailer);
+ }
+ }
+
+ boolean authenticate(Response response, int attempts)
+ throws IOException
+ {
+ String challenge = response.getHeader("WWW-Authenticate");
+ if (challenge == null)
+ {
+ challenge = response.getHeader("Proxy-Authenticate");
+ }
+ int si = challenge.indexOf(' ');
+ String scheme = (si == -1) ? challenge : challenge.substring(0, si);
+ if ("Basic".equalsIgnoreCase(scheme))
+ {
+ Properties params = parseAuthParams(challenge.substring(si + 1));
+ String realm = params.getProperty("realm");
+ Credentials creds = authenticator.getCredentials(realm, attempts);
+ String userPass = creds.getUsername() + ':' + creds.getPassword();
+ byte[] b_userPass = userPass.getBytes("US-ASCII");
+ byte[] b_encoded = BASE64.encode(b_userPass);
+ String authorization =
+ scheme + " " + new String(b_encoded, "US-ASCII");
+ setHeader("Authorization", authorization);
+ return true;
+ }
+ else if ("Digest".equalsIgnoreCase(scheme))
+ {
+ Properties params = parseAuthParams(challenge.substring(si + 1));
+ String realm = params.getProperty("realm");
+ String nonce = params.getProperty("nonce");
+ String qop = params.getProperty("qop");
+ String algorithm = params.getProperty("algorithm");
+ String digestUri = getRequestURI();
+ Credentials creds = authenticator.getCredentials(realm, attempts);
+ String username = creds.getUsername();
+ String password = creds.getPassword();
+ connection.incrementNonce(nonce);
+ try
+ {
+ MessageDigest md5 = MessageDigest.getInstance("MD5");
+ final byte[] COLON = { 0x3a };
+
+ // Calculate H(A1)
+ md5.reset();
+ md5.update(username.getBytes("US-ASCII"));
+ md5.update(COLON);
+ md5.update(realm.getBytes("US-ASCII"));
+ md5.update(COLON);
+ md5.update(password.getBytes("US-ASCII"));
+ byte[] ha1 = md5.digest();
+ if ("md5-sess".equals(algorithm))
+ {
+ byte[] cnonce = generateNonce();
+ md5.reset();
+ md5.update(ha1);
+ md5.update(COLON);
+ md5.update(nonce.getBytes("US-ASCII"));
+ md5.update(COLON);
+ md5.update(cnonce);
+ ha1 = md5.digest();
+ }
+ String ha1Hex = toHexString(ha1);
+
+ // Calculate H(A2)
+ md5.reset();
+ md5.update(method.getBytes("US-ASCII"));
+ md5.update(COLON);
+ md5.update(digestUri.getBytes("US-ASCII"));
+ if ("auth-int".equals(qop))
+ {
+ byte[] hEntity = null; // TODO hash of entity body
+ md5.update(COLON);
+ md5.update(hEntity);
+ }
+ byte[] ha2 = md5.digest();
+ String ha2Hex = toHexString(ha2);
+
+ // Calculate response
+ md5.reset();
+ md5.update(ha1Hex.getBytes("US-ASCII"));
+ md5.update(COLON);
+ md5.update(nonce.getBytes("US-ASCII"));
+ if ("auth".equals(qop) || "auth-int".equals(qop))
+ {
+ String nc = getNonceCount(nonce);
+ byte[] cnonce = generateNonce();
+ md5.update(COLON);
+ md5.update(nc.getBytes("US-ASCII"));
+ md5.update(COLON);
+ md5.update(cnonce);
+ md5.update(COLON);
+ md5.update(qop.getBytes("US-ASCII"));
+ }
+ md5.update(COLON);
+ md5.update(ha2Hex.getBytes("US-ASCII"));
+ String digestResponse = toHexString(md5.digest());
+
+ String authorization = scheme +
+ " username=\"" + username + "\"" +
+ " realm=\"" + realm + "\"" +
+ " nonce=\"" + nonce + "\"" +
+ " uri=\"" + digestUri + "\"" +
+ " response=\"" + digestResponse + "\"";
+ setHeader("Authorization", authorization);
+ return true;
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ return false;
+ }
+ }
+ // Scheme not recognised
+ return false;
+ }
+
+ Properties parseAuthParams(String text)
+ {
+ int len = text.length();
+ String key = null;
+ StringBuffer buf = new StringBuffer();
+ Properties ret = new Properties();
+ boolean inQuote = false;
+ for (int i = 0; i < len; i++)
+ {
+ char c = text.charAt(i);
+ if (c == '"')
+ {
+ inQuote = !inQuote;
+ }
+ else if (c == '=' && key == null)
+ {
+ key = buf.toString().trim();
+ buf.setLength(0);
+ }
+ else if (c == ' ' && !inQuote)
+ {
+ String value = unquote(buf.toString().trim());
+ ret.put(key, value);
+ key = null;
+ buf.setLength(0);
+ }
+ else if (c != ',' || (i <(len - 1) && text.charAt(i + 1) != ' '))
+ {
+ buf.append(c);
+ }
+ }
+ if (key != null)
+ {
+ String value = unquote(buf.toString().trim());
+ ret.put(key, value);
+ }
+ return ret;
+ }
+
+ String unquote(String text)
+ {
+ int len = text.length();
+ if (len > 0 && text.charAt(0) == '"' && text.charAt(len - 1) == '"')
+ {
+ return text.substring(1, len - 1);
+ }
+ return text;
+ }
+
+ /**
+ * Returns the number of times the specified nonce value has been seen.
+ * This always returns an 8-byte 0-padded hexadecimal string.
+ */
+ String getNonceCount(String nonce)
+ {
+ int nc = connection.getNonceCount(nonce);
+ String hex = Integer.toHexString(nc);
+ StringBuffer buf = new StringBuffer();
+ for (int i = 8 - hex.length(); i > 0; i--)
+ {
+ buf.append('0');
+ }
+ buf.append(hex);
+ return buf.toString();
+ }
+
+ /**
+ * Client nonce value.
+ */
+ byte[] nonce;
+
+ /**
+ * Generates a new client nonce value.
+ */
+ byte[] generateNonce()
+ throws IOException, NoSuchAlgorithmException
+ {
+ if (nonce == null)
+ {
+ long time = System.currentTimeMillis();
+ MessageDigest md5 = MessageDigest.getInstance("MD5");
+ md5.update(Long.toString(time).getBytes("US-ASCII"));
+ nonce = md5.digest();
+ }
+ return nonce;
+ }
+
+ String toHexString(byte[] bytes)
+ {
+ char[] ret = new char[bytes.length * 2];
+ for (int i = 0, j = 0; i < bytes.length; i++)
+ {
+ int c =(int) bytes[i];
+ if (c < 0)
+ {
+ c += 0x100;
+ }
+ ret[j++] = Character.forDigit(c / 0x10, 0x10);
+ ret[j++] = Character.forDigit(c % 0x10, 0x10);
+ }
+ return new String(ret);
+ }
+
+ /**
+ * Parse the specified cookie list and notify the cookie manager.
+ */
+ void handleSetCookie(String text)
+ {
+ CookieManager cookieManager = connection.getCookieManager();
+ if (cookieManager == null)
+ {
+ return;
+ }
+ String name = null;
+ String value = null;
+ String comment = null;
+ String domain = connection.getHostName();
+ String path = this.path;
+ int lsi = path.lastIndexOf('/');
+ if (lsi != -1)
+ {
+ path = path.substring(0, lsi);
+ }
+ boolean secure = false;
+ Date expires = null;
+
+ int len = text.length();
+ String attr = null;
+ StringBuffer buf = new StringBuffer();
+ boolean inQuote = false;
+ for (int i = 0; i <= len; i++)
+ {
+ char c =(i == len) ? '\u0000' : text.charAt(i);
+ if (c == '"')
+ {
+ inQuote = !inQuote;
+ }
+ else if (!inQuote)
+ {
+ if (c == '=' && attr == null)
+ {
+ attr = buf.toString().trim();
+ buf.setLength(0);
+ }
+ else if (c == ';' || i == len || c == ',')
+ {
+ String val = unquote(buf.toString().trim());
+ if (name == null)
+ {
+ name = attr;
+ value = val;
+ }
+ else if ("Comment".equalsIgnoreCase(attr))
+ {
+ comment = val;
+ }
+ else if ("Domain".equalsIgnoreCase(attr))
+ {
+ domain = val;
+ }
+ else if ("Path".equalsIgnoreCase(attr))
+ {
+ path = val;
+ }
+ else if ("Secure".equalsIgnoreCase(val))
+ {
+ secure = true;
+ }
+ else if ("Max-Age".equalsIgnoreCase(attr))
+ {
+ int delta = Integer.parseInt(val);
+ Calendar cal = Calendar.getInstance();
+ cal.setTimeInMillis(System.currentTimeMillis());
+ cal.add(Calendar.SECOND, delta);
+ expires = cal.getTime();
+ }
+ else if ("Expires".equalsIgnoreCase(attr))
+ {
+ DateFormat dateFormat = new HTTPDateFormat();
+ try
+ {
+ expires = dateFormat.parse(val);
+ }
+ catch (ParseException e)
+ {
+ // if this isn't a valid date, it may be that
+ // the value was returned unquoted; in that case, we
+ // want to continue buffering the value
+ buf.append(c);
+ continue;
+ }
+ }
+ attr = null;
+ buf.setLength(0);
+ // case EOL
+ if (i == len || c == ',')
+ {
+ Cookie cookie = new Cookie(name, value, comment, domain,
+ path, secure, expires);
+ cookieManager.setCookie(cookie);
+ }
+ if (c == ',')
+ {
+ // Reset cookie fields
+ name = null;
+ value = null;
+ comment = null;
+ domain = connection.getHostName();
+ path = this.path;
+ if (lsi != -1)
+ {
+ path = path.substring(0, lsi);
+ }
+ secure = false;
+ expires = null;
+ }
+ }
+ else
+ {
+ buf.append(c);
+ }
+ }
+ else
+ {
+ buf.append(c);
+ }
+ }
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/RequestBodyWriter.java b/libjava/classpath/gnu/java/net/protocol/http/RequestBodyWriter.java
new file mode 100644
index 00000000000..05d98ebb81a
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/RequestBodyWriter.java
@@ -0,0 +1,69 @@
+/* RequestBodyWriter.java --
+ Copyright (C) 2004 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;
+
+/**
+ * Callback interface for writing request body content.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public interface RequestBodyWriter
+{
+
+ /**
+ * Returns the total number of bytes that will be written in a single pass
+ * by this writer.
+ */
+ int getContentLength();
+
+ /**
+ * Initialises the writer.
+ * This will be called before each pass.
+ */
+ void reset();
+
+ /**
+ * Writes body content to the supplied buffer.
+ * @param buffer the content buffer
+ * @return the number of bytes written
+ */
+ int write(byte[] buffer);
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/Response.java b/libjava/classpath/gnu/java/net/protocol/http/Response.java
new file mode 100644
index 00000000000..29dc28b17d3
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/Response.java
@@ -0,0 +1,185 @@
+/* Response.java --
+ Copyright (C) 2004 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 java.util.Date;
+
+/**
+ * An HTTP response.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class Response
+{
+
+ /**
+ * The HTTP major version of the server issuing the response.
+ */
+ protected final int majorVersion;
+
+ /**
+ * The HTTP minor version of the server issuing the response.
+ */
+ protected final int minorVersion;
+
+ /**
+ * The HTTP status code of the response.
+ */
+ protected final int code;
+
+ /**
+ * The class of the response. This is the most significant digit of the
+ * status code.
+ * <dl>
+ * <dt><code>1xx</code></dt> <dd>Informational response</dd>
+ * <dt><code>2xx</code></dt> <dd>Success</dd>
+ * <dt><code>3xx</code></dt> <dd>Redirection</dd>
+ * <dt><code>4xx</code></dt> <dd>Client error</dd>
+ * <dt><code>5xx</code></dt> <dd>Server error</dd>
+ * </dl>
+ */
+ protected final int codeClass;
+
+ /**
+ * Human-readable text of the response.
+ */
+ protected final String message;
+
+ /**
+ * The response headers.
+ */
+ protected final Headers headers;
+
+ /**
+ * Constructs a new response with the specified parameters.
+ */
+ protected Response(int majorVersion, int minorVersion, int code,
+ int codeClass, String message,
+ Headers headers)
+ {
+ this.majorVersion = majorVersion;
+ this.minorVersion = minorVersion;
+ this.code = code;
+ this.codeClass = codeClass;
+ this.message = message;
+ this.headers = headers;
+ }
+
+ /**
+ * Returns the HTTP major version of the server issuing the response.
+ * @see #majorVersion
+ */
+ public int getMajorVersion()
+ {
+ return majorVersion;
+ }
+
+ /**
+ * Returns the HTTP minor version of the server issuing the response.
+ * @see #minorVersion
+ */
+ public int getMinorVersion()
+ {
+ return minorVersion;
+ }
+
+ /**
+ * Returns the HTTP status code of the response.
+ * @see #code
+ */
+ public int getCode()
+ {
+ return code;
+ }
+
+ /**
+ * Returns the class of the response.
+ * @see #codeClass
+ */
+ public int getCodeClass()
+ {
+ return codeClass;
+ }
+
+ /**
+ * Returns the human-readable text of the response.
+ * @see #message
+ */
+ public String getMessage()
+ {
+ return message;
+ }
+
+ /**
+ * Returns the headers in the response.
+ */
+ public Headers getHeaders()
+ {
+ return headers;
+ }
+
+ /**
+ * Returns the header value for the specified name.
+ * @param name the header name
+ */
+ public String getHeader(String name)
+ {
+ return headers.getValue(name);
+ }
+
+ /**
+ * Returns the header value for the specified name as an integer.
+ * @param name the header name
+ */
+ public int getIntHeader(String name)
+ {
+ return headers.getIntValue(name);
+ }
+
+ /**
+ * Returns the header value for the specified name as a date.
+ * @param name the header name
+ */
+ public Date getDateHeader(String name)
+ {
+ return headers.getDateValue(name);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/ResponseBodyReader.java b/libjava/classpath/gnu/java/net/protocol/http/ResponseBodyReader.java
new file mode 100644
index 00000000000..49e1b376f0f
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/ResponseBodyReader.java
@@ -0,0 +1,70 @@
+/* ResponseBodyReader.java --
+ Copyright (C) 2004 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;
+
+/**
+ * Callback interface for receiving notification of response body content.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public interface ResponseBodyReader
+{
+
+ /**
+ * Indicate whether this reader is interested in the specified response.
+ * If it returns false, it will not receive body content notifications for
+ * that response.
+ */
+ boolean accept(Request request, Response response);
+
+ /**
+ * Receive notification of body content.
+ * @param buffer the content buffer
+ * @param offset the offset within the buffer that content starts
+ * @param length the length of the content
+ */
+ void read(byte[] buffer, int offset, int length);
+
+ /**
+ * Notifies the reader that the end of the content was reached.
+ */
+ void close();
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/ResponseHeaderHandler.java b/libjava/classpath/gnu/java/net/protocol/http/ResponseHeaderHandler.java
new file mode 100644
index 00000000000..8e4e6492acf
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/ResponseHeaderHandler.java
@@ -0,0 +1,57 @@
+/* ResponseHeaderHandler.java --
+ Copyright (C) 2004 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;
+
+/**
+ * Callback interface for objects that wish to be notified of response
+ * header values.
+ * @see Request#setHeaderHandler(String)
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public interface ResponseHeaderHandler
+{
+
+ /**
+ * Sets the value for the header associated with this handler.
+ */
+ void setValue(String value);
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/SimpleCookieManager.java b/libjava/classpath/gnu/java/net/protocol/http/SimpleCookieManager.java
new file mode 100644
index 00000000000..8947471885c
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/SimpleCookieManager.java
@@ -0,0 +1,140 @@
+/* CookieManager.java --
+ Copyright (C) 2004 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 java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A simple non-persistent cookie manager. This class can be extended to
+ * provide cookie persistence.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class SimpleCookieManager
+ implements CookieManager
+{
+
+ /**
+ * The cookie cache.
+ * This is a dictionary mapping domains to maps of cookies by name.
+ */
+ protected Map cookies;
+
+ /**
+ * Constructor.
+ */
+ public SimpleCookieManager()
+ {
+ cookies = new HashMap();
+ }
+
+ public void setCookie(Cookie cookie)
+ {
+ String domain = cookie.getDomain();
+ Map map =(Map) cookies.get(domain);
+ if (map == null)
+ {
+ map = new HashMap();
+ cookies.put(domain, map);
+ }
+ String name = cookie.getName();
+ map.put(name, cookie); // will replace a cookie of the same name
+ }
+
+ public Cookie[] getCookies(String host, boolean secure, String path)
+ {
+ List matches = new ArrayList();
+ Date now = new Date();
+ if (Character.isLetter(host.charAt(0)))
+ {
+ int di = host.indexOf('.');
+ while (di != -1)
+ {
+ addCookies(matches, host, secure, path, now);
+ host = host.substring(di);
+ di = host.indexOf('.', 1);
+ }
+ }
+ addCookies(matches, host, secure, path, now);
+ Cookie[] ret = new Cookie[matches.size()];
+ matches.toArray(ret);
+ return ret;
+ }
+
+ private void addCookies(List matches, String domain, boolean secure,
+ String path, Date now)
+ {
+ Map map = (Map) cookies.get(domain);
+ if (map != null)
+ {
+ List expired = new ArrayList();
+ for (Iterator i = map.entrySet().iterator(); i.hasNext(); )
+ {
+ Map.Entry entry = (Map.Entry) i.next();
+ Cookie cookie = (Cookie) entry.getValue();
+ Date expires = cookie.getExpiryDate();
+ if (expires != null && expires.before(now))
+ {
+ expired.add(entry.getKey());
+ continue;
+ }
+ if (secure && !cookie.isSecure())
+ {
+ continue;
+ }
+ if (path.startsWith(cookie.getPath()))
+ {
+ matches.add(cookie);
+ }
+ }
+ // Good housekeeping
+ for (Iterator i = expired.iterator(); i.hasNext(); )
+ {
+ map.remove(i.next());
+ }
+ }
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/event/ConnectionEvent.java b/libjava/classpath/gnu/java/net/protocol/http/event/ConnectionEvent.java
new file mode 100644
index 00000000000..3f6f5454e73
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/event/ConnectionEvent.java
@@ -0,0 +1,81 @@
+/* ConnectionEvent.java --
+ Copyright (C) 2004 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.event;
+
+import java.util.EventObject;
+
+/**
+ * A connection event.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class ConnectionEvent
+ extends EventObject
+{
+
+ /**
+ * The connection closed event type.
+ */
+ public static final int CONNECTION_CLOSED = 0;
+
+ /**
+ * The type of this event.
+ */
+ protected int type;
+
+ /**
+ * Constructs a connection event with the specified source and type.
+ */
+ public ConnectionEvent(Object source, int type)
+ {
+ super(source);
+ this.type = type;
+ }
+
+ /**
+ * Returns the type of this event.
+ * @see #type
+ */
+ public int getType()
+ {
+ return type;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/event/ConnectionListener.java b/libjava/classpath/gnu/java/net/protocol/http/event/ConnectionListener.java
new file mode 100644
index 00000000000..073e89d4407
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/event/ConnectionListener.java
@@ -0,0 +1,58 @@
+/* ConnectionListener.java --
+ Copyright (C) 2004 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.event;
+
+import java.util.EventListener;
+
+/**
+ * A connection listener.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public interface ConnectionListener
+ extends EventListener
+{
+
+ /**
+ * Callback invoked when the associated connection is closed.
+ */
+ void connectionClosed(ConnectionEvent event);
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/event/RequestEvent.java b/libjava/classpath/gnu/java/net/protocol/http/event/RequestEvent.java
new file mode 100644
index 00000000000..281c621f33f
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/event/RequestEvent.java
@@ -0,0 +1,107 @@
+/* RequestEvent.java --
+ Copyright (C) 2004 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.event;
+
+import gnu.java.net.protocol.http.Request;
+
+import java.util.EventObject;
+
+/**
+ * A request event.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class RequestEvent
+ extends EventObject
+{
+
+ /**
+ * The request created event type.
+ */
+ public static final int REQUEST_CREATED = 0;
+
+ /**
+ * The request sending event type.
+ */
+ public static final int REQUEST_SENDING = 1;
+
+ /**
+ * The request sent event type.
+ */
+ public static final int REQUEST_SENT = 2;
+
+ /**
+ * The type of this event.
+ */
+ protected int type;
+
+ /**
+ * The request associated with this event.
+ */
+ protected Request request;
+
+ /**
+ * Constructs a request event with the specified source, type, and request.
+ */
+ public RequestEvent(Object source, int type, Request request)
+ {
+ super(source);
+ this.type = type;
+ this.request = request;
+ }
+
+ /**
+ * Returns the type of this event.
+ * @see #type
+ */
+ public int getType()
+ {
+ return type;
+ }
+
+ /**
+ * Returns the request associated with this event.
+ */
+ public Request getRequest()
+ {
+ return request;
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/event/RequestListener.java b/libjava/classpath/gnu/java/net/protocol/http/event/RequestListener.java
new file mode 100644
index 00000000000..c880fbce6f0
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/event/RequestListener.java
@@ -0,0 +1,70 @@
+/* RequestListener.java --
+ Copyright (C) 2004 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.event;
+
+import java.util.EventListener;
+
+/**
+ * A request listener.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public interface RequestListener
+ extends EventListener
+{
+
+ /**
+ * Callback invoked when a request is created from the associated
+ * connection.
+ */
+ void requestCreated(RequestEvent event);
+
+ /**
+ * Callback invoked when the request has been initialised with all data
+ * and before sending this data to the server.
+ */
+ void requestSending(RequestEvent event);
+
+ /**
+ * Callback invoked after all request data has been sent to the server.
+ */
+ void requestSent(RequestEvent event);
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/http/event/package.html b/libjava/classpath/gnu/java/net/protocol/http/event/package.html
new file mode 100644
index 00000000000..6aed0fc0169
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/event/package.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.net.protocol.http.event package.
+ Copyright (C) 2005 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. -->
+
+<html>
+<head><title>GNU Classpath - gnu.java.net.protocol.http.event</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
diff --git a/libjava/classpath/gnu/java/net/protocol/http/package.html b/libjava/classpath/gnu/java/net/protocol/http/package.html
new file mode 100644
index 00000000000..8cf7c1e1663
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/http/package.html
@@ -0,0 +1,76 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.net.protocol.http package.
+ Copyright (C) 2004 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. -->
+
+<html>
+<head><title>GNU Classpath - gnu.java.net.protocol.http</title></head>
+
+<body>
+
+<p>
+This package contains an HTTP/1.1 client, as described in RFC 2616.
+It supports the following features:
+<ul>
+<li>Persistent connections</li>
+<li>Basic and Digest authentication (RFC 2617)</li>
+<li>HTTPS</li>
+<li>HTTP proxies</li>
+<li>HTTP/1.0 compatibility</li>
+<li>Support for WebDAV methods and other HTTP extensions</li>
+<li>Automatic decoding of the chunked transfer-coding</li>
+<li>Parsing of HTTP date headers</li>
+<li>Support for the 100-continue expectation</li>
+</ul>
+</p>
+
+<p>
+The API is similar to the <a href='http://www.webdav.org/neon/'>neon</a>
+WebDAV/HTTP library. A logical connection to the server is instantiated,
+and multiple requests can be issued for this connection. Each request
+has an atomic <code>dispatch</code> method which returns the response.
+All I/O, authentication, etc is handled by registering callback objects
+with the request prior to dispatch, which are notified during the dispatch
+procedure as necessary. Simple byte-array content callbacks are supplied
+which can manage any request/response content that fits in available memory.
+</p>
+
+<p>
+An URL stream handler is provided, supporting the full HttpURLConnection
+specification.
+</p>
+
+</body>
diff --git a/libjava/classpath/gnu/java/net/protocol/https/Handler.java b/libjava/classpath/gnu/java/net/protocol/https/Handler.java
new file mode 100644
index 00000000000..2b137517021
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/https/Handler.java
@@ -0,0 +1,76 @@
+/* Handler.java --
+ Copyright (C) 2004, 2005 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.https;
+
+import gnu.java.net.protocol.http.HTTPConnection;
+import gnu.java.net.protocol.http.HTTPURLConnection;
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+
+/**
+ * An HTTPS URL stream handler.
+ *
+ * @author Chris Burdess (dog@gnu.org)
+ */
+public class Handler
+ extends URLStreamHandler
+{
+
+ /**
+ * Returns the default HTTPS port (443).
+ */
+ protected int getDefaultPort()
+ {
+ return HTTPConnection.HTTPS_PORT;
+ }
+
+ /**
+ * Returns an HTTPURLConnection for the given URL.
+ */
+ public URLConnection openConnection(URL url)
+ throws IOException
+ {
+ return new HTTPURLConnection(url);
+ }
+
+}
+
diff --git a/libjava/classpath/gnu/java/net/protocol/jar/Connection.java b/libjava/classpath/gnu/java/net/protocol/jar/Connection.java
new file mode 100644
index 00000000000..bd7a80da739
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/jar/Connection.java
@@ -0,0 +1,170 @@
+/* Connection - jar url connection for java.net
+ Copyright (C) 1999, 2002, 2003, 2005 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.jar;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.JarURLConnection;
+import java.net.MalformedURLException;
+import java.net.ProtocolException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Hashtable;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.zip.ZipFile;
+
+/**
+ * This subclass of java.net.JarURLConnection models a URLConnection via
+ * the "jar" protocol.
+ *
+ * @author Kresten Krab Thorup (krab@gnu.org)
+ */
+public final class Connection extends JarURLConnection
+{
+ private JarFile jar_file;
+ private JarEntry jar_entry;
+ private URL jar_url;
+
+ public static class JarFileCache
+ {
+ private static Hashtable cache = new Hashtable();
+ private static final int READBUFSIZE = 4*1024;
+
+ public static synchronized JarFile get (URL url) throws IOException
+ {
+ JarFile jf = (JarFile) cache.get (url);
+
+ if (jf != null)
+ return jf;
+
+ if ("file".equals (url.getProtocol()))
+ {
+ File f = new File (url.getFile());
+ jf = new JarFile (f, true, ZipFile.OPEN_READ);
+ }
+ else
+ {
+ URLConnection urlconn = url.openConnection();
+ InputStream is = urlconn.getInputStream();
+ byte[] buf = new byte [READBUFSIZE];
+ File f = File.createTempFile ("cache", "jar");
+ FileOutputStream fos = new FileOutputStream (f);
+ int len = 0;
+
+ while ((len = is.read (buf)) != -1)
+ {
+ fos.write (buf, 0, len);
+ }
+
+ fos.close();
+ // Always verify the Manifest, open read only and delete when done.
+ jf = new JarFile (f, true,
+ ZipFile.OPEN_READ | ZipFile.OPEN_DELETE);
+ }
+
+ cache.put (url, jf);
+
+ return jf;
+ }
+ }
+
+ protected Connection(URL url)
+ throws MalformedURLException
+ {
+ super(url);
+ }
+
+ public synchronized void connect() throws IOException
+ {
+ // Call is ignored if already connected.
+ if (connected)
+ return;
+
+ jar_url = getJarFileURL();
+ jar_file = JarFileCache.get (jar_url);
+ String entry_name = getEntryName();
+
+ if (entry_name != null
+ && !entry_name.equals (""))
+ {
+ jar_entry = (JarEntry) jar_file.getEntry (entry_name);
+
+ if(jar_entry == null)
+ throw new IOException ("No entry for " + entry_name + " exists.");
+ }
+
+ connected = true;
+ }
+
+ public InputStream getInputStream() throws IOException
+ {
+ if (!connected)
+ connect();
+
+ 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);
+ }
+
+ public synchronized JarFile getJarFile() throws IOException
+ {
+ if (!connected)
+ connect();
+
+ if (! doInput)
+ throw new ProtocolException("Can't open JarFile if doInput is false");
+
+ return jar_file;
+ }
+
+ public int getContentLength()
+ {
+ if (!connected)
+ return -1;
+
+ return (int) jar_entry.getSize();
+ }
+}
diff --git a/libjava/classpath/gnu/java/net/protocol/jar/Handler.java b/libjava/classpath/gnu/java/net/protocol/jar/Handler.java
new file mode 100644
index 00000000000..316d8cb02be
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/jar/Handler.java
@@ -0,0 +1,173 @@
+/* gnu.java.net.protocol.jar.Handler - jar protocol handler for java.net
+ Copyright (C) 1999, 2002, 2003, 2005 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.jar;
+
+import gnu.java.net.URLParseError;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+
+/**
+ * @author Kresten Krab Thorup (krab@gnu.org)
+ */
+public class Handler extends URLStreamHandler
+{
+ /**
+ * A do nothing constructor
+ */
+ public Handler()
+ {
+ }
+
+ /**
+ * This method returs a new JarURLConnection for the specified URL
+ *
+ * @param url The URL to return a connection for
+ *
+ * @return The URLConnection
+ *
+ * @exception IOException If an error occurs
+ */
+ protected URLConnection openConnection(URL url) throws IOException
+ {
+ return new Connection(url);
+ }
+
+ /**
+ * This method overrides URLStreamHandler's for parsing url of protocol "jar"
+ *
+ * @param url The URL object in which to store the results
+ * @param url_string The String-ized URL to parse
+ * @param start The position in the string to start scanning from
+ * @param end The position in the string to stop scanning
+ */
+ protected void parseURL (URL url, String url_string, int start, int end)
+ {
+ // This method does not throw an exception or return a value. Thus our
+ // strategy when we encounter an error in parsing is to return without
+ // doing anything.
+ String file = url.getFile();
+
+ if (!file.equals(""))
+ { //has context url
+ url_string = url_string.substring (start, end);
+ if (url_string.startsWith("/"))
+ { //url string is an absolute path
+ int idx = file.lastIndexOf ("!/");
+
+ if (idx < 0)
+ throw new URLParseError("no !/ in spec");
+
+ file = file.substring (0, idx + 1) + url_string;
+ }
+ else if (url_string.length() > 0)
+ {
+ int idx = file.lastIndexOf ("/");
+ if (idx == -1) //context path is weird
+ file = "/" + url_string;
+ else if (idx == (file.length() - 1))
+ //just concatenate two parts
+ file = file + url_string;
+ else
+ // according to Java API Documentation, here is a little different
+ // with URLStreamHandler.parseURL
+ // but JDK seems doesn't handle it well
+ file = file.substring(0, idx + 1) + url_string;
+ }
+
+ setURL (url, "jar", url.getHost(), url.getPort(), file, null);
+ return;
+ }
+
+ // Bunches of things should be true. Make sure.
+ if (end < start)
+ return;
+ if (end - start < 2)
+ return;
+ if (start > url_string.length())
+ return;
+
+ // Skip remains of protocol
+ url_string = url_string.substring (start, end);
+
+ int jar_stop;
+ if ((jar_stop = url_string.indexOf("!/")) < 0)
+ throw new URLParseError("no !/ in spec");
+
+ try
+ {
+ new URL(url_string.substring (0, jar_stop));
+ }
+ catch (MalformedURLException e)
+ {
+ throw new URLParseError("invalid inner URL: " + e.getMessage());
+ }
+
+ if (!url.getProtocol().equals ("jar") )
+ throw new URLParseError("unexpected protocol " + url.getProtocol());
+
+ setURL (url, "jar", url.getHost(), url.getPort(), url_string, null);
+ }
+
+ /**
+ * This method converts a Jar URL object into a String.
+ *
+ * @param url The URL object to convert
+ */
+ protected String toExternalForm (URL url)
+ {
+ String file = url.getFile();
+ String ref = url.getRef();
+
+ // return "jar:" + file;
+ // Performance!!:
+ // Do the concatenation manually to avoid resize StringBuffer's
+ // internal buffer. The length of ref is not taken into consideration
+ // as it's a rare path.
+ StringBuffer sb = new StringBuffer (file.length() + 5);
+ sb.append ("jar:");
+ sb.append (file);
+ if (ref != null)
+ sb.append('#').append(ref);
+ return sb.toString();
+ }
+}
diff --git a/libjava/classpath/gnu/java/net/protocol/jar/package.html b/libjava/classpath/gnu/java/net/protocol/jar/package.html
new file mode 100644
index 00000000000..dcd263d59dc
--- /dev/null
+++ b/libjava/classpath/gnu/java/net/protocol/jar/package.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.net.protocol.jar package.
+ Copyright (C) 2005 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. -->
+
+<html>
+<head><title>GNU Classpath - gnu.java.net.protocol.jar</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>