From 0d4ff874df17c5ad482c93e2b445eafce1a9cc8b Mon Sep 17 00:00:00 2001 From: Saurabh Singh Date: Sun, 19 Mar 2017 12:15:19 -0700 Subject: [PATCH 1/3] Allow . as hostname in pipe names --- .../src/System/Data/SqlClient/SNI/SNIProxy.cs | 34 +++++++++++++------ .../tests/FunctionalTests/ExceptionTest.cs | 20 +++++++++++ 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIProxy.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIProxy.cs index 6880bc187321..c4e51dae0ec4 100644 --- a/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIProxy.cs +++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIProxy.cs @@ -786,32 +786,44 @@ private bool InferNamedPipesInformation() try { - Uri uri = new Uri(_dataSourceAfterTrimmingProtocol); - if (string.IsNullOrEmpty(uri.Host)) + string[] tokensByBackSlash = _dataSourceAfterTrimmingProtocol.Split(BackSlashSeparator); + + // The datasource is of the format \\host\pipe\sql\query [0]\[1]\[2]\[3]\[4]\[5] + // It would at least have 6 parts. + // Another valid Sql named pipe for an named instance is \\.\pipe\MSSQL$MYINSTANCE\sql\query + if (tokensByBackSlash.Length < 6) { ReportSNIError(SNIProviders.NP_PROV); return false; } - string[] absolutePathParts = uri.AbsolutePath.Split(ForwardSlashSeparator); + string host = tokensByBackSlash[2]; - //Check if the "pipe" keyword is the first part of path - if (PipeToken.CompareTo(absolutePathParts[1]) != 0) + if (string.IsNullOrEmpty(host)) { ReportSNIError(SNIProviders.NP_PROV); return false; } - // There should be at least 4 parts in the pipename e.g /pipe/sql/query [0]/[1]/[2]/[3] - // Another valid Sql named pipe for an named instance is \\.\pipe\MSSQL$MYINSTANCE\sql\query - if (absolutePathParts.Length < 4) + //Check if the "pipe" keyword is the first part of path + if (!PipeToken.Equals(tokensByBackSlash[3])) { ReportSNIError(SNIProviders.NP_PROV); return false; } - PipeName = uri.AbsolutePath.Substring(PipeToken.Length + 2); - ServerName = IsLocalHost(uri.Host) ? Environment.MachineName : uri.Host; + StringBuilder pipeNameBuilder = new StringBuilder(); + + for ( int i = 4; i < tokensByBackSlash.Length-1; i++) + { + pipeNameBuilder.Append(tokensByBackSlash[i]); + pipeNameBuilder.Append(ForwardSlashSeparator); + } + // Append the last part without a "/" + pipeNameBuilder.Append(tokensByBackSlash[tokensByBackSlash.Length - 1]); + + PipeName = pipeNameBuilder.ToString(); + ServerName = IsLocalHost(host) ? Environment.MachineName : host; } catch (UriFormatException) { @@ -820,7 +832,7 @@ private bool InferNamedPipesInformation() } // DataSource is something like "\\pipename" - if (ConnectionProtocol != DataSource.Protocol.None) + if (ConnectionProtocol == DataSource.Protocol.None) { ConnectionProtocol = DataSource.Protocol.NP; } diff --git a/src/System.Data.SqlClient/tests/FunctionalTests/ExceptionTest.cs b/src/System.Data.SqlClient/tests/FunctionalTests/ExceptionTest.cs index f0e72bdc85b3..5197252d6a5b 100644 --- a/src/System.Data.SqlClient/tests/FunctionalTests/ExceptionTest.cs +++ b/src/System.Data.SqlClient/tests/FunctionalTests/ExceptionTest.cs @@ -76,6 +76,26 @@ public void IndependentConnectionExceptionTestExecuteReader() } } + [Theory] + [InlineData(@"np:\\.\pipe\sqlbad\query")] + [InlineData(@"np:\\.\pipe\MSSQL$NonExistentInstance\sql\query")] + [InlineData(@"\\.\pipe\sqlbad\query")] + [InlineData(@"\\.\pipe\MSSQL$NonExistentInstance\sql\query")] + [InlineData(@"np:\\localhost\pipe\sqlbad\query")] + [InlineData(@"np:\\localhost\pipe\MSSQL$NonExistentInstance\sqlbad\query")] + [InlineData(@"\\localhost\pipe\sqlbad\query")] + [InlineData(@"\\localhost\pipe\MSSQL$NonExistentInstance\sqlbad\query")] + public void NamedPipeTest(string dataSource) + { + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); + builder.DataSource = dataSource; + builder.ConnectTimeout = 1; + using(SqlConnection connection = new SqlConnection(builder.ConnectionString)) + { + VerifyConnectionFailure(() => connection.Open(), "(provider: Named Pipes Provider, error: 11 - Timeout error)"); + } + } + private void GenerateConnectionException(string connectionString) { using (SqlConnection sqlConnection = new SqlConnection(connectionString)) From 12628d23f01eca43f28b907c091bd223045680aa Mon Sep 17 00:00:00 2001 From: Saurabh Singh Date: Sun, 19 Mar 2017 14:14:56 -0700 Subject: [PATCH 2/3] Make NP test platform specific --- src/System.Data.SqlClient/tests/FunctionalTests/ExceptionTest.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/System.Data.SqlClient/tests/FunctionalTests/ExceptionTest.cs b/src/System.Data.SqlClient/tests/FunctionalTests/ExceptionTest.cs index 5197252d6a5b..5d30613835fc 100644 --- a/src/System.Data.SqlClient/tests/FunctionalTests/ExceptionTest.cs +++ b/src/System.Data.SqlClient/tests/FunctionalTests/ExceptionTest.cs @@ -85,6 +85,7 @@ public void IndependentConnectionExceptionTestExecuteReader() [InlineData(@"np:\\localhost\pipe\MSSQL$NonExistentInstance\sqlbad\query")] [InlineData(@"\\localhost\pipe\sqlbad\query")] [InlineData(@"\\localhost\pipe\MSSQL$NonExistentInstance\sqlbad\query")] + [PlatformSpecific(TestPlatforms.Windows)] // Named pipes with the given input strings are not supported on Unix public void NamedPipeTest(string dataSource) { SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); From b36361a8fd56f7d8f15f6fbe9d89d9010267ec4b Mon Sep 17 00:00:00 2001 From: Saurabh Singh Date: Sun, 19 Mar 2017 14:24:28 -0700 Subject: [PATCH 3/3] Use the path separator so that the NamedPipes can get the appropriate path --- .../src/System/Data/SqlClient/SNI/SNIProxy.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIProxy.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIProxy.cs index c4e51dae0ec4..26b590c8f17a 100644 --- a/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIProxy.cs +++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIProxy.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net; @@ -10,9 +9,7 @@ using System.Net.Sockets; using System.Text; using System.Threading.Tasks; -using System; -using System.Threading; -using System.Collections; +using System.IO; namespace System.Data.SqlClient.SNI { @@ -575,7 +572,6 @@ internal class DataSource private const char CommaSeparator = ','; private const char BackSlashSeparator = '\\'; - private const char ForwardSlashSeparator = '/'; private const string DefaultHostName = "localhost"; private const string DefaultSqlServerInstanceName = "mssqlserver"; private const string PipeBeginning = @"\\"; @@ -817,7 +813,7 @@ private bool InferNamedPipesInformation() for ( int i = 4; i < tokensByBackSlash.Length-1; i++) { pipeNameBuilder.Append(tokensByBackSlash[i]); - pipeNameBuilder.Append(ForwardSlashSeparator); + pipeNameBuilder.Append(Path.PathSeparator); } // Append the last part without a "/" pipeNameBuilder.Append(tokensByBackSlash[tokensByBackSlash.Length - 1]);