Merge cherrypicks of [2310999, 2310925, 2310891, 2311000, 2310892, 2310858, 2310986, 2310963, 2311043, 2310928, 2311044, 2310990, 2311022, 2311023, 2310917, 2310994, 2311024, 2311045, 2310967, 2310995, 2311003, 2311059, 2311025, 2311060, 2310953, 2311061, 2311004, 2311046, 2311005, 2311047, 2311006, 2311079, 2310954, 2311026, 2310896, 2310898, 2310997, 2311062, 2310955, 2311029, 2310998, 2311080, 2311119, 2311030, 2310933, 2311140, 2311063, 2310934, 2311049, 2311050, 2311084, 2311031, 2311145, 2311164] into nyc-mr2-security-c-release

Change-Id: Ibb41a00a5e88c741d66b14e399816a79d0f9a333
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 0000000..806ae73
--- /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 61c4a95..fea9421 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 @@
      * @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 @@
                 // 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 void close() throws IOException {
         if (isConnected()) {
-            issueCommand("QUIT");
+            try {
+                issueCommand("QUIT");
+            } catch (FtpProtocolException e) {
+            }
             loggedIn = false;
         }
         disconnect();
@@ -1899,7 +1909,8 @@
         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);