diff --git a/src/libraries/System.Net.Requests/src/Resources/Strings.resx b/src/libraries/System.Net.Requests/src/Resources/Strings.resx
index e746e70fefa499..4919a50fbaa0a8 100644
--- a/src/libraries/System.Net.Requests/src/Resources/Strings.resx
+++ b/src/libraries/System.Net.Requests/src/Resources/Strings.resx
@@ -196,7 +196,7 @@
The underlying connection was closed: An unexpected error occurred on a receive
- CRLF character pair is not allowed in FtpWebRequest inputs.
+ CR and LF characters are not allowed in FtpWebRequest inputs.
The remote name could not be resolved
diff --git a/src/libraries/System.Net.Requests/src/System/Net/FtpControlStream.cs b/src/libraries/System.Net.Requests/src/System/Net/FtpControlStream.cs
index ba72c6f8a9dc76..6673d8483ec158 100644
--- a/src/libraries/System.Net.Requests/src/System/Net/FtpControlStream.cs
+++ b/src/libraries/System.Net.Requests/src/System/Net/FtpControlStream.cs
@@ -1147,7 +1147,7 @@ private string GetPortCommandLine()
///
private static string FormatFtpCommand(string command, string? parameter)
{
- if (parameter is not null && parameter.Contains("\r\n", StringComparison.Ordinal))
+ if (parameter is not null && parameter.AsSpan().ContainsAny('\r', '\n'))
{
throw new FormatException(SR.net_ftp_no_newlines);
}
diff --git a/src/libraries/System.Net.Requests/src/System/Net/FtpWebRequest.cs b/src/libraries/System.Net.Requests/src/System/Net/FtpWebRequest.cs
index f470879e993e41..91b95a5eea6604 100644
--- a/src/libraries/System.Net.Requests/src/System/Net/FtpWebRequest.cs
+++ b/src/libraries/System.Net.Requests/src/System/Net/FtpWebRequest.cs
@@ -487,7 +487,9 @@ internal FtpWebRequest(Uri uri)
if ((object)uri.Scheme != (object)Uri.UriSchemeFtp)
throw new ArgumentOutOfRangeException(nameof(uri));
- if (uri.OriginalString.Contains("\r\n", StringComparison.Ordinal))
+ if (uri.OriginalString.AsSpan().ContainsAny('\r', '\n') ||
+ uri.OriginalString.Contains("%0A", StringComparison.OrdinalIgnoreCase) ||
+ uri.OriginalString.Contains("%0D", StringComparison.OrdinalIgnoreCase))
throw new FormatException(SR.net_ftp_no_newlines);
_timerCallback = new TimerThread.Callback(TimerCallback);
diff --git a/src/libraries/System.Net.Requests/tests/FtpWebRequestTest.cs b/src/libraries/System.Net.Requests/tests/FtpWebRequestTest.cs
index 5401b1e93ebbb7..aae99260d14301 100644
--- a/src/libraries/System.Net.Requests/tests/FtpWebRequestTest.cs
+++ b/src/libraries/System.Net.Requests/tests/FtpWebRequestTest.cs
@@ -29,6 +29,23 @@ public FtpExecutionMode(bool useSsl, bool usePassive, bool useAsync, bool useOld
}
}
+ [Theory]
+ [InlineData("ftp://foo.com/bar\r\nbaz")]
+ [InlineData("ftp://foo.com/bar\rbaz")]
+ [InlineData("ftp://foo.com/bar\nbaz")]
+ [InlineData("ftp://foo.com/bar%0D%0Abaz")]
+ [InlineData("ftp://foo.com/bar%0d%0abaz")]
+ [InlineData("ftp://foo.com/bar%0D%0abaz")]
+ [InlineData("ftp://foo.com/bar%0Dbaz")]
+ [InlineData("ftp://foo.com/bar%0dbaz")]
+ [InlineData("ftp://foo.com/bar%0Abaz")]
+ [InlineData("ftp://foo.com/bar%0abaz")]
+ public void Ctor_NewLineInUri_ThrowsFormatException(string uriString)
+ {
+ Uri uri = new Uri(uriString, UriKind.Absolute);
+ Assert.Throws(() => WebRequest.Create(uri));
+ }
+
[Fact]
public void Ctor_VerifyDefaults_Success()
{
@@ -211,12 +228,15 @@ public void Ftp_Ignore_NewLine_Constructor_Throws_FormatException()
Assert.Throws(() => WebRequest.Create($"{uri}\r\n{WebRequestMethods.Ftp.AppendFile} {Guid.NewGuid().ToString()}"));
}
- [ConditionalFact(typeof(FtpWebRequestTest), nameof(LocalServerAvailable))]
- public void Ftp_Ignore_NewLine_GetRequestStream_And_GetResponse_Throws_FormatException_As_InnerException()
+ [ConditionalTheory(typeof(FtpWebRequestTest), nameof(LocalServerAvailable))]
+ [InlineData("test\r\ntest2")]
+ [InlineData("test\rtest2")]
+ [InlineData("test\ntest2")]
+ public void Ftp_Ignore_NewLine_GetRequestStream_And_GetResponse_Throws_FormatException_As_InnerException(string credential)
{
FtpWebRequest ftpWebRequest = (FtpWebRequest)WebRequest.Create(absoluteUri + Guid.NewGuid().ToString());
ftpWebRequest.Method = "APPE";
- ftpWebRequest.Credentials = new NetworkCredential("test\r\ntest2", "test\r\ntest2");
+ ftpWebRequest.Credentials = new NetworkCredential(credential, credential);
var requestException = Assert.Throws(() => ftpWebRequest.GetRequestStream());
Assert.True(requestException.InnerException is FormatException);
@@ -224,6 +244,20 @@ public void Ftp_Ignore_NewLine_GetRequestStream_And_GetResponse_Throws_FormatExc
Assert.True(responseException.InnerException is FormatException);
}
+ [ConditionalTheory(typeof(FtpWebRequestTest), nameof(LocalServerAvailable))]
+ [InlineData("ok\r\nbad")]
+ [InlineData("ok\rbad")]
+ [InlineData("ok\nbad")]
+ public void Ftp_NewLineInRenameTo_GetResponse_Throws_FormatException_As_InnerException(string renameTo)
+ {
+ FtpWebRequest request = (FtpWebRequest)WebRequest.Create(absoluteUri + Guid.NewGuid().ToString());
+ request.Method = WebRequestMethods.Ftp.Rename;
+ request.RenameTo = renameTo;
+
+ WebException ex = Assert.Throws(() => request.GetResponse());
+ Assert.IsType(ex.InnerException);
+ }
+
private static async Task DoAsync(FtpWebRequest request, MemoryStream requestBody)
{
if (requestBody != null)