/// <summary> /// Removes and returns the current header value by first checking the HttpResponse /// and falling back to the value from HttpResponseMessage or HttpContent only if /// <see cref="ResponseTransformContext.HeadersCopied"/> is not set. /// This ordering allows multiple transforms to mutate the same header. /// </summary> /// <param name="headerName">The name of the header to take.</param> /// <returns>The response header value, or StringValues.Empty if none.</returns> public static StringValues TakeHeader(ResponseTransformContext context, string headerName) { if (context is null) { throw new System.ArgumentNullException(nameof(context)); } if (string.IsNullOrEmpty(headerName)) { throw new System.ArgumentException($"'{nameof(headerName)}' cannot be null or empty.", nameof(headerName)); } var existingValues = StringValues.Empty; if (context.HttpContext.Response.Headers.TryGetValue(headerName, out var responseValues)) { context.HttpContext.Response.Headers.Remove(headerName); existingValues = responseValues; } else if (context.ProxyResponse != null && !context.HeadersCopied && (context.ProxyResponse.Headers.TryGetValues(headerName, out var values) || context.ProxyResponse.Content.Headers.TryGetValues(headerName, out values))) { existingValues = (string[])values; } return(existingValues); }
/// <inheritdoc/> public override ValueTask ApplyAsync(ResponseTransformContext context) { if (context is null) { throw new ArgumentNullException(nameof(context)); } if (context.ProxyResponse == null) { return(default);
// Assumes the response status code has been set on the HttpContext already. /// <inheritdoc/> public override ValueTask ApplyAsync(ResponseTransformContext context) { if (context is null) { throw new ArgumentNullException(nameof(context)); } if (Always || Success(context)) { context.HttpContext.Response.Headers.Remove(HeaderName); } return(default);
/// <inheritdoc/> public override ValueTask ApplyAsync(ResponseTransformContext context) { if (context is null) { throw new ArgumentNullException(nameof(context)); } Debug.Assert(!context.HeadersCopied); // See https://github.com/microsoft/reverse-proxy/blob/51d797986b1fea03500a1ad173d13a1176fb5552/src/ReverseProxy/Forwarder/HttpTransformer.cs#L67-L77 var responseHeaders = context.HttpContext.Response.Headers; CopyResponseHeaders(context.ProxyResponse.Headers, responseHeaders); if (context.ProxyResponse.Content != null) { CopyResponseHeaders(context.ProxyResponse.Content.Headers, responseHeaders); } context.HeadersCopied = true; return(default);
// Assumes the response status code has been set on the HttpContext already. /// <inheritdoc/> public override ValueTask ApplyAsync(ResponseTransformContext context) { if (context is null) { throw new ArgumentNullException(nameof(context)); } if (Always || Success(context)) { var existingHeader = TakeHeader(context, HeaderName); if (Append) { var value = StringValues.Concat(existingHeader, Value); SetHeader(context, HeaderName, value); } else { SetHeader(context, HeaderName, Value); } } return(default);
/// <inheritdoc/> public override ValueTask ApplyAsync(ResponseTransformContext context) { return(_func(context)); }
internal static bool Success(ResponseTransformContext context) { // TODO: How complex should this get? Compare with http://nginx.org/en/docs/http/ngx_http_headers_module.html#add_header return(context.HttpContext.Response.StatusCode < 400); }
/// <summary> /// Sets the given header on the HttpResponse. /// </summary> public static void SetHeader(ResponseTransformContext context, string headerName, StringValues values) { context.HttpContext.Response.Headers[headerName] = values; }
/// <summary> /// Transforms the given response. The status and headers will have (optionally) already been /// copied to the <see cref="HttpResponse"/> and any changes should be made there. /// </summary> public abstract ValueTask ApplyAsync(ResponseTransformContext context);