Fix unnecessary culture-aware comparisons in System.Net (dotnet/corefx#37499)
authorStephen Toub <stoub@microsoft.com>
Thu, 9 May 2019 00:24:41 +0000 (20:24 -0400)
committerGitHub <noreply@github.com>
Thu, 9 May 2019 00:24:41 +0000 (20:24 -0400)
- string.IndexOf(string) and string.IndexOf(string, int) are culture-aware.  For most situations in System.Net, that's undesirable and Ordinal is both more correct and faster.
- string.IndexOf("c", StringComparison.Ordinal) is better off as string.IndexOf('c') for perf and simplicity.
- string.IndexOf('c') >= 0 is better off as string.Contains('c') for perf and simplicity.

Commit migrated from https://github.com/dotnet/corefx/commit/6acc044c36df2138d86620e2c27d3234c4fa0d3d

src/libraries/System.Net.Http/src/System/Net/Http/CurlHandler/CurlResponseHeaderReader.cs
src/libraries/System.Net.Http/src/System/Net/Http/Headers/ContentDispositionHeaderValue.cs
src/libraries/System.Net.Http/src/System/Net/Http/MultipartContent.cs
src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.Digest.cs
src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpWindowsProxy.cs
src/libraries/System.Net.HttpListener/src/System/Net/ServiceNameStore.cs
src/libraries/System.Net.Requests/src/System/Net/FtpControlStream.cs
src/libraries/System.Net.Requests/src/System/Net/HttpWebRequest.cs
src/libraries/System.Net.Requests/src/System/Net/HttpWebResponse.cs
src/libraries/System.Net.WebProxy/src/System/Net/WebProxy.cs

index 474e5d0..d685836 100644 (file)
@@ -123,7 +123,7 @@ namespace System.Net.Http
         private static bool ValidHeaderNameChar(byte c)
         {
             const string invalidChars = "()<>@,;:\\\"/[]?={}";
-            return c > ' ' && invalidChars.IndexOf((char)c) < 0;
+            return c > ' ' && !invalidChars.Contains((char)c);
         }
 
         internal static bool IsWhiteSpaceLatin1(byte c)
index d38085a..5d8afc5 100644 (file)
@@ -435,7 +435,7 @@ namespace System.Net.Http.Headers
                 needsQuotes = true;
             }
 
-            if (result.IndexOf("\"", 0, StringComparison.Ordinal) >= 0) // Only bounding quotes are allowed.
+            if (result.Contains('"')) // Only bounding quotes are allowed.
             {
                 throw new ArgumentException(SR.Format(CultureInfo.InvariantCulture,
                     SR.net_http_headers_invalid_value, input));
index fed41a4..4cf988b 100644 (file)
@@ -96,7 +96,7 @@ namespace System.Net.Http
                 if (('0' <= ch && ch <= '9') || // Digit.
                     ('a' <= ch && ch <= 'z') || // alpha.
                     ('A' <= ch && ch <= 'Z') || // ALPHA.
-                    (AllowedMarks.IndexOf(ch) >= 0)) // Marks.
+                    (AllowedMarks.Contains(ch))) // Marks.
                 {
                     // Valid.
                 }
