456 lines
18 KiB
Java
456 lines
18 KiB
Java
|
/*
|
||
|
* Copyright 2002 Sun Microsystems, Inc. All Rights Reserved.
|
||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||
|
*
|
||
|
* This code is free software; you can redistribute it and/or modify it
|
||
|
* under the terms of the GNU General Public License version 2 only, as
|
||
|
* published by the Free Software Foundation.
|
||
|
*
|
||
|
* This code 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
|
||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||
|
* accompanied this code).
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License version
|
||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||
|
*
|
||
|
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||
|
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||
|
* have any questions.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
*
|
||
|
* run from MarkResetTest.sh
|
||
|
*/
|
||
|
|
||
|
import java.io.*;
|
||
|
import java.net.*;
|
||
|
import java.util.regex.*;
|
||
|
|
||
|
public class MarkResetTest {
|
||
|
|
||
|
/**
|
||
|
* A class that simulates, on a separate, an FTP server.
|
||
|
*/
|
||
|
private class FtpServer extends Thread {
|
||
|
private ServerSocket server;
|
||
|
private int port;
|
||
|
private boolean done = false;
|
||
|
private boolean pasvEnabled = true;
|
||
|
private boolean portEnabled = true;
|
||
|
private boolean extendedEnabled = true;
|
||
|
|
||
|
/**
|
||
|
* This Inner class will handle ONE client at a time.
|
||
|
* That's where 99% of the protocol handling is done.
|
||
|
*/
|
||
|
|
||
|
private class FtpServerHandler extends Thread {
|
||
|
BufferedReader in;
|
||
|
PrintWriter out;
|
||
|
Socket client;
|
||
|
private final int ERROR = 0;
|
||
|
private final int USER = 1;
|
||
|
private final int PASS = 2;
|
||
|
private final int CWD = 3;
|
||
|
private final int TYPE = 4;
|
||
|
private final int RETR = 5;
|
||
|
private final int PASV = 6;
|
||
|
private final int PORT = 7;
|
||
|
private final int QUIT = 8;
|
||
|
private final int EPSV = 9;
|
||
|
String[] cmds = { "USER", "PASS", "CWD",
|
||
|
"TYPE", "RETR", "PASV",
|
||
|
"PORT", "QUIT", "EPSV"};
|
||
|
private String arg = null;
|
||
|
private ServerSocket pasv = null;
|
||
|
private int data_port = 0;
|
||
|
private InetAddress data_addr = null;
|
||
|
|
||
|
/**
|
||
|
* Parses a line to match it with one of the supported FTP commands.
|
||
|
* Returns the command number.
|
||
|
*/
|
||
|
|
||
|
private int parseCmd(String cmd) {
|
||
|
if (cmd == null || cmd.length() < 3)
|
||
|
return ERROR;
|
||
|
int blank = cmd.indexOf(' ');
|
||
|
if (blank < 0)
|
||
|
blank = cmd.length();
|
||
|
if (blank < 3)
|
||
|
return ERROR;
|
||
|
String s = cmd.substring(0, blank);
|
||
|
if (cmd.length() > blank+1)
|
||
|
arg = cmd.substring(blank+1, cmd.length());
|
||
|
else
|
||
|
arg = null;
|
||
|
for (int i = 0; i < cmds.length; i++) {
|
||
|
if (s.equalsIgnoreCase(cmds[i]))
|
||
|
return i+1;
|
||
|
}
|
||
|
return ERROR;
|
||
|
}
|
||
|
|
||
|
public FtpServerHandler(Socket cl) {
|
||
|
client = cl;
|
||
|
}
|
||
|
|
||
|
protected boolean isPasvSet() {
|
||
|
if (pasv != null && !pasvEnabled) {
|
||
|
try {
|
||
|
pasv.close();
|
||
|
} catch (IOException ex) {
|
||
|
}
|
||
|
pasv = null;
|
||
|
}
|
||
|
if (pasvEnabled && pasv != null)
|
||
|
return true;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Open the data socket with the client. This can be the
|
||
|
* result of a "PASV" or "PORT" command.
|
||
|
*/
|
||
|
|
||
|
protected OutputStream getOutDataStream() {
|
||
|
try {
|
||
|
if (isPasvSet()) {
|
||
|
Socket s = pasv.accept();
|
||
|
return s.getOutputStream();
|
||
|
}
|
||
|
if (data_addr != null) {
|
||
|
Socket s = new Socket(data_addr, data_port);
|
||
|
data_addr = null;
|
||
|
data_port = 0;
|
||
|
return s.getOutputStream();
|
||
|
}
|
||
|
} catch (Exception e) {
|
||
|
e.printStackTrace();
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
protected InputStream getInDataStream() {
|
||
|
try {
|
||
|
if (isPasvSet()) {
|
||
|
Socket s = pasv.accept();
|
||
|
return s.getInputStream();
|
||
|
}
|
||
|
if (data_addr != null) {
|
||
|
Socket s = new Socket(data_addr, data_port);
|
||
|
data_addr = null;
|
||
|
data_port = 0;
|
||
|
return s.getInputStream();
|
||
|
}
|
||
|
} catch (Exception e) {
|
||
|
e.printStackTrace();
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Handles the protocol exchange with the client.
|
||
|
*/
|
||
|
|
||
|
public void run() {
|
||
|
boolean done = false;
|
||
|
String str;
|
||
|
int res;
|
||
|
boolean logged = false;
|
||
|
boolean waitpass = false;
|
||
|
|
||
|
try {
|
||
|
in = new BufferedReader(new InputStreamReader(
|
||
|
client.getInputStream()));
|
||
|
out = new PrintWriter(client.getOutputStream(), true);
|
||
|
out.println("220 tatooine FTP server (SunOS 5.8) ready.");
|
||
|
} catch (Exception ex) {
|
||
|
return;
|
||
|
}
|
||
|
while (!done) {
|
||
|
try {
|
||
|
str = in.readLine();
|
||
|
res = parseCmd(str);
|
||
|
if ((res > PASS && res != QUIT) && !logged) {
|
||
|
out.println("530 Not logged in.");
|
||
|
continue;
|
||
|
}
|
||
|
switch (res) {
|
||
|
case ERROR:
|
||
|
out.println("500 '" + str +
|
||
|
"': command not understood.");
|
||
|
break;
|
||
|
case USER:
|
||
|
if (!logged && !waitpass) {
|
||
|
out.println("331 Password required for " + arg);
|
||
|
waitpass = true;
|
||
|
} else {
|
||
|
out.println("503 Bad sequence of commands.");
|
||
|
}
|
||
|
break;
|
||
|
case PASS:
|
||
|
if (!logged && waitpass) {
|
||
|
out.println("230-Welcome to the FTP server!");
|
||
|
out.println("ab");
|
||
|
out.println("230 Guest login ok, " +
|
||
|
"access restrictions apply.");
|
||
|
logged = true;
|
||
|
waitpass = false;
|
||
|
} else
|
||
|
out.println("503 Bad sequence of commands.");
|
||
|
break;
|
||
|
case QUIT:
|
||
|
out.println("221 Goodbye.");
|
||
|
out.flush();
|
||
|
out.close();
|
||
|
if (pasv != null)
|
||
|
pasv.close();
|
||
|
done = true;
|
||
|
break;
|
||
|
case TYPE:
|
||
|
out.println("200 Type set to " + arg + ".");
|
||
|
break;
|
||
|
case CWD:
|
||
|
out.println("250 CWD command successful.");
|
||
|
break;
|
||
|
case EPSV:
|
||
|
if (!extendedEnabled || !pasvEnabled) {
|
||
|
out.println("500 EPSV is disabled, " +
|
||
|
"use PORT instead.");
|
||
|
continue;
|
||
|
}
|
||
|
if ("all".equalsIgnoreCase(arg)) {
|
||
|
out.println("200 EPSV ALL command successful.");
|
||
|
continue;
|
||
|
}
|
||
|
try {
|
||
|
if (pasv == null)
|
||
|
pasv = new ServerSocket(0);
|
||
|
int port = pasv.getLocalPort();
|
||
|
out.println("229 Entering Extended" +
|
||
|
" Passive Mode (|||" + port + "|)");
|
||
|
} catch (IOException ssex) {
|
||
|
out.println("425 Can't build data connection:" +
|
||
|
" Connection refused.");
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case PASV:
|
||
|
if (!pasvEnabled) {
|
||
|
out.println("500 PASV is disabled, " +
|
||
|
"use PORT instead.");
|
||
|
continue;
|
||
|
}
|
||
|
try {
|
||
|
if (pasv == null)
|
||
|
pasv = new ServerSocket(0);
|
||
|
int port = pasv.getLocalPort();
|
||
|
|
||
|
// Parenthesis are optional, so let's be
|
||
|
// nasty and don't put them
|
||
|
out.println("227 Entering Passive Mode" +
|
||
|
" 127,0,0,1," +
|
||
|
(port >> 8) + "," + (port & 0xff));
|
||
|
} catch (IOException ssex) {
|
||
|
out.println("425 Can't build data connection:" +
|
||
|
"Connection refused.");
|
||
|
}
|
||
|
break;
|
||
|
case PORT:
|
||
|
if (!portEnabled) {
|
||
|
out.println("500 PORT is disabled, " +
|
||
|
"use PASV instead");
|
||
|
continue;
|
||
|
}
|
||
|
StringBuffer host;
|
||
|
int i = 0, j = 4;
|
||
|
while (j > 0) {
|
||
|
i = arg.indexOf(',', i + 1);
|
||
|
if (i < 0)
|
||
|
break;
|
||
|
j--;
|
||
|
}
|
||
|
if (j != 0) {
|
||
|
out.println("500 '" + arg + "':" +
|
||
|
" command not understood.");
|
||
|
continue;
|
||
|
}
|
||
|
try {
|
||
|
host = new StringBuffer(arg.substring(0, i));
|
||
|
for (j = 0; j < host.length(); j++)
|
||
|
if (host.charAt(j) == ',')
|
||
|
host.setCharAt(j, '.');
|
||
|
String ports = arg.substring(i+1);
|
||
|
i = ports.indexOf(',');
|
||
|
data_port = Integer.parseInt(
|
||
|
ports.substring(0, i)) << 8;
|
||
|
data_port += (Integer.parseInt(
|
||
|
ports.substring(i+1)));
|
||
|
data_addr = InetAddress.getByName(
|
||
|
host.toString());
|
||
|
out.println("200 Command okay.");
|
||
|
} catch (Exception ex3) {
|
||
|
data_port = 0;
|
||
|
data_addr = null;
|
||
|
out.println("500 '" + arg + "':" +
|
||
|
" command not understood.");
|
||
|
}
|
||
|
break;
|
||
|
case RETR:
|
||
|
{
|
||
|
File file = new File(arg);
|
||
|
if (!file.exists()) {
|
||
|
System.out.println("File not found");
|
||
|
out.println("200 Command okay.");
|
||
|
out.println("550 '" + arg +
|
||
|
"' No such file or directory.");
|
||
|
break;
|
||
|
}
|
||
|
FileInputStream fin = new FileInputStream(file);
|
||
|
OutputStream dout = getOutDataStream();
|
||
|
if (dout != null) {
|
||
|
out.println("150 Binary data connection" +
|
||
|
" for " + arg +
|
||
|
" (" + client.getInetAddress().
|
||
|
getHostAddress() + ") (" +
|
||
|
file.length() + " bytes).");
|
||
|
int c;
|
||
|
int len = 0;
|
||
|
while ((c = fin.read()) != -1) {
|
||
|
dout.write(c);
|
||
|
len++;
|
||
|
}
|
||
|
dout.flush();
|
||
|
dout.close();
|
||
|
fin.close();
|
||
|
out.println("226 Binary Transfer complete.");
|
||
|
} else {
|
||
|
out.println("425 Can't build data" +
|
||
|
" connection: Connection refused.");
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
} catch (IOException ioe) {
|
||
|
ioe.printStackTrace();
|
||
|
try {
|
||
|
out.close();
|
||
|
} catch (Exception ex2) {
|
||
|
}
|
||
|
done = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public FtpServer(int port) {
|
||
|
this.port = port;
|
||
|
}
|
||
|
|
||
|
public FtpServer() {
|
||
|
this(21);
|
||
|
}
|
||
|
|
||
|
public int getPort() {
|
||
|
if (server != null)
|
||
|
return server.getLocalPort();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* A way to tell the server that it can stop.
|
||
|
*/
|
||
|
synchronized public void terminate() {
|
||
|
done = true;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* All we got to do here is create a ServerSocket and wait for a
|
||
|
* connection. When a connection happens, we just have to create
|
||
|
* a thread that will handle it.
|
||
|
*/
|
||
|
public void run() {
|
||
|
try {
|
||
|
server = new ServerSocket(port);
|
||
|
Socket client;
|
||
|
client = server.accept();
|
||
|
(new FtpServerHandler(client)).start();
|
||
|
server.close();
|
||
|
} catch (Exception e) {
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static void main(String[] args) throws Exception {
|
||
|
MarkResetTest test = new MarkResetTest();
|
||
|
}
|
||
|
|
||
|
public MarkResetTest() {
|
||
|
FtpServer server = null;
|
||
|
try {
|
||
|
server = new FtpServer(0);
|
||
|
server.start();
|
||
|
int port = 0;
|
||
|
while (port == 0) {
|
||
|
Thread.sleep(500);
|
||
|
port = server.getPort();
|
||
|
}
|
||
|
|
||
|
String filename = "EncDec.doc";
|
||
|
URL url = new URL("ftp://localhost:" + port + "/" +
|
||
|
filename);
|
||
|
|
||
|
URLConnection con = url.openConnection();
|
||
|
System.out.println("getContent: " + con.getContent());
|
||
|
System.out.println("getContent-length: " + con.getContentLength());
|
||
|
|
||
|
InputStream is = con.getInputStream();
|
||
|
|
||
|
/**
|
||
|
* guessContentTypeFromStream method calls mark and reset methods
|
||
|
* on the given stream. Make sure that calling
|
||
|
* guessContentTypeFromStream repeatedly does not affect
|
||
|
* reading from the stream afterwards
|
||
|
*/
|
||
|
System.out.println("Call GuessContentTypeFromStream()" +
|
||
|
" several times..");
|
||
|
for (int i = 0; i < 5; i++) {
|
||
|
System.out.println((i + 1) + " mime-type: " +
|
||
|
con.guessContentTypeFromStream(is));
|
||
|
}
|
||
|
|
||
|
int len = 0;
|
||
|
int c;
|
||
|
while ((c = is.read()) != -1) {
|
||
|
len++;
|
||
|
}
|
||
|
is.close();
|
||
|
System.out.println("read: " + len + " bytes of the file");
|
||
|
|
||
|
// We're done!
|
||
|
server.terminate();
|
||
|
server.interrupt();
|
||
|
|
||
|
// Did we pass ?
|
||
|
if (len != (new File(filename)).length()) {
|
||
|
throw new Exception("Failed to read the file correctly");
|
||
|
}
|
||
|
System.out.println("PASSED: File read correctly");
|
||
|
} catch (Exception e) {
|
||
|
e.printStackTrace();
|
||
|
try {
|
||
|
server.terminate();
|
||
|
server.interrupt();
|
||
|
} catch (Exception ex) {
|
||
|
}
|
||
|
throw new RuntimeException("FTP support error: " + e.getMessage());
|
||
|
}
|
||
|
}
|
||
|
}
|