forked from ThreeMammals/Ocelot
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
use a stream rather than byte array in responder (ThreeMammals#519)
- Loading branch information
1 parent
eb4b996
commit b854ca6
Showing
4 changed files
with
334 additions
and
335 deletions.
There are no files selected for viewing
19 changes: 9 additions & 10 deletions
19
src/Ocelot/Errors/Middleware/ExceptionHandlerMiddleware.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,74 +1,74 @@ | ||
using System.IO; | ||
using System.Linq; | ||
using System.Net; | ||
using System.Threading.Tasks; | ||
using Microsoft.AspNetCore.Http; | ||
using Microsoft.Extensions.Primitives; | ||
using Ocelot.Headers; | ||
using Ocelot.Middleware; | ||
|
||
namespace Ocelot.Responder | ||
{ | ||
/// <summary> | ||
/// Cannot unit test things in this class due to methods not being implemented | ||
/// on .net concretes used for testing | ||
/// </summary> | ||
public class HttpContextResponder : IHttpResponder | ||
{ | ||
private readonly IRemoveOutputHeaders _removeOutputHeaders; | ||
|
||
public HttpContextResponder(IRemoveOutputHeaders removeOutputHeaders) | ||
{ | ||
_removeOutputHeaders = removeOutputHeaders; | ||
} | ||
|
||
public async Task SetResponseOnHttpContext(HttpContext context, DownstreamResponse response) | ||
{ | ||
_removeOutputHeaders.Remove(response.Headers); | ||
|
||
foreach (var httpResponseHeader in response.Headers) | ||
{ | ||
AddHeaderIfDoesntExist(context, httpResponseHeader); | ||
} | ||
|
||
foreach (var httpResponseHeader in response.Content.Headers) | ||
{ | ||
AddHeaderIfDoesntExist(context, new Header(httpResponseHeader.Key, httpResponseHeader.Value)); | ||
} | ||
|
||
var content = await response.Content.ReadAsByteArrayAsync(); | ||
|
||
AddHeaderIfDoesntExist(context, new Header("Content-Length", new []{ content.Length.ToString() }) ); | ||
|
||
context.Response.OnStarting(state => | ||
{ | ||
var httpContext = (HttpContext)state; | ||
|
||
httpContext.Response.StatusCode = (int)response.StatusCode; | ||
|
||
return Task.CompletedTask; | ||
}, context); | ||
|
||
using (Stream stream = new MemoryStream(content)) | ||
{ | ||
if (response.StatusCode != HttpStatusCode.NotModified && context.Response.ContentLength != 0) | ||
{ | ||
await stream.CopyToAsync(context.Response.Body); | ||
} | ||
} | ||
} | ||
|
||
public void SetErrorResponseOnContext(HttpContext context, int statusCode) | ||
using System.IO; | ||
using System.Linq; | ||
using System.Net; | ||
using System.Threading.Tasks; | ||
using Microsoft.AspNetCore.Http; | ||
using Microsoft.Extensions.Primitives; | ||
using Ocelot.Headers; | ||
using Ocelot.Middleware; | ||
|
||
namespace Ocelot.Responder | ||
{ | ||
/// <summary> | ||
/// Cannot unit test things in this class due to methods not being implemented | ||
/// on .net concretes used for testing | ||
/// </summary> | ||
public class HttpContextResponder : IHttpResponder | ||
{ | ||
private readonly IRemoveOutputHeaders _removeOutputHeaders; | ||
|
||
public HttpContextResponder(IRemoveOutputHeaders removeOutputHeaders) | ||
{ | ||
context.Response.StatusCode = statusCode; | ||
} | ||
|
||
private static void AddHeaderIfDoesntExist(HttpContext context, Header httpResponseHeader) | ||
{ | ||
if (!context.Response.Headers.ContainsKey(httpResponseHeader.Key)) | ||
{ | ||
context.Response.Headers.Add(httpResponseHeader.Key, new StringValues(httpResponseHeader.Values.ToArray())); | ||
} | ||
} | ||
} | ||
} | ||
_removeOutputHeaders = removeOutputHeaders; | ||
} | ||
|
||
public async Task SetResponseOnHttpContext(HttpContext context, DownstreamResponse response) | ||
{ | ||
_removeOutputHeaders.Remove(response.Headers); | ||
|
||
foreach (var httpResponseHeader in response.Headers) | ||
{ | ||
AddHeaderIfDoesntExist(context, httpResponseHeader); | ||
} | ||
|
||
foreach (var httpResponseHeader in response.Content.Headers) | ||
{ | ||
AddHeaderIfDoesntExist(context, new Header(httpResponseHeader.Key, httpResponseHeader.Value)); | ||
} | ||
|
||
var content = await response.Content.ReadAsStreamAsync(); | ||
|
||
AddHeaderIfDoesntExist(context, new Header("Content-Length", new []{ content.Length.ToString() }) ); | ||
|
||
context.Response.OnStarting(state => | ||
{ | ||
var httpContext = (HttpContext)state; | ||
|
||
httpContext.Response.StatusCode = (int)response.StatusCode; | ||
|
||
return Task.CompletedTask; | ||
}, context); | ||
|
||
using(content) | ||
{ | ||
if (response.StatusCode != HttpStatusCode.NotModified && context.Response.ContentLength != 0) | ||
{ | ||
await content.CopyToAsync(context.Response.Body); | ||
} | ||
} | ||
} | ||
|
||
public void SetErrorResponseOnContext(HttpContext context, int statusCode) | ||
{ | ||
context.Response.StatusCode = statusCode; | ||
} | ||
|
||
private static void AddHeaderIfDoesntExist(HttpContext context, Header httpResponseHeader) | ||
{ | ||
if (!context.Response.Headers.ContainsKey(httpResponseHeader.Key)) | ||
{ | ||
context.Response.Headers.Add(httpResponseHeader.Key, new StringValues(httpResponseHeader.Values.ToArray())); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,55 +1,55 @@ | ||
using Microsoft.AspNetCore.Http; | ||
using Ocelot.Errors; | ||
using Ocelot.Logging; | ||
using Ocelot.Middleware; | ||
using System.Collections.Generic; | ||
using System.Threading.Tasks; | ||
using Ocelot.Infrastructure.Extensions; | ||
|
||
namespace Ocelot.Responder.Middleware | ||
{ | ||
/// <summary> | ||
/// Completes and returns the request and request body, if any pipeline errors occured then sets the appropriate HTTP status code instead. | ||
/// </summary> | ||
public class ResponderMiddleware : OcelotMiddleware | ||
{ | ||
private readonly OcelotRequestDelegate _next; | ||
private readonly IHttpResponder _responder; | ||
private readonly IErrorsToHttpStatusCodeMapper _codeMapper; | ||
|
||
public ResponderMiddleware(OcelotRequestDelegate next, | ||
IHttpResponder responder, | ||
IOcelotLoggerFactory loggerFactory, | ||
IErrorsToHttpStatusCodeMapper codeMapper | ||
) | ||
:base(loggerFactory.CreateLogger<ResponderMiddleware>()) | ||
{ | ||
_next = next; | ||
_responder = responder; | ||
_codeMapper = codeMapper; | ||
} | ||
|
||
public async Task Invoke(DownstreamContext context) | ||
{ | ||
await _next.Invoke(context); | ||
|
||
if (context.IsError) | ||
{ | ||
Logger.LogWarning($"{context.Errors.ToErrorString()} errors found in {MiddlewareName}. Setting error response for request path:{context.HttpContext.Request.Path}, request method: {context.HttpContext.Request.Method}"); | ||
|
||
SetErrorResponse(context.HttpContext, context.Errors); | ||
} | ||
else | ||
{ | ||
Logger.LogDebug("no pipeline errors, setting and returning completed response"); | ||
await _responder.SetResponseOnHttpContext(context.HttpContext, context.DownstreamResponse); | ||
} | ||
} | ||
|
||
private void SetErrorResponse(HttpContext context, List<Error> errors) | ||
{ | ||
var statusCode = _codeMapper.Map(errors); | ||
_responder.SetErrorResponseOnContext(context, statusCode); | ||
} | ||
} | ||
} | ||
using Microsoft.AspNetCore.Http; | ||
using Ocelot.Errors; | ||
using Ocelot.Logging; | ||
using Ocelot.Middleware; | ||
using System.Collections.Generic; | ||
using System.Threading.Tasks; | ||
using Ocelot.Infrastructure.Extensions; | ||
|
||
namespace Ocelot.Responder.Middleware | ||
{ | ||
/// <summary> | ||
/// Completes and returns the request and request body, if any pipeline errors occured then sets the appropriate HTTP status code instead. | ||
/// </summary> | ||
public class ResponderMiddleware : OcelotMiddleware | ||
{ | ||
private readonly OcelotRequestDelegate _next; | ||
private readonly IHttpResponder _responder; | ||
private readonly IErrorsToHttpStatusCodeMapper _codeMapper; | ||
|
||
public ResponderMiddleware(OcelotRequestDelegate next, | ||
IHttpResponder responder, | ||
IOcelotLoggerFactory loggerFactory, | ||
IErrorsToHttpStatusCodeMapper codeMapper | ||
) | ||
:base(loggerFactory.CreateLogger<ResponderMiddleware>()) | ||
{ | ||
_next = next; | ||
_responder = responder; | ||
_codeMapper = codeMapper; | ||
} | ||
|
||
public async Task Invoke(DownstreamContext context) | ||
{ | ||
await _next.Invoke(context); | ||
|
||
if (context.IsError) | ||
{ | ||
Logger.LogWarning($"{context.Errors.ToErrorString()} errors found in {MiddlewareName}. Setting error response for request path:{context.HttpContext.Request.Path}, request method: {context.HttpContext.Request.Method}"); | ||
|
||
SetErrorResponse(context.HttpContext, context.Errors); | ||
} | ||
else | ||
{ | ||
Logger.LogDebug("no pipeline errors, setting and returning completed response"); | ||
await _responder.SetResponseOnHttpContext(context.HttpContext, context.DownstreamResponse); | ||
} | ||
} | ||
|
||
private void SetErrorResponse(HttpContext context, List<Error> errors) | ||
{ | ||
var statusCode = _codeMapper.Map(errors); | ||
_responder.SetErrorResponseOnContext(context, statusCode); | ||
} | ||
} | ||
} |
Oops, something went wrong.