index b65b240..10723cc 100644 (file)
@@ -117,17 +117,17 @@ namespace System.Net.Http
             if (digestResponse.Parameters.ContainsKey(Qop))
             {
                 // Check if auth-int present in qop string
-                int index1 = digestResponse.Parameters[Qop].IndexOf(AuthInt);
+                int index1 = digestResponse.Parameters[Qop].IndexOf(AuthInt, StringComparison.Ordinal);
                 if (index1 != -1)
                 {
                     // Get index of auth if present in qop string
-                    int index2 = digestResponse.Parameters[Qop].IndexOf(Auth);
+                    int index2 = digestResponse.Parameters[Qop].IndexOf(Auth, StringComparison.Ordinal);
 
                     // If index2 < index1, auth option is available
                     // If index2 == index1, check if auth option available later in string after auth-int.
                     if (index2 == index1)
                     {
-                        index2 = digestResponse.Parameters[Qop].IndexOf(Auth, index1 + AuthInt.Length);
+                        index2 = digestResponse.Parameters[Qop].IndexOf(Auth, index1 + AuthInt.Length, StringComparison.Ordinal);
                         if (index2 == -1)
                         {
                             qop = AuthInt;
index 219a387..68d1034 100644 (file)
@@ -226,7 +226,7 @@ namespace System.Net.Http
                 return;
             }
 
-            int idx = value.IndexOf("http://");
+            int idx = value.IndexOf("http://", StringComparison.Ordinal);
             if (idx >= 0)
             {
                 int proxyLength = GetProxySubstringLength(value, idx);
@@ -235,7 +235,7 @@ namespace System.Net.Http
 
             if (insecureProxy == null)
             {
-                idx = value.IndexOf("http=");
+                idx = value.IndexOf("http=", StringComparison.Ordinal);
                 if (idx >= 0)
                 {
                     idx += 5; // Skip "http=" so we can replace it with "http://"
@@ -244,7 +244,7 @@ namespace System.Net.Http
                 }
             }
 
-            idx = value.IndexOf("https://");
+            idx = value.IndexOf("https://", StringComparison.Ordinal);
             if (idx >= 0)
             {
                 idx += 8; // Skip "https://" so we can replace it with "http://"
@@ -254,7 +254,7 @@ namespace System.Net.Http
 
             if (secureProxy == null)
             {
-                idx = value.IndexOf("https=");
+                idx = value.IndexOf("https=", StringComparison.Ordinal);
                 if (idx >= 0)
                 {
                     idx += 6; // Skip "https=" so we can replace it with "http://"
index 260955d..7eb26dc 100644 (file)
@@ -237,7 +237,7 @@ namespace System.Net
             }
             else if (allowInvalidUriStrings)
             {
-                int i = uriPrefix.IndexOf("://") + 3;
+                int i = uriPrefix.IndexOf("://", StringComparison.Ordinal) + 3;
                 int j = i;
 
                 bool inSquareBrackets = false;
index 6539ade..3045ed1 100644 (file)
@@ -283,7 +283,7 @@ namespace System.Net
             // If we are already logged in and the server returns 530 then
             // the server does not support re-issuing a USER command,
             // tear down the connection and start all over again
-            if (entry.Command.IndexOf("USER") != -1)
+            if (entry.Command.IndexOf("USER", StringComparison.Ordinal) != -1)
             {
                 // The server may not require a password for this user, so bypass the password command
                 if (status == FtpStatusCode.LoggedInProceed)
@@ -306,7 +306,7 @@ namespace System.Net
             }
 
             if (_loginState != FtpLoginState.LoggedIn
-                && entry.Command.IndexOf("PASS") != -1)
+                && entry.Command.IndexOf("PASS", StringComparison.Ordinal) != -1)
             {
                 // Note the fact that we logged in
                 if (status == FtpStatusCode.NeedLoginAccount || status == FtpStatusCode.LoggedInProceed)
@@ -412,11 +412,11 @@ namespace System.Net
             else if (status == FtpStatusCode.FileStatus)
             {
                 FtpWebRequest request = (FtpWebRequest)_request;
-                if (entry.Command.StartsWith("SIZE "))
+                if (entry.Command.StartsWith("SIZE ", StringComparison.Ordinal))
                 {
                     _contentLength = GetContentLengthFrom213Response(response.StatusDescription);
                 }
-                else if (entry.Command.StartsWith("MDTM "))
+                else if (entry.Command.StartsWith("MDTM ", StringComparison.Ordinal))
                 {
                     _lastModified = GetLastModifiedFrom213Response(response.StatusDescription);
                 }
@@ -433,7 +433,7 @@ namespace System.Net
             else
             {
                 // We only use CWD to reset ourselves back to the login directory.
-                if (entry.Command.IndexOf("CWD") != -1)
+                if (entry.Command.IndexOf("CWD", StringComparison.Ordinal) != -1)
                 {
                     _establishedServerDirectory = _requestedServerDirectory;
                 }
@@ -940,7 +940,7 @@ namespace System.Net
             //
             // Not sure what we are doing here but I guess the logic is IIS centric
             //
-            int start = str.IndexOf("for ");
+            int start = str.IndexOf("for ", StringComparison.Ordinal);
             if (start == -1)
                 return;
             start += 4;
@@ -991,10 +991,10 @@ namespace System.Net
         /// </summary>
         private void TryUpdateContentLength(string str)
         {
-            int pos1 = str.LastIndexOf("(");
+            int pos1 = str.LastIndexOf('(');
             if (pos1 != -1)
             {
-                int pos2 = str.IndexOf(" bytes).");
+                int pos2 = str.IndexOf(" bytes).", StringComparison.Ordinal);
                 if (pos2 != -1 && pos2 > pos1)
                 {
                     pos1++;
@@ -1056,8 +1056,8 @@ namespace System.Net
         /// </summary>
         private int GetPortV6(string responseString)
         {
-            int pos1 = responseString.LastIndexOf("(");
-            int pos2 = responseString.LastIndexOf(")");
+            int pos1 = responseString.LastIndexOf('(');
+            int pos2 = responseString.LastIndexOf(')');
             if (pos1 == -1 || pos2 <= pos1)
                 throw new FormatException(SR.Format(SR.net_ftp_response_invalid_format, responseString));
 
@@ -1196,7 +1196,7 @@ namespace System.Net
             // FTP protocol for multiline responses.
             // All other cases indicate that the response is not yet complete.
             int index = 0;
-            while ((index = responseString.IndexOf("\r\n", validThrough)) != -1)  // gets the end line.
+            while ((index = responseString.IndexOf("\r\n", validThrough, StringComparison.Ordinal)) != -1)  // gets the end line.
             {
                 int lineStart = validThrough;
                 validThrough = index + 2;  // validThrough now marks the end of the line being examined.
index bbe72db..77a31bf 100644 (file)
@@ -394,8 +394,7 @@ namespace System.Net
                     //
                     // if not check if the user is trying to set chunked:
                     //
-                    string newValue = value.ToLower();
-                    fChunked = (newValue.IndexOf(ChunkedHeader) != -1);
+                    fChunked = (value.IndexOf(ChunkedHeader, StringComparison.OrdinalIgnoreCase) != -1);
 
                     //
                     // prevent them from adding chunked, or from adding an Encoding without
@@ -539,10 +538,8 @@ namespace System.Net
                         return;
                     }
 
-                    string newValue = value.ToLower();
-
-                    fKeepAlive = (newValue.IndexOf("keep-alive") != -1);
-                    fClose = (newValue.IndexOf("close") != -1);
+                    fKeepAlive = (value.IndexOf("keep-alive", StringComparison.OrdinalIgnoreCase) != -1);
+                    fClose = (value.IndexOf("close", StringComparison.OrdinalIgnoreCase) != -1);
 
                     //
                     // Prevent keep-alive and close from being added
@@ -603,9 +600,7 @@ namespace System.Net
                     // Prevent 100-continues from being added
                     //
 
-                    string newValue = value.ToLower();
-
-                    fContinue100 = (newValue.IndexOf(ContinueHeader) != -1);
+                    fContinue100 = (value.IndexOf(ContinueHeader, StringComparison.OrdinalIgnoreCase) != -1);
 
                     if (fContinue100)
                     {
index 7b63ed4..1bbb996 100644 (file)
@@ -275,18 +275,18 @@ namespace System.Net
                     string srchString = contentType.ToLower();
 
                     //media subtypes of text type has a default as specified by rfc 2616
-                    if (srchString.Trim().StartsWith("text/"))
+                    if (srchString.Trim().StartsWith("text/", StringComparison.Ordinal))
                     {
                         _characterSet = "ISO-8859-1";
                     }
 
                     //one of the parameters may be the character set
                     //there must be at least a mediatype for this to be valid
-                    int i = srchString.IndexOf(";");
+                    int i = srchString.IndexOf(';');
                     if (i > 0)
                     {
                         //search the parameters
-                        while ((i = srchString.IndexOf("charset", i)) >= 0)
+                        while ((i = srchString.IndexOf("charset", i, StringComparison.Ordinal)) >= 0)
                         {
                             i += 7;
 
index a97631f..686a1b9 100644 (file)
@@ -96,7 +96,7 @@ namespace System.Net
 
         private static Uri CreateProxyUri(string address) =>
             address == null ? null :
-            address.IndexOf("://") == -1 ? new Uri("http://" + address) :
+            address.IndexOf("://", StringComparison.Ordinal) == -1 ? new Uri("http://" + address) :
             new Uri(address);
 
         private void UpdateRegExList(bool canThrow)