test/jdk/sun/net/ftp/FtpURL.java
changeset 47216 71c04702a3d5
parent 25805 0bc2aa4aadbe
child 54746 61049e91eae5
--- /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();
+        }
+    }
+}