diff --git a/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs b/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs index 4181057d6..d15319cb1 100644 --- a/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs +++ b/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs @@ -128,6 +128,17 @@ namespace NzbDrone.Common.Test.Http response.Content.Should().NotBeNullOrWhiteSpace(); } + [Test] + public void should_throw_timeout_request() + { + var request = new HttpRequest($"https://{_httpBinHost}/delay/10"); + + request.RequestTimeout = new TimeSpan(0, 0, 5); + + Assert.Throws(() => Subject.Execute(request)); + ExceptionVerification.ExpectedErrors(1); + } + [Test] public void should_execute_https_get() { diff --git a/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs b/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs index b3e707961..1c22f9d16 100644 --- a/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs +++ b/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs @@ -107,52 +107,59 @@ namespace NzbDrone.Common.Http.Dispatchers sw.Start(); - using var responseMessage = await httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead, cts.Token); + try { - byte[] data = null; - - try + using var responseMessage = await httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead, cts.Token); { - if (request.ResponseStream != null && responseMessage.StatusCode == HttpStatusCode.OK) + byte[] data = null; + + try { - await responseMessage.Content.CopyToAsync(request.ResponseStream, null, cts.Token); + if (request.ResponseStream != null && responseMessage.StatusCode == HttpStatusCode.OK) + { + await responseMessage.Content.CopyToAsync(request.ResponseStream, null, cts.Token); + } + else + { + data = await responseMessage.Content.ReadAsByteArrayAsync(cts.Token); + } } - else + catch (Exception ex) { - data = await responseMessage.Content.ReadAsByteArrayAsync(cts.Token); + throw new WebException("Failed to read complete http response", ex, WebExceptionStatus.ReceiveFailure, null); } - } - catch (Exception ex) - { - throw new WebException("Failed to read complete http response", ex, WebExceptionStatus.ReceiveFailure, null); - } - var headers = responseMessage.Headers.ToNameValueCollection(); + var headers = responseMessage.Headers.ToNameValueCollection(); - headers.Add(responseMessage.Content.Headers.ToNameValueCollection()); + headers.Add(responseMessage.Content.Headers.ToNameValueCollection()); - var responseCookies = new CookieContainer(); + var responseCookies = new CookieContainer(); - if (responseMessage.Headers.TryGetValues("Set-Cookie", out var cookieHeaders)) - { - foreach (var responseCookieHeader in cookieHeaders) + if (responseMessage.Headers.TryGetValues("Set-Cookie", out var cookieHeaders)) { - try - { - cookies.SetCookies(responseMessage.RequestMessage.RequestUri, responseCookieHeader); - } - catch + foreach (var responseCookieHeader in cookieHeaders) { - // Ignore invalid cookies + try + { + cookies.SetCookies(responseMessage.RequestMessage.RequestUri, responseCookieHeader); + } + catch + { + // Ignore invalid cookies + } } } - } - var cookieCollection = cookies.GetCookies(responseMessage.RequestMessage.RequestUri); + var cookieCollection = cookies.GetCookies(responseMessage.RequestMessage.RequestUri); - sw.Stop(); + sw.Stop(); - return new HttpResponse(request, new HttpHeader(headers), cookieCollection, data, sw.ElapsedMilliseconds, responseMessage.StatusCode, responseMessage.Version); + return new HttpResponse(request, new HttpHeader(headers), cookieCollection, data, sw.ElapsedMilliseconds, responseMessage.StatusCode, responseMessage.Version); + } + } + catch (OperationCanceledException ex) when (cts.IsCancellationRequested) + { + throw new WebException("Http request timed out", ex.InnerException, WebExceptionStatus.Timeout, null); } }