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)); }
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(); }
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); }
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(); }
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(); }
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); }
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); }
/// <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); }
public bool Equals(EdgeKey other) { return (IsCorsPreflightRequest == other.IsCorsPreflightRequest && HttpMethods.Equals(HttpMethod, other.HttpMethod)); }