public override async Task TransformResponseTrailersAsync(HttpContext httpContext, HttpResponseMessage proxyResponse)
        {
            if (ShouldCopyResponseTrailers.GetValueOrDefault(true))
            {
                await base.TransformResponseTrailersAsync(httpContext, proxyResponse);
            }

            if (ResponseTrailerTransforms.Count == 0)
            {
                return;
            }

            // Only run the transforms if trailers are actually supported by the client response.
            var responseTrailersFeature = httpContext.Features.Get <IHttpResponseTrailersFeature>();
            var outgoingTrailers        = responseTrailersFeature?.Trailers;

            if (outgoingTrailers != null && !outgoingTrailers.IsReadOnly)
            {
                var transformContext = new ResponseTrailersTransformContext()
                {
                    HttpContext   = httpContext,
                    ProxyResponse = proxyResponse,
                    HeadersCopied = ShouldCopyResponseTrailers.GetValueOrDefault(true),
                };

                foreach (var responseTrailerTransform in ResponseTrailerTransforms)
                {
                    await responseTrailerTransform.ApplyAsync(transformContext);
                }
            }
        }
Пример #2
0
        /// <summary>
        /// Sets the given trailer on the HttpResponse.
        /// </summary>
        public static void SetHeader(ResponseTrailersTransformContext context, string headerName, StringValues values)
        {
            var responseTrailersFeature = context.HttpContext.Features.Get <IHttpResponseTrailersFeature>();
            var responseTrailers        = responseTrailersFeature.Trailers;

            // Support should have already been checked by the caller.
            Debug.Assert(responseTrailers != null);
            Debug.Assert(!responseTrailers.IsReadOnly);

            responseTrailers[headerName] = values;
        }
        public async Task AddResponseTrailer_Success(string startValue, int status, string value, bool append, bool always, string expected)
        {
            var httpContext    = new DefaultHttpContext();
            var trailerFeature = new TestTrailersFeature();

            httpContext.Features.Set <IHttpResponseTrailersFeature>(trailerFeature);
            trailerFeature.Trailers["name"] = startValue.Split(";", System.StringSplitOptions.RemoveEmptyEntries);
            httpContext.Response.StatusCode = status;
            var transformContext = new ResponseTrailersTransformContext()
            {
                HttpContext   = httpContext,
                ProxyResponse = new HttpResponseMessage(),
                HeadersCopied = true,
            };
            var transform = new ResponseTrailerValueTransform("name", value, append, always);
            await transform.ApplyAsync(transformContext);

            Assert.Equal(expected.Split(";", System.StringSplitOptions.RemoveEmptyEntries), trailerFeature.Trailers["name"]);
        }
Пример #4
0
        // Assumes the response status code has been set on the HttpContext already.
        /// <inheritdoc/>
        public override ValueTask ApplyAsync(ResponseTrailersTransformContext 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 if (!string.IsNullOrEmpty(Value))
                {
                    SetHeader(context, HeaderName, Value);
                }
                // If the given value is empty, any existing header is removed.
            }

            return(default);
Пример #5
0
        /// <summary>
        /// Removes and returns the current trailer value by first checking the HttpResponse
        /// and falling back to the value from HttpResponseMessage only if
        /// <see cref="ResponseTrailersTransformContext.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(ResponseTrailersTransformContext context, string headerName)
        {
            var existingValues          = StringValues.Empty;
            var responseTrailersFeature = context.HttpContext.Features.Get <IHttpResponseTrailersFeature>();
            var responseTrailers        = responseTrailersFeature.Trailers;

            // Support should have already been checked by the caller.
            Debug.Assert(responseTrailers != null);
            Debug.Assert(!responseTrailers.IsReadOnly);

            if (responseTrailers.TryGetValue(headerName, out var responseValues))
            {
                responseTrailers.Remove(headerName);
                existingValues = responseValues;
            }
            else if (!context.HeadersCopied &&
                     context.ProxyResponse.TrailingHeaders.TryGetValues(headerName, out var values))
            {
                existingValues = (string[])values;
            }

            return(existingValues);
        }
Пример #6
0
 /// <inheritdoc/>
 public override ValueTask ApplyAsync(ResponseTrailersTransformContext context)
 {
     return(_func(context));
 }
Пример #7
0
 /// <summary>
 /// Transforms the given response trailers. The trailers will have (optionally) already been
 /// copied to the <see cref="HttpResponse"/> and any changes should be made there.
 /// </summary>
 public abstract Task ApplyAsync(ResponseTrailersTransformContext context);
 private static bool Success(ResponseTrailersTransformContext 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);
 }