Skip to content

fix: parsing error response for queries #83

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Merged
merged 1 commit into from
Apr 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
### Bug Fixes
1. [#81](https://github.com/influxdata/influxdb-client-csharp/pull/81): Fixed potentially hangs on of WriteApi.Dispose()
1. [#82](https://github.com/influxdata/influxdb-client-csharp/pull/82): Avoid to deadlock when is client used in UI
1. [#83](https://github.com/influxdata/influxdb-client-csharp/pull/83): Fixed parsing error response for 1.x

## 1.7.0 [2020-04-17]

Expand Down
51 changes: 39 additions & 12 deletions Client.Core/Exceptions/InfluxException.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using InfluxDB.Client.Core.Internal;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RestSharp;

Expand Down Expand Up @@ -53,40 +55,64 @@ public HttpException(string message, int status) : base(message, 0)
/// </summary>
public int? RetryAfter { get; set; }

public static HttpException Create(IRestResponse requestResult)
public static HttpException Create(IRestResponse requestResult, object body)
{
Arguments.CheckNotNull(requestResult, nameof(requestResult));

var httpHeaders = LoggingHandler.ToHeaders(requestResult.Headers);

return Create(requestResult.Content, httpHeaders, requestResult.ErrorMessage, requestResult.StatusCode);
return Create(body, httpHeaders, requestResult.ErrorMessage, requestResult.StatusCode);
}

public static HttpException Create(IHttpResponse requestResult)
public static HttpException Create(IHttpResponse requestResult, object body)
{
Arguments.CheckNotNull(requestResult, nameof(requestResult));

return Create(requestResult.Content, requestResult.Headers, requestResult.ErrorMessage, requestResult.StatusCode);
return Create(body, requestResult.Headers, requestResult.ErrorMessage, requestResult.StatusCode);
}

public static HttpException Create(string content, IList<HttpHeader> headers, string ErrorMessage, HttpStatusCode statusCode)
public static HttpException Create(object content, IList<HttpHeader> headers, string ErrorMessage, HttpStatusCode statusCode)
{
string stringBody = null;
var errorBody = new JObject();
string errorMessage = null;
JObject errorBody;

int? retryAfter = null;
{
var retryHeader = headers.FirstOrDefault(header => header.Name.Equals("Retry-After"));
if (retryHeader != null) retryAfter = Convert.ToInt32(retryHeader.Value);
}

if (string.IsNullOrEmpty(content))
errorBody = new JObject();
else
errorBody = JObject.Parse(content);

if (errorBody.ContainsKey("message")) errorMessage = errorBody.GetValue("message").ToString();
if (content != null)
{
if (content is Stream)
{
var stream = content as Stream;
var sr = new StreamReader(stream);
stringBody = sr.ReadToEnd();
}
else
{
stringBody = content.ToString();
}
}

if (!string.IsNullOrEmpty(stringBody))
{
try
{
errorBody = JObject.Parse(stringBody);
if (errorBody.ContainsKey("message"))
{
errorMessage = errorBody.GetValue("message").ToString();
}
}
catch (JsonException)
{
errorBody = new JObject();
}
}

var keys = new[] {"X-Platform-Error-Code", "X-Influx-Error", "X-InfluxDb-Error"};

if (string.IsNullOrEmpty(errorMessage))
Expand All @@ -95,6 +121,7 @@ public static HttpException Create(string content, IList<HttpHeader> headers, st
.Select(header => header.Value.ToString()).FirstOrDefault();

if (string.IsNullOrEmpty(errorMessage)) errorMessage = ErrorMessage;
if (string.IsNullOrEmpty(errorMessage)) errorMessage = stringBody;

return new HttpException(errorMessage, (int) statusCode)
{ErrorBody = errorBody, RetryAfter = retryAfter};
Expand Down
10 changes: 5 additions & 5 deletions Client.Core/Internal/AbstractQueryClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,11 @@ protected async Task Query(RestRequest query, Action<ICancellable, Stream> consu
{
responseStream = AfterIntercept((int)response.StatusCode, () => response.Headers, responseStream);

RaiseForInfluxError(response);
RaiseForInfluxError(response, responseStream);
consumer(cancellable, responseStream);
};

await Task.Run(() => { RestClient.DownloadData(query, true); });
await Task.Run(() => { RestClient.DownloadData(query, true); }).ConfigureAwait(true);
if (!cancellable.IsCancelled())
{
onComplete();
Expand Down Expand Up @@ -195,7 +195,7 @@ private bool IsCloseException(Exception exception)
return exception is EndOfStreamException;
}

protected void RaiseForInfluxError(object result)
protected void RaiseForInfluxError(object result, object body)
{
if (result is IRestResponse restResponse)
{
Expand All @@ -206,7 +206,7 @@ protected void RaiseForInfluxError(object result)
throw restResponse.ErrorException;
}

throw HttpException.Create(restResponse);
throw HttpException.Create(restResponse, body);
}

var httpResponse = (IHttpResponse) result;
Expand All @@ -220,7 +220,7 @@ protected void RaiseForInfluxError(object result)
throw httpResponse.ErrorException;
}

throw HttpException.Create(httpResponse);
throw HttpException.Create(httpResponse, body);
}

protected class FluxResponseConsumerRecord : FluxCsvParser.IFluxResponseConsumer
Expand Down
25 changes: 25 additions & 0 deletions Client.Legacy.Test/FluxClientQueryTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using NUnit.Framework;
using WireMock.Matchers;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;

namespace Client.Legacy.Test
{
Expand Down Expand Up @@ -75,6 +76,30 @@ public async Task QueryError()
}
}

[Test]
public async Task ErrorAsStream()
{
var response = Response.Create()
.WithStatusCode(403)
.WithBody("Flux query service disabled. Verify flux-enabled=true in the [http] section of the InfluxDB config.");

MockServer.Given(Request.Create().WithPath("/api/v2/query").UsingPost())
.RespondWith(response);

try
{
await FluxClient.QueryAsync("from(bucket:\"telegraf\")");

Assert.Fail();
}
catch (InfluxException e)
{
Assert.AreEqual(e.Status, 403);
Assert.AreEqual(e.Message,
"Flux query service disabled. Verify flux-enabled=true in the [http] section of the InfluxDB config.");
}
}

[Test]
public async Task QueryErrorSuccessResponse()
{
Expand Down
2 changes: 1 addition & 1 deletion Client.Legacy/FluxClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ private async Task<IRestResponse> ExecuteAsync(RestRequest request)

var response = await Task.Run(() => RestClient.Execute(request)).ConfigureAwait(false);

RaiseForInfluxError(response);
RaiseForInfluxError(response, response.Content);

response.Content = AfterIntercept(
(int) response.StatusCode,
Expand Down
2 changes: 1 addition & 1 deletion Client/InfluxDBClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ protected internal InfluxDBClient(InfluxDBClientOptions options)
_apiClient.RestClient.UserAgent = $"influxdb-client-csharp/{version}";

_exceptionFactory = (methodName, response) =>
!response.IsSuccessful ? HttpException.Create(response) : null;
!response.IsSuccessful ? HttpException.Create(response, response.Content) : null;

_setupService = new SetupService((Configuration) _apiClient.Configuration)
{
Expand Down
2 changes: 1 addition & 1 deletion Client/WriteApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ protected internal WriteApi(InfluxDBClientOptions options, WriteService service,
// ReSharper disable once ConvertIfStatementToReturnStatement
if (result.IsSuccessful) return Notification.CreateOnNext(result);

return Notification.CreateOnError<IRestResponse>(HttpException.Create(result));
return Notification.CreateOnError<IRestResponse>(HttpException.Create(result, result.Content));
})
.Catch<Notification<IRestResponse>, Exception>(ex =>
{
Expand Down