44using System . IO ;
55using System . Linq ;
66using System . Security . Cryptography . X509Certificates ;
7+ using System . Text ;
78
89namespace Elasticsearch . Net
910{
@@ -42,10 +43,17 @@ IMemoryStreamFactory memoryStreamFactory
4243 HttpCompression = global . EnableHttpCompression ;
4344 RequestMimeType = local ? . ContentType ?? MimeType ;
4445 Accept = local ? . Accept ?? MimeType ;
45- Headers = global . Headers != null ? new NameValueCollection ( global . Headers ) : new NameValueCollection ( ) ;
46+
47+ if ( global . Headers != null )
48+ Headers = new NameValueCollection ( global . Headers ) ;
4649
4750 if ( ! string . IsNullOrEmpty ( local ? . OpaqueId ) )
51+ {
52+ if ( Headers == null )
53+ Headers = new NameValueCollection ( ) ;
54+
4855 Headers . Add ( OpaqueIdHeader , local . OpaqueId ) ;
56+ }
4957
5058 RunAs = local ? . RunAs ;
5159 SkipDeserializationForStatusCodes = global ? . SkipDeserializationForStatusCodes ;
@@ -54,7 +62,7 @@ IMemoryStreamFactory memoryStreamFactory
5462 RequestTimeout = local ? . RequestTimeout ?? global . RequestTimeout ;
5563 PingTimeout =
5664 local ? . PingTimeout
57- ?? global ? . PingTimeout
65+ ?? global . PingTimeout
5866 ?? ( global . ConnectionPool . UsingSsl ? ConnectionConfiguration . DefaultPingTimeoutOnSSL : ConnectionConfiguration . DefaultPingTimeout ) ;
5967
6068 KeepAliveInterval = ( int ) ( global . KeepAliveInterval ? . TotalMilliseconds ?? 2000 ) ;
@@ -86,7 +94,7 @@ IMemoryStreamFactory memoryStreamFactory
8694 public bool MadeItToResponse { get ; set ; }
8795 public IMemoryStreamFactory MemoryStreamFactory { get ; }
8896
89- public HttpMethod Method { get ; private set ; }
97+ public HttpMethod Method { get ; }
9098
9199 public Node Node { get ; set ; }
92100 public AuditEvent OnFailureAuditEvent => MadeItToResponse ? AuditEvent . BadResponse : AuditEvent . BadRequest ;
@@ -111,11 +119,12 @@ private string CreatePathWithQueryStrings(string path, IConnectionConfigurationV
111119 {
112120 path = path ?? string . Empty ;
113121 if ( path . Contains ( "?" ) )
114- throw new ArgumentException ( $ "{ nameof ( path ) } can not contain querystring parmeters and needs to be already escaped") ;
122+ throw new ArgumentException ( $ "{ nameof ( path ) } can not contain querystring parameters and needs to be already escaped") ;
115123
116124 var g = global . QueryStringParameters ;
117125 var l = request ? . QueryString ;
118- if ( g ? . Count == 0 && l ? . Count == 0 ) return path ;
126+
127+ if ( ( g == null || g . Count == 0 ) && ( l == null || l . Count == 0 ) ) return path ;
119128
120129 //create a copy of the global query string collection if needed.
121130 var nv = g == null ? new NameValueCollection ( ) : new NameValueCollection ( g ) ;
@@ -138,15 +147,22 @@ internal static class NameValueCollectionExtensions
138147 {
139148 internal static string ToQueryString ( this NameValueCollection nv )
140149 {
141- if ( nv == null ) return string . Empty ;
142- if ( nv . AllKeys . Length == 0 ) return string . Empty ;
150+ if ( nv == null || nv . AllKeys . Length == 0 ) return string . Empty ;
143151
144- string E ( string v )
152+ // initialize with capacity for number of key/values with length 5 each
153+ var builder = new StringBuilder ( "?" , nv . AllKeys . Length * 2 * 5 ) ;
154+ for ( int i = 0 ; i < nv . AllKeys . Length ; i ++ )
145155 {
146- return Uri . EscapeDataString ( v ) ;
156+ if ( i != 0 )
157+ builder . Append ( "&" ) ;
158+
159+ var key = nv . AllKeys [ i ] ;
160+ builder . Append ( Uri . EscapeDataString ( key ) ) ;
161+ builder . Append ( "=" ) ;
162+ builder . Append ( Uri . EscapeDataString ( nv [ key ] ) ) ;
147163 }
148164
149- return "?" + string . Join ( "&" , nv . AllKeys . Select ( key => $ " { E ( key ) } = { E ( nv [ key ] ) } " ) ) ;
165+ return builder . ToString ( ) ;
150166 }
151167
152168 internal static void UpdateFromDictionary ( this NameValueCollection queryString , Dictionary < string , object > queryStringUpdates ,
0 commit comments