-
Notifications
You must be signed in to change notification settings - Fork 842
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Relayer transfroms #612
Relayer transfroms #612
Conversation
c9e5d98
to
657488c
Compare
The design change looks good. About the API, I think the type should be abstract and the methods should be virtual instead of delegates. Then maybe the base class can do the copying instead of exposing those properties. public abstract class HttpTransforms
{
public static readonly HttpTransforms Default = new DefaultHttpTransforms();
/// <summary>
/// A callback that is invoked prior to sending the proxied request. All HttpRequestMessage fields are
/// initialized except RequestUri, which will be initialized after the callback if no value is provided.
/// The string parameter represents the destination URI prefix that should be used when constructing the RequestUri.
/// The headers will be copied before the callback if CopyRequestHeaders is enabled.
/// </summary>
public Task OnRequestAsync(HttpContext httpContext, HttpRequestMessage proxyRequest) => Default.OnRequestAsync(httpContext, proxyRequest);
/// <summary>
/// A callback that is invoked when the proxied response is received. The status code and reason phrase will be copied
/// to the HttpContext.Response before the callback is invoked, but may still be modified there. The headers will be
/// copied to HttpContext.Response.Headers before the callback if CopyResponseHeaders is enabled.
/// </summary>
public virtual Task OnResponseAsync(HttpContext httpContext, HttpResponseMessage proxyResponse) => Default.OnResponseAsync(httpContext, proxyResponse);
/// <summary>
/// A callback that is invoked after the response body to modify trailers, if supported. The trailers will be
/// copied to the HttpContext.Response before the callback if CopyResponseTrailers is enabled.
/// </summary>
public virtual Task OnResponseTrailersAsync(HttpContext httpContext, HttpResponseMessage proxyResponse) => Default.OnResponseTrailersAsync(httpContext, proxyResponse);
} |
@davidfowl Why abstract + Default instead of having the defaults directly in a virtual base class? As a way of communicating to people that they must derive from it to change anything? Would a protected constructor accomplish the same? |
94a1728
to
d8eb4dc
Compare
e62f3e2
to
0b11a6b
Compare
} | ||
|
||
|
||
private static void CopyResponseHeaders(HttpHeaders source, IHeaderDictionary destination) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we make this protected static or is it simple enough to copy around
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you're going to customize TransformResponseAsync or TransformResponseTrailersAsync enough not to call the base implementation then you probably need to customize this code too. That's what happened for the structured transforms derivation.
src/ReverseProxy/Service/RuntimeModel/Transforms/RequestHeaderTransform.cs
Outdated
Show resolved
Hide resolved
{ | ||
// TODO: this list only contains "Transfer-Encoding" because that messes up Kestrel. If we don't need to add any more here then it would be more efficient to | ||
// check for the single value directly. What about connection headers? | ||
internal static readonly HashSet<string> ResponseHeadersToSkip = new HashSet<string>(StringComparer.OrdinalIgnoreCase) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This may as well be an array.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I expect this logic to get more interesting when we fix #583. I'll hold off changes until then.
/// <param name="query">The query to append</param> | ||
internal static Uri MakeDestinationAddress(string destinationPrefix, PathString path, QueryString query) | ||
{ | ||
var builder = new StringBuilder(destinationPrefix); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Allocations in the hot path.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but it's trying to save you from even more allocations 😁. Let's revisit this on its own when we get to profiling.
Yea you're right. |
@davidfowl I think everybody else is out now, consider yourself the sole reviewer. |
Do we still want to (eventually) provide an API that makes this easy to do without overriding the IHttpProxy? Something you can do in middleware? |
That's where #60 comes in. |
#594 IHttpProxy is getting much more attention/usage than other parts of YARP. Long term we're interested in moving that component into ASP.NET Core. However, IHttpProxy also brings in the entire transforms infrastructure which it's not clear if people using IHttpProxy directly need, or if they could use a simplified model (e.g. callbacks).
Here's the proposed new transforms model for IHttpProxy:
The idea is that everything should just work but you can get in and tweak things as needed. The higher layer uses these callbacks to hook in and run about the same structured transforms logic it was doing before. There's a little code duplication around header copying to to investigate, and some tests that need cleaning up.