@@ -153,16 +153,14 @@ private ValueTask<TResponse> DoRequestCoreAsync<TRequest, TResponse, TRequestPar
153153 ( int ) ProductCheckStatus . NotChecked
154154 ) ;
155155
156- // TODO: Re-enable product check
157- //return productCheckStatus switch
158- //{
159- // (int)ProductCheckStatus.NotChecked => SendRequestWithProductCheck(),
160- // (int)ProductCheckStatus.InProgress or
161- // (int)ProductCheckStatus.Succeeded => SendRequest(),
162- // (int)ProductCheckStatus.Failed => throw new UnsupportedProductException(UnsupportedProductException.InvalidProductError),
163- // _ => throw new InvalidOperationException("unreachable")
164- //};
165- return SendRequest ( ) ;
156+ return productCheckStatus switch
157+ {
158+ ( int ) ProductCheckStatus . NotChecked => SendRequestWithProductCheck ( ) ,
159+ ( int ) ProductCheckStatus . InProgress or
160+ ( int ) ProductCheckStatus . Succeeded => SendRequest ( ) ,
161+ ( int ) ProductCheckStatus . Failed => throw new UnsupportedProductException ( UnsupportedProductException . InvalidProductError ) ,
162+ _ => throw new InvalidOperationException ( "unreachable" )
163+ } ;
166164
167165 ValueTask < TResponse > SendRequest ( )
168166 {
@@ -176,98 +174,85 @@ ValueTask<TResponse> SendRequest()
176174 . Request < TResponse > ( new EndpointPath ( request . HttpMethod , resolvedUrl ) , postData , in openTelemetryData , request . RequestConfig ) ) ;
177175 }
178176
179- //async ValueTask<TResponse> SendRequestWithProductCheck()
180- //{
181- // try
182- // {
183- // return await SendRequestWithProductCheckCore().ConfigureAwait(false);
184- // }
185- // catch
186- // {
187- // // Re-try product check on next request.
188-
189- // // 32-bit read/write operations are atomic and due to the initial memory barrier, we can be sure that
190- // // no other thread executes the product check at the same time. Locked access is not required here.
191- // if (_productCheckStatus is (int)ProductCheckStatus.InProgress)
192- // _productCheckStatus = (int)ProductCheckStatus.NotChecked;
193-
194- // throw;
195- // }
196- //}
197-
198- //async ValueTask<TResponse> SendRequestWithProductCheckCore()
199- //{
200- // // Attach product check header
201-
202- // var hadRequestConfig = false;
203- // HeadersList? originalHeaders = null;
204-
205- // if (request.RequestConfiguration is null)
206- // request.RequestParameters.RequestConfiguration = new RequestConfiguration();
207- // else
208- // {
209- // originalHeaders = request.RequestParameters.RequestConfiguration.ResponseHeadersToParse;
210- // hadRequestConfig = true;
211- // }
212-
213- // request.RequestParameters.RequestConfiguration.ResponseHeadersToParse = request.RequestParameters.RequestConfiguration.ResponseHeadersToParse.Count == 0
214- // ? new HeadersList("x-elastic-product")
215- // : new HeadersList(request.RequestParameters.RequestConfiguration.ResponseHeadersToParse, "x-elastic-product");
216-
217- // // Send request
218-
219- // var (resolvedUrl, _, resolvedRouteValues, postData) = PrepareRequest<TRequest, TRequestParameters>(request, forceConfiguration);
220- // var openTelemetryData = PrepareOpenTelemetryData<TRequest, TRequestParameters>(request, resolvedRouteValues);
221-
222- // TResponse response;
223-
224- // if (isAsync)
225- // {
226- // response = await _transport
227- // .RequestAsync<TResponse>(request.HttpMethod, resolvedUrl, postData, request.RequestParameters, in openTelemetryData, cancellationToken)
228- // .ConfigureAwait(false);
229- // }
230- // else
231- // {
232- // response = _transport
233- // .Request<TResponse>(request.HttpMethod, resolvedUrl, postData, request.RequestParameters, in openTelemetryData);
234- // }
235-
236- // // Evaluate product check result
237-
238- // var hasSuccessStatusCode = response.ApiCallDetails.HttpStatusCode is >= 200 and <= 299;
239- // if (hasSuccessStatusCode)
240- // {
241- // var productCheckSucceeded = response.ApiCallDetails.TryGetHeader("x-elastic-product", out var values) &&
242- // values.FirstOrDefault(x => x.Equals("Elasticsearch", StringComparison.Ordinal)) is not null;
243-
244- // _productCheckStatus = productCheckSucceeded
245- // ? (int)ProductCheckStatus.Succeeded
246- // : (int)ProductCheckStatus.Failed;
247-
248- // if (_productCheckStatus == (int)ProductCheckStatus.Failed)
249- // throw new UnsupportedProductException(UnsupportedProductException.InvalidProductError);
250- // }
251-
252- // if (request.RequestParameters.RequestConfiguration is null)
253- // return response;
254-
255- // // Reset request configuration
256-
257- // if (!hadRequestConfig)
258- // request.RequestParameters.RequestConfiguration = null;
259- // else if (originalHeaders is { Count: > 0 })
260- // request.RequestParameters.RequestConfiguration.ResponseHeadersToParse = originalHeaders.Value;
261-
262- // if (!hasSuccessStatusCode)
263- // {
264- // // The product check is unreliable for non success status codes.
265- // // We have to re-try on the next request.
266- // _productCheckStatus = (int)ProductCheckStatus.NotChecked;
267- // }
268-
269- // return response;
270- //}
177+ async ValueTask < TResponse > SendRequestWithProductCheck ( )
178+ {
179+ try
180+ {
181+ return await SendRequestWithProductCheckCore ( ) . ConfigureAwait ( false ) ;
182+ }
183+ catch
184+ {
185+ // Re-try product check on next request.
186+
187+ // 32-bit read/write operations are atomic and due to the initial memory barrier, we can be sure that
188+ // no other thread executes the product check at the same time. Locked access is not required here.
189+ if ( _productCheckStatus is ( int ) ProductCheckStatus . InProgress )
190+ _productCheckStatus = ( int ) ProductCheckStatus . NotChecked ;
191+
192+ throw ;
193+ }
194+ }
195+
196+ async ValueTask < TResponse > SendRequestWithProductCheckCore ( )
197+ {
198+ // Attach product check header
199+
200+ // TODO: The copy constructor should accept null values
201+ var requestConfig = ( request . RequestConfig is null )
202+ ? new RequestConfiguration ( )
203+ {
204+ ResponseHeadersToParse = new HeadersList ( "x-elastic-product" )
205+ }
206+ : new RequestConfiguration ( request . RequestConfig )
207+ {
208+ ResponseHeadersToParse = ( request . RequestConfig . ResponseHeadersToParse is { Count : > 0 } )
209+ ? new HeadersList ( request . RequestConfig . ResponseHeadersToParse , "x-elastic-product" )
210+ : new HeadersList ( "x-elastic-product" )
211+ } ;
212+
213+ // Send request
214+
215+ var ( resolvedUrl , _, resolvedRouteValues , postData ) = PrepareRequest < TRequest , TRequestParameters > ( request ) ;
216+ var openTelemetryData = PrepareOpenTelemetryData < TRequest , TRequestParameters > ( request , resolvedRouteValues ) ;
217+
218+ TResponse response ;
219+
220+ if ( isAsync )
221+ {
222+ response = await _transport
223+ . RequestAsync < TResponse > ( new EndpointPath ( request . HttpMethod , resolvedUrl ) , postData , in openTelemetryData , requestConfig , cancellationToken )
224+ . ConfigureAwait ( false ) ;
225+ }
226+ else
227+ {
228+ response = _transport
229+ . Request < TResponse > ( new EndpointPath ( request . HttpMethod , resolvedUrl ) , postData , in openTelemetryData , requestConfig ) ;
230+ }
231+
232+ // Evaluate product check result
233+
234+ var hasSuccessStatusCode = response . ApiCallDetails . HttpStatusCode is >= 200 and <= 299 ;
235+ if ( ! hasSuccessStatusCode )
236+ {
237+ // The product check is unreliable for non success status codes.
238+ // We have to re-try on the next request.
239+ _productCheckStatus = ( int ) ProductCheckStatus . NotChecked ;
240+
241+ return response ;
242+ }
243+
244+ var productCheckSucceeded = response . ApiCallDetails . TryGetHeader ( "x-elastic-product" , out var values ) &&
245+ values . FirstOrDefault ( x => x . Equals ( "Elasticsearch" , StringComparison . Ordinal ) ) is not null ;
246+
247+ _productCheckStatus = productCheckSucceeded
248+ ? ( int ) ProductCheckStatus . Succeeded
249+ : ( int ) ProductCheckStatus . Failed ;
250+
251+ if ( _productCheckStatus == ( int ) ProductCheckStatus . Failed )
252+ throw new UnsupportedProductException ( UnsupportedProductException . InvalidProductError ) ;
253+
254+ return response ;
255+ }
271256 }
272257
273258 private static OpenTelemetryData PrepareOpenTelemetryData < TRequest , TRequestParameters > ( TRequest request , Dictionary < string , string > resolvedRouteValues )
0 commit comments