Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/sun/net/ftp/FtpURL.java
38838 views
/*1* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import java.io.*;24import java.net.*;2526/*27* @test28* @bug 439888029* @summary FTP URL processing modified to conform to RFC 173830*/3132public class FtpURL {33/**34* A class that simulates, on a separate, an FTP server.35*/3637private class FtpServer extends Thread {38private ServerSocket server;39private int port;40private boolean done = false;41private boolean portEnabled = true;42private boolean pasvEnabled = true;43private String username;44private String password;45private String cwd;46private String filename;47private String type;48private boolean list = false;4950/**51* This Inner class will handle ONE client at a time.52* That's where 99% of the protocol handling is done.53*/5455private class FtpServerHandler {56BufferedReader in;57PrintWriter out;58Socket client;59private final int ERROR = 0;60private final int USER = 1;61private final int PASS = 2;62private final int CWD = 3;63private final int CDUP = 4;64private final int PWD = 5;65private final int TYPE = 6;66private final int NOOP = 7;67private final int RETR = 8;68private final int PASV = 9;69private final int PORT = 10;70private final int LIST = 11;71private final int REIN = 12;72private final int QUIT = 13;73private final int STOR = 14;74private final int NLST = 15;75private final int RNFR = 16;76private final int RNTO = 17;77String[] cmds = { "USER", "PASS", "CWD", "CDUP", "PWD", "TYPE",78"NOOP", "RETR", "PASV", "PORT", "LIST", "REIN",79"QUIT", "STOR", "NLST", "RNFR", "RNTO" };80private String arg = null;81private ServerSocket pasv = null;82private int data_port = 0;83private InetAddress data_addr = null;8485/**86* Parses a line to match it with one of the supported FTP commands.87* Returns the command number.88*/8990private int parseCmd(String cmd) {91if (cmd == null || cmd.length() < 3)92return ERROR;93int blank = cmd.indexOf(' ');94if (blank < 0)95blank = cmd.length();96if (blank < 3)97return ERROR;98String s = cmd.substring(0, blank);99if (cmd.length() > blank+1)100arg = cmd.substring(blank+1, cmd.length());101else102arg = null;103for (int i = 0; i < cmds.length; i++) {104if (s.equalsIgnoreCase(cmds[i]))105return i+1;106}107return ERROR;108}109110public FtpServerHandler(Socket cl) {111client = cl;112}113114protected boolean isPasvSet() {115if (pasv != null && !pasvEnabled) {116try {117pasv.close();118} catch (IOException ex) {119}120pasv = null;121}122if (pasvEnabled && pasv != null)123return true;124return false;125}126127/**128* Open the data socket with the client. This can be the129* result of a "PASV" or "PORT" command.130*/131132protected OutputStream getOutDataStream() {133try {134if (isPasvSet()) {135Socket s = pasv.accept();136return s.getOutputStream();137}138if (data_addr != null) {139Socket s = new Socket(data_addr, data_port);140data_addr = null;141data_port = 0;142return s.getOutputStream();143}144} catch (Exception e) {145e.printStackTrace();146}147return null;148}149150protected InputStream getInDataStream() {151try {152if (isPasvSet()) {153Socket s = pasv.accept();154return s.getInputStream();155}156if (data_addr != null) {157Socket s = new Socket(data_addr, data_port);158data_addr = null;159data_port = 0;160return s.getInputStream();161}162} catch (Exception e) {163e.printStackTrace();164}165return null;166}167168/**169* Handles the protocol exchange with the client.170*/171172public void run() {173boolean done = false;174String str;175int res;176boolean logged = false;177boolean waitpass = false;178179try {180in = new BufferedReader(new InputStreamReader(client.getInputStream()));181out = new PrintWriter(client.getOutputStream(), true);182out.println("220 tatooine FTP server (SunOS 5.8) ready.");183} catch (Exception ex) {184return;185}186synchronized (FtpServer.this) {187while (!done) {188try {189str = in.readLine();190res = parseCmd(str);191if ((res > PASS && res != QUIT) && !logged) {192out.println("530 Not logged in.");193continue;194}195switch (res) {196case ERROR:197out.println("500 '" + str + "': command not understood.");198break;199case USER:200if (!logged && !waitpass) {201username = str.substring(5);202password = null;203cwd = null;204if ("user2".equals(username)) {205out.println("230 Guest login ok, access restrictions apply.");206logged = true;207} else {208out.println("331 Password required for " + arg);209waitpass = true;210}211} else {212out.println("503 Bad sequence of commands.");213}214break;215case PASS:216if (!logged && waitpass) {217out.println("230 Guest login ok, access restrictions apply.");218password = str.substring(5);219logged = true;220waitpass = false;221} else222out.println("503 Bad sequence of commands.");223break;224case QUIT:225out.println("221 Goodbye.");226out.flush();227out.close();228if (pasv != null)229pasv.close();230done = true;231break;232case TYPE:233out.println("200 Type set to " + arg + ".");234type = arg;235break;236case CWD:237out.println("250 CWD command successful.");238if (cwd == null)239cwd = str.substring(4);240else241cwd = cwd + "/" + str.substring(4);242break;243case CDUP:244out.println("250 CWD command successful.");245break;246case PWD:247out.println("257 \"" + cwd + "\" is current directory");248break;249case PASV:250if (!pasvEnabled) {251out.println("500 PASV is disabled, use PORT instead.");252continue;253}254try {255if (pasv == null)256pasv = new ServerSocket(0);257int port = pasv.getLocalPort();258out.println("227 Entering Passive Mode (127,0,0,1," +259(port >> 8) + "," + (port & 0xff) +")");260} catch (IOException ssex) {261out.println("425 Can't build data connection: Connection refused.");262}263break;264case PORT:265if (!portEnabled) {266out.println("500 PORT is disabled, use PASV instead");267continue;268}269StringBuffer host;270int i=0, j=4;271while (j>0) {272i = arg.indexOf(',', i+1);273if (i < 0)274break;275j--;276}277if (j != 0) {278out.println("500 '" + arg + "': command not understood.");279continue;280}281try {282host = new StringBuffer(arg.substring(0,i));283for (j=0; j < host.length(); j++)284if (host.charAt(j) == ',')285host.setCharAt(j, '.');286String ports = arg.substring(i+1);287i = ports.indexOf(',');288data_port = Integer.parseInt(ports.substring(0,i)) << 8;289data_port += (Integer.parseInt(ports.substring(i+1)));290data_addr = InetAddress.getByName(host.toString());291out.println("200 Command okay.");292} catch (Exception ex3) {293data_port = 0;294data_addr = null;295out.println("500 '" + arg + "': command not understood.");296}297break;298case RETR:299{300filename = str.substring(5);301OutputStream dout = getOutDataStream();302if (dout != null) {303out.println("200 Command okay.");304PrintWriter pout = new PrintWriter(new BufferedOutputStream(dout));305pout.println("Hello World!");306pout.flush();307pout.close();308list = false;309} else310out.println("425 Can't build data connection: Connection refused.");311}312break;313case NLST:314filename = arg;315case LIST:316{317OutputStream dout = getOutDataStream();318if (dout != null) {319out.println("200 Command okay.");320PrintWriter pout = new PrintWriter(new BufferedOutputStream(dout));321pout.println("total 130");322pout.println("drwxrwxrwt 7 sys sys 577 May 12 03:30 .");323pout.println("drwxr-xr-x 39 root root 1024 Mar 27 12:55 ..");324pout.println("drwxrwxr-x 2 root root 176 Apr 10 12:02 .X11-pipe");325pout.println("drwxrwxr-x 2 root root 176 Apr 10 12:02 .X11-unix");326pout.println("drwxrwxrwx 2 root root 179 Mar 30 15:09 .pcmcia");327pout.println("drwxrwxrwx 2 jladen staff 117 Mar 30 18:18 .removable");328pout.println("drwxrwxrwt 2 root root 327 Mar 30 15:08 .rpc_door");329pout.println("-rw-r--r-- 1 root other 21 May 5 16:59 hello2.txt");330pout.println("-rw-rw-r-- 1 root sys 5968 Mar 30 15:08 ps_data");331pout.flush();332pout.close();333list = true;334try {335FtpServer.this.wait ();336} catch (Exception e) {}337} else338out.println("425 Can't build data connection: Connection refused.");339}340break;341case STOR:342{343InputStream is = getInDataStream();344if (is != null) {345out.println("200 Command okay.");346BufferedInputStream din = new BufferedInputStream(is);347int val;348do {349val = din.read();350} while (val != -1);351din.close();352} else353out.println("425 Can't build data connection: Connection refused.");354}355break;356}357} catch (IOException ioe) {358ioe.printStackTrace();359try {360out.close();361} catch (Exception ex2) {362}363done = true;364}365}366}367}368}369370public FtpServer(int port) {371this.port = port;372try {373server = new ServerSocket(port);374} catch (IOException e) {375}376}377378public FtpServer() {379this(21);380}381382public int getPort() {383if (server != null)384return server.getLocalPort();385return 0;386}387388/**389* A way to tell the server that it can stop.390*/391synchronized public void terminate() {392done = true;393}394395synchronized public void setPortEnabled(boolean ok) {396portEnabled = ok;397}398399synchronized public void setPasvEnabled(boolean ok) {400pasvEnabled = ok;401}402403String getUsername() {404return username;405}406407String getPassword() {408return password;409}410411String pwd() {412return cwd;413}414415String getFilename() {416return filename;417}418419String getType() {420return type;421}422423synchronized boolean getList() {424notify ();425return list;426}427428/*429* All we got to do here is create a ServerSocket and wait for connections.430* When a connection happens, we just have to create a thread that will431* handle it.432*/433public void run() {434try {435Socket client;436for (int i=0; i<2; i++) {437client = server.accept();438(new FtpServerHandler(client)).run();439}440} catch(Exception e) {441} finally {442try { server.close(); } catch (IOException unused) {}443}444}445}446public static void main(String[] args) throws Exception {447FtpURL test = new FtpURL();448}449450public FtpURL() throws Exception {451FtpServer server = new FtpServer(0);452BufferedReader in = null;453try {454server.start();455int port = server.getPort();456457// Now let's check the URL handler458459URL url = new URL("ftp://user:password@localhost:" + port + "/%2Fetc/motd;type=a");460URLConnection con = url.openConnection();461in = new BufferedReader(new InputStreamReader(con.getInputStream()));462String s;463do {464s = in.readLine();465} while (s != null);466if (!("user".equals(server.getUsername())))467throw new RuntimeException("Inccorect username received");468if (!("password".equals(server.getPassword())))469throw new RuntimeException("Inccorect password received");470if (!("/etc".equals(server.pwd())))471throw new RuntimeException("Inccorect directory received");472if (!("motd".equals(server.getFilename())))473throw new RuntimeException("Inccorect username received");474if (!("A".equals(server.getType())))475throw new RuntimeException("Incorrect type received");476477in.close();478// We're done!479480// Second URL test481port = server.getPort();482483// Now let's check the URL handler484485url = new URL("ftp://user2@localhost:" + port + "/%2Fusr/bin;type=d");486con = url.openConnection();487in = new BufferedReader(new InputStreamReader(con.getInputStream()));488do {489s = in.readLine();490} while (s != null);491if (!server.getList())492throw new RuntimeException(";type=d didn't generate a NLST");493if (server.getPassword() != null)494throw new RuntimeException("password should be null!");495if (! "bin".equals(server.getFilename()))496throw new RuntimeException("Incorrect filename received");497if (! "/usr".equals(server.pwd()))498throw new RuntimeException("Incorrect pwd received");499// We're done!500501} catch (Exception e) {502throw new RuntimeException("FTP support error: " + e.getMessage());503} finally {504try { in.close(); } catch (IOException unused) {}505server.terminate();506server.server.close();507}508}509}510511512