diff --git a/src/Grpc.AspNetCore.Server/Model/Internal/ServiceRouteBuilder.cs b/src/Grpc.AspNetCore.Server/Model/Internal/ServiceRouteBuilder.cs index 42ee0cce1..6f54b56b8 100644 --- a/src/Grpc.AspNetCore.Server/Model/Internal/ServiceRouteBuilder.cs +++ b/src/Grpc.AspNetCore.Server/Model/Internal/ServiceRouteBuilder.cs @@ -131,19 +131,20 @@ internal static void CreateUnimplementedEndpoints( private static void CreateUnimplementedEndpoint(IEndpointRouteBuilder endpointRouteBuilder, string pattern, string displayName, RequestDelegate requestDelegate) { - var routePattern = RoutePatternFactory.Parse(pattern, defaults: null, new { contentType = GrpcContentTypeConstraint.Instance }); + var routePattern = RoutePatternFactory.Parse(pattern, defaults: null, new { contentType = GrpcUnimplementedConstraint.Instance }); var endpointBuilder = endpointRouteBuilder.Map(routePattern, requestDelegate); endpointBuilder.Add(ep => { ep.DisplayName = $"gRPC - {displayName}"; - ep.Metadata.Add(new HttpMethodMetadata(new[] { "POST" })); + // Don't add POST metadata here. It will return 405 status for other HTTP methods which isn't + // what we want. That check is made in a constraint instead. }); } - private class GrpcContentTypeConstraint : IRouteConstraint + private class GrpcUnimplementedConstraint : IRouteConstraint { - public static readonly GrpcContentTypeConstraint Instance = new GrpcContentTypeConstraint(); + public static readonly GrpcUnimplementedConstraint Instance = new GrpcUnimplementedConstraint(); public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection) { @@ -152,10 +153,15 @@ public bool Match(HttpContext httpContext, IRouter route, string routeKey, Route return false; } + if (!HttpMethods.IsPost(httpContext.Request.Method)) + { + return false; + } + return GrpcProtocolHelpers.IsGrpcContentType(httpContext.Request.ContentType); } - private GrpcContentTypeConstraint() + private GrpcUnimplementedConstraint() { } } diff --git a/test/FunctionalTests/Server/UnimplementedTests.cs b/test/FunctionalTests/Server/UnimplementedTests.cs index f3f4cb8af..5406176db 100644 --- a/test/FunctionalTests/Server/UnimplementedTests.cs +++ b/test/FunctionalTests/Server/UnimplementedTests.cs @@ -82,9 +82,11 @@ public async Task HttpContextExtensionMethod_ReturnContextInTrailer() response.AssertTrailerStatus(StatusCode.Unimplemented, "Service is unimplemented."); } - [TestCase("application/grpc", HttpStatusCode.OK, StatusCode.Unimplemented)] - [TestCase("application/json", (HttpStatusCode)418, null)] - public async Task UnimplementedContentType_ReturnUnimplementedForAppGrpc(string contentType, HttpStatusCode httpStatusCode, StatusCode? grpcStatusCode) + [TestCase("application/grpc", "POST", HttpStatusCode.OK, StatusCode.Unimplemented)] + [TestCase("application/grpc", "GET", (HttpStatusCode)404, null)] + [TestCase("application/json", "POST", (HttpStatusCode)404, null)] + [TestCase("application/json", "GET", (HttpStatusCode)404, null)] + public async Task UnimplementedContentType_ReturnUnimplementedForAppGrpc(string contentType, string httpMethod, HttpStatusCode httpStatusCode, StatusCode? grpcStatusCode) { // Arrange var requestMessage = new HelloRequest @@ -96,6 +98,7 @@ public async Task UnimplementedContentType_ReturnUnimplementedForAppGrpc(string MessageHelpers.WriteMessage(requestStream, requestMessage); var httpRequest = GrpcHttpHelper.Create("HasMapped/Extra"); + httpRequest.Method = new HttpMethod(httpMethod); httpRequest.Content = new StreamContent(requestStream); httpRequest.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType); diff --git a/testassets/FunctionalTestsWebsite/Startup.cs b/testassets/FunctionalTestsWebsite/Startup.cs index f9f003ccd..3b8a685c4 100644 --- a/testassets/FunctionalTestsWebsite/Startup.cs +++ b/testassets/FunctionalTestsWebsite/Startup.cs @@ -133,12 +133,6 @@ public void Configure(IApplicationBuilder app) endpoints.DataSources.Add(endpoints.ServiceProvider.GetRequiredService()); - endpoints.Map("{FirstSegment}/{SecondSegment}", context => - { - context.Response.StatusCode = StatusCodes.Status418ImATeapot; - return Task.CompletedTask; - }); - endpoints.MapGet("/generateJwtToken", context => { return context.Response.WriteAsync(GenerateJwtToken());