diff --git a/src/Ocelot/Errors/OcelotErrorCode.cs b/src/Ocelot/Errors/OcelotErrorCode.cs index d8b6f333..6ca67e7d 100644 --- a/src/Ocelot/Errors/OcelotErrorCode.cs +++ b/src/Ocelot/Errors/OcelotErrorCode.cs @@ -39,6 +39,7 @@ CannotAddPlaceholderError = 34, CannotRemovePlaceholderError = 35, QuotaExceededError = 36, - RequestCanceled = 37, + RequestCanceled = 37, + ConnectionToDownstreamServiceError = 38, } } diff --git a/src/Ocelot/Requester/ConnectionToDownstreamServiceError.cs b/src/Ocelot/Requester/ConnectionToDownstreamServiceError.cs new file mode 100644 index 00000000..d2087983 --- /dev/null +++ b/src/Ocelot/Requester/ConnectionToDownstreamServiceError.cs @@ -0,0 +1,13 @@ +using Ocelot.Errors; +using System; + +namespace Ocelot.Requester +{ + class ConnectionToDownstreamServiceError : Error + { + public ConnectionToDownstreamServiceError(Exception exception) + : base($"Error connecting to downstream service, exception: {exception}", OcelotErrorCode.ConnectionToDownstreamServiceError) + { + } + } +} diff --git a/src/Ocelot/Requester/HttpExeptionToErrorMapper.cs b/src/Ocelot/Requester/HttpExeptionToErrorMapper.cs index f2fbad2d..f696a02b 100644 --- a/src/Ocelot/Requester/HttpExeptionToErrorMapper.cs +++ b/src/Ocelot/Requester/HttpExeptionToErrorMapper.cs @@ -4,6 +4,8 @@ namespace Ocelot.Requester using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; + using System.Net.Http; + using System.Net.Sockets; public class HttpExeptionToErrorMapper : IExceptionToErrorMapper { @@ -28,6 +30,11 @@ namespace Ocelot.Requester return new RequestCanceledError(exception.Message); } + if (type == typeof(HttpRequestException)) + { + return new ConnectionToDownstreamServiceError(exception); + } + return new UnableToCompleteRequestError(exception); } } diff --git a/src/Ocelot/Responder/ErrorsToHttpStatusCodeMapper.cs b/src/Ocelot/Responder/ErrorsToHttpStatusCodeMapper.cs index c50daa27..6b0ee6cc 100644 --- a/src/Ocelot/Responder/ErrorsToHttpStatusCodeMapper.cs +++ b/src/Ocelot/Responder/ErrorsToHttpStatusCodeMapper.cs @@ -38,6 +38,11 @@ namespace Ocelot.Responder if (errors.Any(e => e.Code == OcelotErrorCode.UnableToFindDownstreamRouteError)) { return 404; + } + + if (errors.Any(e => e.Code == OcelotErrorCode.ConnectionToDownstreamServiceError)) + { + return 502; } if (errors.Any(e => e.Code == OcelotErrorCode.UnableToCompleteRequestError)) diff --git a/test/Ocelot.AcceptanceTests/HttpTests.cs b/test/Ocelot.AcceptanceTests/HttpTests.cs index 57947d07..da59d000 100644 --- a/test/Ocelot.AcceptanceTests/HttpTests.cs +++ b/test/Ocelot.AcceptanceTests/HttpTests.cs @@ -141,7 +141,7 @@ namespace Ocelot.AcceptanceTests } [Fact] - public void should_return_response_500_when_using_http_one_to_talk_to_server_running_http_two() + public void should_return_response_502_when_using_http_one_to_talk_to_server_running_http_two() { var port = RandomPortFinder.GetRandomPort(); @@ -177,7 +177,7 @@ namespace Ocelot.AcceptanceTests .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/", httpContent)) - .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.InternalServerError)) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.BadGateway)) .BDDfy(); } diff --git a/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs b/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs index 1ebc1113..323c9e14 100644 --- a/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs +++ b/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs @@ -16,6 +16,38 @@ { _serviceHandler = new ServiceHandler(); _steps = new Steps(); + } + + [Fact] + public void should_return_bad_gateway_error_if_downstream_service_doesnt_respond() + { + var configuration = new FileConfiguration + { + ReRoutes = new List + { + new FileReRoute + { + DownstreamPathTemplate = "/", + UpstreamPathTemplate = "/", + UpstreamHttpMethod = new List { "Get" }, + DownstreamHostAndPorts = new List + { + new FileHostAndPort + { + Host = "localhost", + Port = 53877, + }, + }, + DownstreamScheme = "http", + }, + }, + }; + + this.Given(x => _steps.GivenThereIsAConfiguration(configuration)) + .And(x => _steps.GivenOcelotIsRunning()) + .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.BadGateway)) + .BDDfy(); } [Fact] diff --git a/test/Ocelot.AcceptanceTests/SslTests.cs b/test/Ocelot.AcceptanceTests/SslTests.cs index 58c9e6a1..ee1f8141 100644 --- a/test/Ocelot.AcceptanceTests/SslTests.cs +++ b/test/Ocelot.AcceptanceTests/SslTests.cs @@ -89,7 +89,7 @@ namespace Ocelot.AcceptanceTests .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) - .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.InternalServerError)) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.BadGateway)) .BDDfy(); } diff --git a/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs b/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs index 8b550a05..d662f86f 100644 --- a/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs +++ b/test/Ocelot.UnitTests/Responder/ErrorsToHttpStatusCodeMapperTests.cs @@ -50,6 +50,13 @@ namespace Ocelot.UnitTests.Responder public void should_return_internal_server_error(OcelotErrorCode errorCode) { ShouldMapErrorToStatusCode(errorCode, HttpStatusCode.InternalServerError); + } + + [Theory] + [InlineData(OcelotErrorCode.ConnectionToDownstreamServiceError)] + public void should_return_bad_gateway_error(OcelotErrorCode errorCode) + { + ShouldMapErrorToStatusCode(errorCode, HttpStatusCode.BadGateway); } [Theory] @@ -125,7 +132,7 @@ namespace Ocelot.UnitTests.Responder // If this test fails then it's because the number of error codes has changed. // You should make the appropriate changes to the test cases here to ensure // they cover all the error codes, and then modify this assertion. - Enum.GetNames(typeof(OcelotErrorCode)).Length.ShouldBe(38, "Looks like the number of error codes has changed. Do you need to modify ErrorsToHttpStatusCodeMapper?"); + Enum.GetNames(typeof(OcelotErrorCode)).Length.ShouldBe(39, "Looks like the number of error codes has changed. Do you need to modify ErrorsToHttpStatusCodeMapper?"); } private void ShouldMapErrorToStatusCode(OcelotErrorCode errorCode, HttpStatusCode expectedHttpStatusCode)