--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/sun/net/ftp/FtpURL.java Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,510 @@
+/*
+ * Copyright (c) 2001, 2010, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.*;
+import java.net.*;
+
+/*
+ * @test
+ * @bug 4398880
+ * @summary FTP URL processing modified to conform to RFC 1738
+ */
+
+public class FtpURL {
+ /**
+ * 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 portEnabled = true;
+ private boolean pasvEnabled = true;
+ private String username;
+ private String password;
+ private String cwd;
+ private String filename;
+ private String type;
+ private boolean list = false;
+
+ /**
+ * This Inner class will handle ONE client at a time.
+ * That's where 99% of the protocol handling is done.
+ */
+
+ private class FtpServerHandler {
+ 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 CDUP = 4;
+ private final int PWD = 5;
+ private final int TYPE = 6;
+ private final int NOOP = 7;
+ private final int RETR = 8;
+ private final int PASV = 9;
+ private final int PORT = 10;
+ private final int LIST = 11;
+ private final int REIN = 12;
+ private final int QUIT = 13;
+ private final int STOR = 14;
+ private final int NLST = 15;
+ private final int RNFR = 16;
+ private final int RNTO = 17;
+ String[] cmds = { "USER", "PASS", "CWD", "CDUP", "PWD", "TYPE",
+ "NOOP", "RETR", "PASV", "PORT", "LIST", "REIN",
+ "QUIT", "STOR", "NLST", "RNFR", "RNTO" };
+ 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;
+ }
+ synchronized (FtpServer.this) {
+ 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) {
+ username = str.substring(5);
+ password = null;
+ cwd = null;
+ if ("user2".equals(username)) {
+ out.println("230 Guest login ok, access restrictions apply.");
+ logged = true;
+ } else {
+ 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 Guest login ok, access restrictions apply.");
+ password = str.substring(5);
+ 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 + ".");
+ type = arg;
+ break;
+ case CWD:
+ out.println("250 CWD command successful.");
+ if (cwd == null)
+ cwd = str.substring(4);
+ else
+ cwd = cwd + "/" + str.substring(4);
+ break;
+ case CDUP:
+ out.println("250 CWD command successful.");
+ break;
+ case PWD:
+ out.println("257 \"" + cwd + "\" is current directory");
+ 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();
+ 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:
+ {
+ filename = str.substring(5);
+ OutputStream dout = getOutDataStream();
+ if (dout != null) {
+ out.println("200 Command okay.");
+ PrintWriter pout = new PrintWriter(new BufferedOutputStream(dout));
+ pout.println("Hello World!");
+ pout.flush();
+ pout.close();
+ list = false;
+ } else
+ out.println("425 Can't build data connection: Connection refused.");
+ }
+ break;
+ case NLST:
+ filename = arg;
+ case LIST:
+ {
+ OutputStream dout = getOutDataStream();
+ if (dout != null) {
+ out.println("200 Command okay.");
+ PrintWriter pout = new PrintWriter(new BufferedOutputStream(dout));
+ pout.println("total 130");
+ pout.println("drwxrwxrwt 7 sys sys 577 May 12 03:30 .");
+ pout.println("drwxr-xr-x 39 root root 1024 Mar 27 12:55 ..");
+ pout.println("drwxrwxr-x 2 root root 176 Apr 10 12:02 .X11-pipe");
+ pout.println("drwxrwxr-x 2 root root 176 Apr 10 12:02 .X11-unix");
+ pout.println("drwxrwxrwx 2 root root 179 Mar 30 15:09 .pcmcia");
+ pout.println("drwxrwxrwx 2 jladen staff 117 Mar 30 18:18 .removable");
+ pout.println("drwxrwxrwt 2 root root 327 Mar 30 15:08 .rpc_door");
+ pout.println("-rw-r--r-- 1 root other 21 May 5 16:59 hello2.txt");
+ pout.println("-rw-rw-r-- 1 root sys 5968 Mar 30 15:08 ps_data");
+ pout.flush();
+ pout.close();
+ list = true;
+ try {
+ FtpServer.this.wait ();
+ } catch (Exception e) {}
+ } else
+ out.println("425 Can't build data connection: Connection refused.");
+ }
+ break;
+ case STOR:
+ {
+ InputStream is = getInDataStream();
+ if (is != null) {
+ out.println("200 Command okay.");
+ BufferedInputStream din = new BufferedInputStream(is);
+ int val;
+ do {
+ val = din.read();
+ } while (val != -1);
+ din.close();
+ } 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;
+ try {
+ server = new ServerSocket(port);
+ } catch (IOException e) {
+ }
+ }
+
+ 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;
+ }
+
+ synchronized public void setPortEnabled(boolean ok) {
+ portEnabled = ok;
+ }
+
+ synchronized public void setPasvEnabled(boolean ok) {
+ pasvEnabled = ok;
+ }
+
+ String getUsername() {
+ return username;
+ }
+
+ String getPassword() {
+ return password;
+ }
+
+ String pwd() {
+ return cwd;
+ }
+
+ String getFilename() {
+ return filename;
+ }
+
+ String getType() {
+ return type;
+ }
+
+ synchronized boolean getList() {
+ notify ();
+ return list;
+ }
+
+ /*
+ * All we got to do here is create a ServerSocket and wait for connections.
+ * When a connection happens, we just have to create a thread that will
+ * handle it.
+ */
+ public void run() {
+ try {
+ Socket client;
+ for (int i=0; i<2; i++) {
+ client = server.accept();
+ (new FtpServerHandler(client)).run();
+ }
+ } catch(Exception e) {
+ } finally {
+ try { server.close(); } catch (IOException unused) {}
+ }
+ }
+ }
+ public static void main(String[] args) throws Exception {
+ FtpURL test = new FtpURL();
+ }
+
+ public FtpURL() throws Exception {
+ FtpServer server = new FtpServer(0);
+ BufferedReader in = null;
+ try {
+ server.start();
+ int port = server.getPort();
+
+ // Now let's check the URL handler
+
+ URL url = new URL("ftp://user:password@localhost:" + port + "/%2Fetc/motd;type=a");
+ URLConnection con = url.openConnection();
+ in = new BufferedReader(new InputStreamReader(con.getInputStream()));
+ String s;
+ do {
+ s = in.readLine();
+ } while (s != null);
+ if (!("user".equals(server.getUsername())))
+ throw new RuntimeException("Inccorect username received");
+ if (!("password".equals(server.getPassword())))
+ throw new RuntimeException("Inccorect password received");
+ if (!("/etc".equals(server.pwd())))
+ throw new RuntimeException("Inccorect directory received");
+ if (!("motd".equals(server.getFilename())))
+ throw new RuntimeException("Inccorect username received");
+ if (!("A".equals(server.getType())))
+ throw new RuntimeException("Incorrect type received");
+
+ in.close();
+ // We're done!
+
+ // Second URL test
+ port = server.getPort();
+
+ // Now let's check the URL handler
+
+ url = new URL("ftp://user2@localhost:" + port + "/%2Fusr/bin;type=d");
+ con = url.openConnection();
+ in = new BufferedReader(new InputStreamReader(con.getInputStream()));
+ do {
+ s = in.readLine();
+ } while (s != null);
+ if (!server.getList())
+ throw new RuntimeException(";type=d didn't generate a NLST");
+ if (server.getPassword() != null)
+ throw new RuntimeException("password should be null!");
+ if (! "bin".equals(server.getFilename()))
+ throw new RuntimeException("Incorrect filename received");
+ if (! "/usr".equals(server.pwd()))
+ throw new RuntimeException("Incorrect pwd received");
+ // We're done!
+
+ } catch (Exception e) {
+ throw new RuntimeException("FTP support error: " + e.getMessage());
+ } finally {
+ try { in.close(); } catch (IOException unused) {}
+ server.terminate();
+ server.server.close();
+ }
+ }
+}