diff options
-rw-r--r-- | luni/src/test/java/libcore/java/net/FtpURLConnectionTest.java | 85 | ||||
-rwxr-xr-x | ojluni/src/main/java/sun/net/ftp/impl/FtpClient.java | 19 |
2 files changed, 100 insertions, 4 deletions
diff --git a/luni/src/test/java/libcore/java/net/FtpURLConnectionTest.java b/luni/src/test/java/libcore/java/net/FtpURLConnectionTest.java new file mode 100644 index 00000000000..806ae73fb0f --- /dev/null +++ b/luni/src/test/java/libcore/java/net/FtpURLConnectionTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package libcore.java.net; + +import junit.framework.TestCase; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URL; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import sun.net.ftp.FtpLoginException; + +/** + * Tests URLConnections for ftp:// URLs. + */ +public class FtpURLConnectionTest extends TestCase { + + private static final String FILE_PATH = "test/file/for/FtpURLConnectionTest.txt"; + private static final String SERVER_HOSTNAME = "localhost"; + + // http://b/35784677 + public void testCRLFInUserinfo() throws Exception { + List<String> encodedUserInfos = Arrays.asList( + // '\r\n' in the username with password + "user%0D%0Acommand:password", + // '\r\n' in the password + "user:password%0D%0Acommand", + // just '\n' in the password + "user:password%0Acommand", + // just '\n' in the username + "user%0Acommand:password" + ); + for (String encodedUserInfo : encodedUserInfos) { + ExecutorService executor = Executors.newSingleThreadExecutor(); + ServerSocket mockFtpServerSocket = new ServerSocket(0); + Future<Void> future = executor.submit(new Callable<Void>() { + @Override public Void call() throws Exception { + Socket clientSocket = mockFtpServerSocket.accept(); + clientSocket.getOutputStream().write("220 o/".getBytes()); + clientSocket.close(); + return null; + } + }); + executor.shutdown(); + + String urlString = String.format(Locale.US, "ftp://%s@%s:%s/%s", + encodedUserInfo, SERVER_HOSTNAME, mockFtpServerSocket.getLocalPort(), FILE_PATH); + try { + new URL(urlString).openConnection().connect(); + fail("Connection shouldn't have succeeded: " + urlString); + } catch (FtpLoginException expected) { + // The original message "Illegal carriage return" gets lost + // where FtpURLConnection.connect() translates the + // original FtpProtocolException into FtpLoginException. + assertEquals("Invalid username/password", expected.getMessage()); + } + + // Cleanup + future.get(); + mockFtpServerSocket.close(); + } + } +} diff --git a/ojluni/src/main/java/sun/net/ftp/impl/FtpClient.java b/ojluni/src/main/java/sun/net/ftp/impl/FtpClient.java index 61c4a95ea41..fea94218b7a 100755 --- a/ojluni/src/main/java/sun/net/ftp/impl/FtpClient.java +++ b/ojluni/src/main/java/sun/net/ftp/impl/FtpClient.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2017, 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 @@ -518,7 +518,8 @@ public class FtpClient extends sun.net.ftp.FtpClient { * @return <code>true</code> if the command was successful * @throws IOException */ - private boolean issueCommand(String cmd) throws IOException { + private boolean issueCommand(String cmd) throws IOException, + sun.net.ftp.FtpProtocolException { if (!isConnected()) { throw new IllegalStateException("Not connected"); } @@ -529,6 +530,12 @@ public class FtpClient extends sun.net.ftp.FtpClient { // ignore... } } + if (cmd.indexOf('\n') != -1) { + sun.net.ftp.FtpProtocolException ex + = new sun.net.ftp.FtpProtocolException("Illegal FTP command"); + ex.initCause(new IllegalArgumentException("Illegal carriage return")); + throw ex; + } sendServer(cmd + "\r\n"); return readReply(); } @@ -1121,7 +1128,10 @@ public class FtpClient extends sun.net.ftp.FtpClient { */ public void close() throws IOException { if (isConnected()) { - issueCommand("QUIT"); + try { + issueCommand("QUIT"); + } catch (FtpProtocolException e) { + } loggedIn = false; } disconnect(); @@ -1899,7 +1909,8 @@ public class FtpClient extends sun.net.ftp.FtpClient { return null; } - private boolean sendSecurityData(byte[] buf) throws IOException { + private boolean sendSecurityData(byte[] buf) throws IOException, + sun.net.ftp.FtpProtocolException { BASE64Encoder encoder = new BASE64Encoder(); String s = encoder.encode(buf); return issueCommand("ADAT " + s); |