示例#1
0
        internal static bool IsCorsPreflightRequest(HttpContext httpContext, string httpMethod, out StringValues accessControlRequestMethod)
        {
            accessControlRequestMethod = default;
            var headers = httpContext.Request.Headers;

            return(HttpMethods.Equals(httpMethod, PreflightHttpMethod) &&
                   headers.ContainsKey(HeaderNames.Origin) &&
                   headers.TryGetValue(HeaderNames.AccessControlRequestMethod, out accessControlRequestMethod) &&
                   !StringValues.IsNullOrEmpty(accessControlRequestMethod));
        }
示例#2
0
        public async Task RequestWithDataAndNoContentLength_Success(string method)
        {
            using var server = Utilities.CreateDynamicHttpsServer(out var address, httpContext =>
            {
                Assert.True(HttpMethods.Equals(method, httpContext.Request.Method));
                Assert.True(httpContext.Request.CanHaveBody());
                Assert.Null(httpContext.Request.ContentLength);
                // The client didn't send this header, Http.Sys added it for back compat with HTTP/1.1.
                Assert.Equal("chunked", httpContext.Request.Headers.TransferEncoding);
                return(httpContext.Request.Body.CopyToAsync(httpContext.Response.Body));
            });

            await new HostBuilder()
            .UseHttp2Cat(address, async h2Connection =>
            {
                await h2Connection.InitializeConnectionAsync();

                h2Connection.Logger.LogInformation("Initialized http2 connection. Starting stream 1.");

                var headers = new[]
                {
                    new KeyValuePair <string, string>(HeaderNames.Method, method),
                    new KeyValuePair <string, string>(HeaderNames.Path, "/"),
                    new KeyValuePair <string, string>(HeaderNames.Scheme, "https"),
                    new KeyValuePair <string, string>(HeaderNames.Authority, "localhost:80"),
                };

                await h2Connection.StartStreamAsync(1, headers, endStream: false);

                await h2Connection.SendDataAsync(1, Encoding.UTF8.GetBytes("Hello World"), endStream: true);

                // Http.Sys no longer sends a window update here on later versions.
                if (Environment.OSVersion.Version < new Version(10, 0, 19041, 0))
                {
                    var windowUpdate = await h2Connection.ReceiveFrameAsync();
                    Assert.Equal(Http2FrameType.WINDOW_UPDATE, windowUpdate.Type);
                }

                await h2Connection.ReceiveHeadersAsync(1, decodedHeaders =>
                {
                    Assert.Equal("200", decodedHeaders[HeaderNames.Status]);
                });

                var dataFrame = await h2Connection.ReceiveFrameAsync();
                Http2Utilities.VerifyDataFrame(dataFrame, 1, endOfStream: false, length: 11);
                Assert.Equal("Hello World", Encoding.UTF8.GetString(dataFrame.Payload.Span));

                dataFrame = await h2Connection.ReceiveFrameAsync();
                Http2Utilities.VerifyDataFrame(dataFrame, 1, endOfStream: true, length: 0);

                h2Connection.Logger.LogInformation("Connection stopped.");
            })
            .Build().RunAsync();
        }
示例#3
0
    public override int GetDestination(HttpContext httpContext)
    {
        var httpMethod = httpContext.Request.Method;

        if (_supportsCorsPreflight && HttpMethodMatcherPolicy.IsCorsPreflightRequest(httpContext, httpMethod, out var accessControlRequestMethod))
        {
            return(HttpMethods.Equals(accessControlRequestMethod.ToString(), _method) ? _corsPreflightDestination : _corsPreflightExitDestination);
        }

        return(HttpMethods.Equals(httpMethod, _method) ? _destination : _exitDestination);
    }
