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