Path: blob/master/test/jdk/sun/net/ftp/FtpGetContent.java
41149 views
/*1* Copyright (c) 2001, 2019, 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 425528029* @summary URL.getContent() loses first six bytes for ftp URLs30* @run main FtpGetContent31* @run main/othervm -Djava.net.preferIPv6Addresses=true FtpGetContent32*/3334public class FtpGetContent {35static int filesize = 2048;3637/**38* A class that simulates, on a separate, an FTP server.39*/4041private class FtpServer extends Thread {42private final ServerSocket server;43private int port;44private boolean done = false;45private boolean portEnabled = true;46private boolean pasvEnabled = true;47private boolean extendedEnabled = true;48private String username;49private String password;50private String cwd;51private String filename;52private String type;53private boolean list = false;5455/**56* This Inner class will handle ONE client at a time.57* That's where 99% of the protocol handling is done.58*/5960private class FtpServerHandler extends Thread {61BufferedReader in;62PrintWriter out;63Socket client;64private final int ERROR = 0;65private final int USER = 1;66private final int PASS = 2;67private final int CWD = 3;68private final int CDUP = 4;69private final int PWD = 5;70private final int TYPE = 6;71private final int NOOP = 7;72private final int RETR = 8;73private final int PASV = 9;74private final int PORT = 10;75private final int LIST = 11;76private final int REIN = 12;77private final int QUIT = 13;78private final int STOR = 14;79private final int NLST = 15;80private final int RNFR = 16;81private final int RNTO = 17;82private final int EPSV = 18;83String[] cmds = { "USER", "PASS", "CWD", "CDUP", "PWD", "TYPE",84"NOOP", "RETR", "PASV", "PORT", "LIST", "REIN",85"QUIT", "STOR", "NLST", "RNFR", "RNTO", "EPSV"};86private String arg = null;87private ServerSocket pasv = null;88private int data_port = 0;89private InetAddress data_addr = null;9091/**92* Parses a line to match it with one of the supported FTP commands.93* Returns the command number.94*/9596private int parseCmd(String cmd) {97System.out.println("FTP server received command: " + cmd);98if (cmd == null || cmd.length() < 3)99return ERROR;100int blank = cmd.indexOf(' ');101if (blank < 0)102blank = cmd.length();103if (blank < 3)104return ERROR;105String s = cmd.substring(0, blank);106if (cmd.length() > blank+1)107arg = cmd.substring(blank+1, cmd.length());108else109arg = null;110for (int i = 0; i < cmds.length; i++) {111if (s.equalsIgnoreCase(cmds[i]))112return i+1;113}114return ERROR;115}116117public FtpServerHandler(Socket cl) {118client = cl;119}120121protected boolean isPasvSet() {122if (pasv != null && !pasvEnabled) {123try {124pasv.close();125} catch (IOException ex) {126}127pasv = null;128}129if (pasvEnabled && pasv != null)130return true;131return false;132}133134/**135* Open the data socket with the client. This can be the136* result of a "PASV" or "PORT" command.137*/138139protected OutputStream getOutDataStream() {140try {141if (isPasvSet()) {142Socket s = pasv.accept();143return s.getOutputStream();144}145if (data_addr != null) {146Socket s = new Socket(data_addr, data_port);147data_addr = null;148data_port = 0;149return s.getOutputStream();150}151} catch (Exception e) {152e.printStackTrace();153}154return null;155}156157protected InputStream getInDataStream() {158try {159if (isPasvSet()) {160Socket s = pasv.accept();161return s.getInputStream();162}163if (data_addr != null) {164Socket s = new Socket(data_addr, data_port);165data_addr = null;166data_port = 0;167return s.getInputStream();168}169} catch (Exception e) {170e.printStackTrace();171}172return null;173}174175/**176* Handles the protocol exchange with the client.177*/178179public void run() {180boolean done = false;181String str;182int res;183boolean logged = false;184boolean waitpass = false;185186try {187in = new BufferedReader(new InputStreamReader(client.getInputStream()));188out = new PrintWriter(client.getOutputStream(), true);189out.println("220 tatooine FTP server (SunOS 5.8) ready.");190} catch (Exception ex) {191return;192}193while (!done) {194try {195str = in.readLine();196res = parseCmd(str);197if ((res > PASS && res != QUIT) && !logged) {198out.println("530 Not logged in.");199continue;200}201switch (res) {202case ERROR:203out.println("500 '" + str + "': command not understood.");204break;205case USER:206if (!logged && !waitpass) {207username = str.substring(5);208password = null;209cwd = null;210if ("user2".equals(username)) {211out.println("230 Guest login ok, access restrictions apply.");212logged = true;213} else {214out.println("331 Password required for " + arg);215waitpass = true;216}217} else {218out.println("503 Bad sequence of commands.");219}220break;221case PASS:222if (!logged && waitpass) {223out.println("230 Guest login ok, access restrictions apply.");224password = str.substring(5);225logged = true;226waitpass = false;227} else228out.println("503 Bad sequence of commands.");229break;230case QUIT:231out.println("221 Goodbye.");232out.flush();233out.close();234if (pasv != null)235pasv.close();236done = true;237break;238case TYPE:239out.println("200 Type set to " + arg + ".");240type = arg;241break;242case CWD:243out.println("250 CWD command successful.");244if (cwd == null)245cwd = str.substring(4);246else247cwd = cwd + "/" + str.substring(4);248break;249case CDUP:250out.println("250 CWD command successful.");251break;252case PWD:253out.println("257 \"" + cwd + "\" is current directory");254break;255case EPSV:256if (!extendedEnabled || !pasvEnabled) {257out.println("500 EPSV is disabled, " +258"use PORT instead.");259continue;260}261if (!(server.getInetAddress() instanceof Inet6Address)) {262// pretend EPSV is not implemented263out.println("500 '" + str + "': command not understood.");264break;265}266if ("all".equalsIgnoreCase(arg)) {267out.println("200 EPSV ALL command successful.");268continue;269}270try {271if (pasv == null)272pasv = new ServerSocket(0, 0, server.getInetAddress());273int port = pasv.getLocalPort();274out.println("229 Entering Extended" +275" Passive Mode (|||" + port + "|)");276} catch (IOException ssex) {277out.println("425 Can't build data connection:" +278" Connection refused.");279}280break;281case PASV:282if (!pasvEnabled) {283out.println("500 PASV is disabled, use PORT instead.");284continue;285}286try {287if (pasv == null) {288pasv = new ServerSocket();289pasv.bind(new InetSocketAddress("127.0.0.1", 0));290}291int port = pasv.getLocalPort();292out.println("227 Entering Passive Mode (127,0,0,1," +293(port >> 8) + "," + (port & 0xff) +")");294} catch (IOException ssex) {295out.println("425 Can't build data connection: Connection refused.");296}297break;298case PORT:299if (!portEnabled) {300out.println("500 PORT is disabled, use PASV instead");301continue;302}303StringBuffer host;304int i=0, j=4;305while (j>0) {306i = arg.indexOf(',', i+1);307if (i < 0)308break;309j--;310}311if (j != 0) {312out.println("500 '" + arg + "': command not understood.");313continue;314}315try {316host = new StringBuffer(arg.substring(0,i));317for (j=0; j < host.length(); j++)318if (host.charAt(j) == ',')319host.setCharAt(j, '.');320String ports = arg.substring(i+1);321i = ports.indexOf(',');322data_port = Integer.parseInt(ports.substring(0,i)) << 8;323data_port += (Integer.parseInt(ports.substring(i+1)));324data_addr = InetAddress.getByName(host.toString());325out.println("200 Command okay.");326} catch (Exception ex3) {327data_port = 0;328data_addr = null;329out.println("500 '" + arg + "': command not understood.");330}331break;332case RETR:333{334filename = str.substring(5);335OutputStream dout = getOutDataStream();336if (dout != null) {337out.println("200 Command okay.");338BufferedOutputStream pout = new BufferedOutputStream(dout);339for (int x = 0; x < filesize ; x++)340pout.write(0);341pout.flush();342pout.close();343list = false;344} else345out.println("425 Can't build data connection: Connection refused.");346}347break;348case NLST:349filename = arg;350case LIST:351{352OutputStream dout = getOutDataStream();353if (dout != null) {354out.println("200 Command okay.");355PrintWriter pout = new PrintWriter(new BufferedOutputStream(dout));356pout.println("total 130");357pout.println("drwxrwxrwt 7 sys sys 577 May 12 03:30 .");358pout.println("drwxr-xr-x 39 root root 1024 Mar 27 12:55 ..");359pout.println("drwxrwxr-x 2 root root 176 Apr 10 12:02 .X11-pipe");360pout.println("drwxrwxr-x 2 root root 176 Apr 10 12:02 .X11-unix");361pout.println("drwxrwxrwx 2 root root 179 Mar 30 15:09 .pcmcia");362pout.println("drwxrwxrwx 2 jladen staff 117 Mar 30 18:18 .removable");363pout.println("drwxrwxrwt 2 root root 327 Mar 30 15:08 .rpc_door");364pout.println("-rw-r--r-- 1 root other 21 May 5 16:59 hello2.txt");365pout.println("-rw-rw-r-- 1 root sys 5968 Mar 30 15:08 ps_data");366pout.flush();367pout.close();368list = true;369} else370out.println("425 Can't build data connection: Connection refused.");371}372break;373case STOR:374{375InputStream is = getInDataStream();376if (is != null) {377out.println("200 Command okay.");378BufferedInputStream din = new BufferedInputStream(is);379int val;380do {381val = din.read();382} while (val != -1);383din.close();384} else385out.println("425 Can't build data connection: Connection refused.");386}387break;388}389} catch (IOException ioe) {390ioe.printStackTrace();391try {392out.close();393} catch (Exception ex2) {394}395done = true;396}397}398}399}400401public FtpServer(int port) {402this(null, 0);403}404405public FtpServer(InetAddress address, int port) {406this.port = port;407try {408server = new ServerSocket();409server.bind(new InetSocketAddress(address, port));410} catch (IOException e) {411throw new RuntimeException(e);412}413}414415public FtpServer() {416this(21);417}418419public int getPort() {420if (server != null)421return server.getLocalPort();422return 0;423}424425public String getAuthority() {426InetAddress address = server.getInetAddress();427String hostaddr = address.isAnyLocalAddress()428? "localhost" : address.getHostAddress();429if (hostaddr.indexOf(':') > -1) {430hostaddr = "[" + hostaddr +"]";431}432return hostaddr + ":" + getPort();433}434435/**436* A way to tell the server that it can stop.437*/438synchronized public void terminate() {439done = true;440}441442synchronized boolean done() {443return done;444}445446synchronized public void setPortEnabled(boolean ok) {447portEnabled = ok;448}449450synchronized public void setPasvEnabled(boolean ok) {451pasvEnabled = ok;452}453454String getUsername() {455return username;456}457458String getPassword() {459return password;460}461462String pwd() {463return cwd;464}465466String getFilename() {467return filename;468}469470String getType() {471return type;472}473474boolean getList() {475return list;476}477478/*479* All we got to do here is create a ServerSocket and wait for connections.480* When a connection happens, we just have to create a thread that will481* handle it.482*/483public void run() {484try {485Socket client;486while (!done()) {487client = server.accept();488(new FtpServerHandler(client)).start();489}490} catch(Exception e) {491} finally {492try { server.close(); } catch (IOException unused) {}493}494}495}496public static void main(String[] args) throws Exception {497FtpGetContent test = new FtpGetContent();498}499500public FtpGetContent() throws Exception {501FtpServer server = null;502try {503InetAddress loopback = InetAddress.getLoopbackAddress();504server = new FtpServer(loopback, 0);505server.start();506String authority = server.getAuthority();507508// Now let's check the URL handler509510URL url = new URL("ftp://" + authority + "/pub/BigFile");511InputStream stream = (InputStream)url.openConnection(Proxy.NO_PROXY)512.getContent();513byte[] buffer = new byte[1024];514int totalBytes = 0;515int bytesRead = stream.read(buffer);516while (bytesRead != -1) {517totalBytes += bytesRead;518bytesRead = stream.read(buffer);519}520stream.close();521if (totalBytes != filesize)522throw new RuntimeException("wrong file size!");523} catch (IOException e) {524throw new RuntimeException(e.getMessage());525} finally {526server.terminate();527server.server.close();528}529}530}531532533