示例#4
0
        public async Task RequestWithoutData_Success(string method)
        {
            using var server = Utilities.CreateDynamicHttpsServer(out var address, httpContext =>
            {
                Assert.True(HttpMethods.Equals(method, httpContext.Request.Method));
                Assert.False(httpContext.Request.CanHaveBody());
                Assert.Null(httpContext.Request.ContentLength);
                Assert.False(httpContext.Request.Headers.ContainsKey(HeaderNames.TransferEncoding));
                return(Task.CompletedTask);
            });

            await new HostBuilder()
            .UseHttp2Cat(address, async h2Connection =>
            {
                await h2Connection.InitializeConnectionAsync();

                h2Connection.Logger.LogInformation("Initialized http2 connection. Starting stream 1.");

                var headers = new[]
                {
                    new KeyValuePair <string, string>(HeaderNames.Method, method),
                    new KeyValuePair <string, string>(HeaderNames.Path, "/"),
                    new KeyValuePair <string, string>(HeaderNames.Scheme, "https"),
                    new KeyValuePair <string, string>(HeaderNames.Authority, "localhost:80"),
                };

                await h2Connection.StartStreamAsync(1, headers, endStream: true);

                await h2Connection.ReceiveHeadersAsync(1, decodedHeaders =>
                {
                    Assert.Equal("200", decodedHeaders[HeaderNames.Status]);
                });

                var dataFrame = await h2Connection.ReceiveFrameAsync();
                if (Environment.OSVersion.Version >= Win10_Regressed_DataFrame)
                {
                    // TODO: Remove when the regression is fixed.
                    // https://github.com/dotnet/aspnetcore/issues/23164#issuecomment-652646163
                    Http2Utilities.VerifyDataFrame(dataFrame, 1, endOfStream: false, length: 0);

                    dataFrame = await h2Connection.ReceiveFrameAsync();
                }
                Http2Utilities.VerifyDataFrame(dataFrame, 1, endOfStream: true, length: 0);

                h2Connection.Logger.LogInformation("Connection stopped.");
            })
            .Build().RunAsync();
        }
示例#5
0
    public async Task RequestWithoutData_Success(string method)
    {
        using var server = Utilities.CreateDynamicHttpsServer(out var address, httpContext =>
        {
            Assert.True(HttpMethods.Equals(method, httpContext.Request.Method));
            Assert.False(httpContext.Request.CanHaveBody());
            Assert.Null(httpContext.Request.ContentLength);
            Assert.False(httpContext.Request.Headers.ContainsKey(HeaderNames.TransferEncoding));
            return(Task.CompletedTask);
        });

        await new HostBuilder()
        .UseHttp2Cat(address, async h2Connection =>
        {
            await h2Connection.InitializeConnectionAsync();

            h2Connection.Logger.LogInformation("Initialized http2 connection. Starting stream 1.");

            var headers = new[]
            {
                new KeyValuePair <string, string>(InternalHeaderNames.Method, method),
                new KeyValuePair <string, string>(InternalHeaderNames.Path, "/"),
                new KeyValuePair <string, string>(InternalHeaderNames.Scheme, "https"),
                new KeyValuePair <string, string>(InternalHeaderNames.Authority, "localhost:80"),
            };

            await h2Connection.StartStreamAsync(1, headers, endStream: true);

            await h2Connection.ReceiveHeadersAsync(1, decodedHeaders =>
            {
                Assert.Equal("200", decodedHeaders[InternalHeaderNames.Status]);
            });

            var dataFrame = await h2Connection.ReceiveFrameAsync();
            Http2Utilities.VerifyDataFrame(dataFrame, 1, endOfStream: true, length: 0);

            h2Connection.Logger.LogInformation("Connection stopped.");
        })
        .Build().RunAsync();
    }
示例#6
0
            public override int GetDestination(HttpContext httpContext)
            {
                int destination;

                var httpMethod = httpContext.Request.Method;
                var headers    = httpContext.Request.Headers;

                if (_supportsCorsPreflight &&
                    HttpMethods.Equals(httpMethod, PreflightHttpMethod) &&
                    headers.ContainsKey(HeaderNames.Origin) &&
                    headers.TryGetValue(HeaderNames.AccessControlRequestMethod, out var accessControlRequestMethod) &&
                    !StringValues.IsNullOrEmpty(accessControlRequestMethod))
                {
                    return(_corsPreflightDestinations != null &&
                           _corsPreflightDestinations.TryGetValue(accessControlRequestMethod, out destination)
                        ? destination
                        : _corsPreflightExitDestination);
                }

                return(_destinations != null &&
                       _destinations.TryGetValue(httpMethod, out destination) ? destination : _exitDestination);
            }
