예제 #1
0
        /// <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.
        /// See <see cref="RequestUtilities.MakeDestinationAddress(string, PathString, QueryString)"/> for constructing a custom request Uri.
        /// The string parameter represents the destination URI prefix that should be used when constructing the RequestUri.
        /// The headers are copied by the base implementation, excluding some protocol headers like HTTP/2 pseudo headers (":authority").
        /// </summary>
        /// <param name="httpContext">The incoming request.</param>
        /// <param name="proxyRequest">The outgoing proxy request.</param>
        /// <param name="destinationPrefix">The uri prefix for the selected destination server which can be used to create the RequestUri.</param>
        public virtual ValueTask TransformRequestAsync(HttpContext httpContext, HttpRequestMessage proxyRequest, string destinationPrefix)
        {
            foreach (var header in httpContext.Request.Headers)
            {
                var headerName  = header.Key;
                var headerValue = header.Value;
                if (RequestUtilities.ShouldSkipRequestHeader(headerName))
                {
                    continue;
                }

                RequestUtilities.AddHeader(proxyRequest, headerName, headerValue);
            }

            // https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.3
            // If a message is received with both a Transfer-Encoding and a
            // Content-Length header field, the Transfer-Encoding overrides the
            // Content-Length.  Such a message might indicate an attempt to
            // perform request smuggling (Section 9.5) or response splitting
            // (Section 9.4) and ought to be handled as an error.  A sender MUST
            // remove the received Content-Length field prior to forwarding such
            // a message downstream.
            if (httpContext.Request.Headers.ContainsKey(HeaderNames.TransferEncoding) &&
                httpContext.Request.Headers.ContainsKey(HeaderNames.ContentLength))
            {
                proxyRequest.Content?.Headers.Remove(HeaderNames.ContentLength);
            }

            // https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.2.2
            // The only exception to this is the TE header field, which MAY be
            // present in an HTTP/2 request; when it is, it MUST NOT contain any
            // value other than "trailers".
            if (ProtocolHelper.IsHttp2OrGreater(httpContext.Request.Protocol))
            {
                var te = httpContext.Request.Headers.GetCommaSeparatedValues(HeaderNames.TE);
                if (te != null)
                {
                    for (var i = 0; i < te.Length; i++)
                    {
                        if (string.Equals(te[i], "trailers", StringComparison.OrdinalIgnoreCase))
                        {
                            var added = proxyRequest.Headers.TryAddWithoutValidation(HeaderNames.TE, te[i]);
                            Debug.Assert(added);
                            break;
                        }
                    }
                }
            }

            return(default);
예제 #2
0
        /// <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.
        /// See <see cref="RequestUtilities.MakeDestinationAddress(string, PathString, QueryString)"/> for constructing a custom request Uri.
        /// The string parameter represents the destination URI prefix that should be used when constructing the RequestUri.
        /// The headers are copied by the base implementation, excluding some protocol headers like HTTP/2 pseudo headers (":authority").
        /// </summary>
        /// <param name="httpContext">The incoming request.</param>
        /// <param name="proxyRequest">The outgoing proxy request.</param>
        /// <param name="destinationPrefix">The uri prefix for the selected destination server which can be used to create the RequestUri.</param>
        public virtual ValueTask TransformRequestAsync(HttpContext httpContext, HttpRequestMessage proxyRequest, string destinationPrefix)
        {
            foreach (var header in httpContext.Request.Headers)
            {
                var headerName  = header.Key;
                var headerValue = header.Value;
                if (StringValues.IsNullOrEmpty(headerValue) ||
                    RequestUtilities.ShouldSkipRequestHeader(headerName))
                {
                    continue;
                }

                RequestUtilities.AddHeader(proxyRequest, headerName, headerValue);
            }

            return(default);