Initial revision

From-SVN: r102074
This commit is contained in:
Tom Tromey 2005-07-16 00:30:23 +00:00
parent 6f4434b39b
commit f911ba985a
4557 changed files with 1000262 additions and 0 deletions

View file

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

View file

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

View file

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

View file

@ -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];
}
}

View file

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

View file

@ -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

View file

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

View file

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

View file

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

View file

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

View file

@ -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>

View file

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

View file

@ -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

View file

@ -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>

View file

@ -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)
{
}
}
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

@ -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)
{
}
}
}
}

View file

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

View file

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

View file

@ -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>

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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>

View file

@ -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>

View file

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

View file

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

View file

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

View file

@ -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>