示例#7
0
        private static bool ContainsHttpMethod(List <string> httpMethods, string httpMethod)
        {
            var methods = CollectionsMarshal.AsSpan(httpMethods);

            for (var i = 0; i < methods.Length; i++)
            {
                // This is a fast path for when everything is using static HttpMethods instances.
                if (object.ReferenceEquals(methods[i], httpMethod))
                {
                    return(true);
                }
            }

            for (var i = 0; i < methods.Length; i++)
            {
                if (HttpMethods.Equals(methods[i], httpMethod))
                {
                    return(true);
                }
            }

            return(false);
        }
示例#8
0
        /// <summary>
        /// For framework use only.
        /// </summary>
        /// <param name="httpContext"></param>
        /// <param name="candidates"></param>
        /// <returns></returns>
        public Task ApplyAsync(HttpContext httpContext, CandidateSet candidates)
        {
            if (httpContext == null)
            {
                throw new ArgumentNullException(nameof(httpContext));
            }

            if (candidates == null)
            {
                throw new ArgumentNullException(nameof(candidates));
            }

            // Returning a 405 here requires us to return keep track of all 'seen' HTTP methods. We allocate to
            // keep track of this beause we either need to keep track of the HTTP methods or keep track of the
            // endpoints - both allocate.
            //
            // Those code only runs in the presence of dynamic endpoints anyway.
            //
            // We want to return a 405 iff we eliminated ALL of the currently valid endpoints due to HTTP method
            // mismatch.
            bool?            needs405Endpoint = null;
            HashSet <string>?methods          = null;

            for (var i = 0; i < candidates.Count; i++)
            {
                // We do this check first for consistency with how 405 is implemented for the graph version
                // of this code. We still want to know if any endpoints in this set require an HTTP method
                // even if those endpoints are already invalid - hence the null-check.
                var metadata = candidates[i].Endpoint?.Metadata.GetMetadata <IHttpMethodMetadata>();
                if (metadata == null || metadata.HttpMethods.Count == 0)
                {
                    // Can match any method.
                    needs405Endpoint = false;
                    continue;
                }

                // Saw a valid endpoint.
                needs405Endpoint = needs405Endpoint ?? true;

                if (!candidates.IsValidCandidate(i))
                {
                    continue;
                }

                var httpMethod = httpContext.Request.Method;
                var headers    = httpContext.Request.Headers;
                if (metadata.AcceptCorsPreflight &&
                    HttpMethods.Equals(httpMethod, PreflightHttpMethod) &&
                    headers.ContainsKey(HeaderNames.Origin) &&
                    headers.TryGetValue(HeaderNames.AccessControlRequestMethod, out var accessControlRequestMethod) &&
                    !StringValues.IsNullOrEmpty(accessControlRequestMethod))
                {
                    needs405Endpoint = false; // We don't return a 405 for a CORS preflight request when the endpoints accept CORS preflight.
                    httpMethod       = accessControlRequestMethod;
                }

                var matched = false;
                for (var j = 0; j < metadata.HttpMethods.Count; j++)
                {
                    var candidateMethod = metadata.HttpMethods[j];
                    if (!HttpMethods.Equals(httpMethod, candidateMethod))
                    {
                        methods = methods ?? new HashSet <string>(StringComparer.OrdinalIgnoreCase);
                        methods.Add(candidateMethod);
                        continue;
                    }

                    matched          = true;
                    needs405Endpoint = false;
                    break;
                }

                if (!matched)
                {
                    candidates.SetValidity(i, false);
                }
            }

            if (needs405Endpoint == true)
            {
                // We saw some endpoints coming in, and we eliminated them all.
                httpContext.SetEndpoint(CreateRejectionEndpoint(methods !.OrderBy(m => m, StringComparer.OrdinalIgnoreCase)));
                httpContext.Request.RouteValues = null !;
            }

            return(Task.CompletedTask);
        }
示例#9
0
 public bool Equals(EdgeKey other)
 {
     return
         (IsCorsPreflightRequest == other.IsCorsPreflightRequest &&
          HttpMethods.Equals(HttpMethod, other.HttpMethod));
 }