From 42658b548e1dc0c1e6f715cc43ea89e885c25787 Mon Sep 17 00:00:00 2001 From: Nicolas Bachschmidt Date: Tue, 30 Jan 2024 18:34:06 +0100 Subject: [PATCH] Remove HeadResponder The HEAD method is identical to GET except that the server must not send content in the response (RFC 9110, section 9.3.2). The previous default behaviour of returning 200 OK to every HEAD request to a constant route is not standard-compliant. The new behaviour is to always forward the request to the GET route, unless the developer explicitly configured a custom HEAD route. --- .../Vapor/Responder/DefaultResponder.swift | 26 ------------------- Tests/VaporTests/RouteTests.swift | 21 +++------------ 2 files changed, 3 insertions(+), 44 deletions(-) diff --git a/Sources/Vapor/Responder/DefaultResponder.swift b/Sources/Vapor/Responder/DefaultResponder.swift index c342131261..1a2dece011 100644 --- a/Sources/Vapor/Responder/DefaultResponder.swift +++ b/Sources/Vapor/Responder/DefaultResponder.swift @@ -39,26 +39,6 @@ internal struct DefaultResponder: Responder { } } - // If the route isn't explicitly a HEAD route, - // and it's made up solely of .constant components, - // register a HEAD route with the same path - if route.method == .GET && - route.path.allSatisfy({ component in - if case .constant(_) = component { return true } - return false - }) { - let headRoute = Route( - method: .HEAD, - path: route.path, - responder: middleware.makeResponder(chainingTo: HeadResponder()), - requestType: route.requestType, - responseType: route.responseType) - - let headCachedRoute = CachedRoute(route: headRoute, responder: middleware.makeResponder(chainingTo: HeadResponder())) - - router.register(headCachedRoute, at: [.constant(HTTPMethod.HEAD.string)] + path) - } - router.register(cached, at: [.constant(route.method.string)] + path) } self.router = router @@ -155,12 +135,6 @@ internal struct DefaultResponder: Responder { } } -private struct HeadResponder: Responder { - func respond(to request: Request) -> EventLoopFuture { - request.eventLoop.makeSucceededFuture(.init(status: .ok)) - } -} - private struct NotFoundResponder: Responder { func respond(to request: Request) -> EventLoopFuture { request.eventLoop.makeFailedFuture(RouteNotFound()) diff --git a/Tests/VaporTests/RouteTests.swift b/Tests/VaporTests/RouteTests.swift index bf28872016..4ecbce263a 100644 --- a/Tests/VaporTests/RouteTests.swift +++ b/Tests/VaporTests/RouteTests.swift @@ -229,38 +229,23 @@ final class RouteTests: XCTestCase { } } - func testHeadRequestWithConstantPathReturnsOK() throws { + func testHeadRequestForwardedToGet() throws { let app = Application(.testing) defer { app.shutdown() } app.get("hello") { req -> String in - return "hi" - } - - try app.testable(method: .running(port: 0)).test(.HEAD, "/hello") { res in - XCTAssertEqual(res.status, .ok) - XCTAssertEqual(res.headers.first(name: .contentLength), "0") - XCTAssertEqual(res.body.readableBytes, 0) - } - } - - func testHeadRequestWithParameterForwardedToGet() throws { - let app = Application(.testing) - defer { app.shutdown() } - - app.get("hello", ":name") { req -> String in XCTAssertEqual(req.method, .HEAD) return "hi" } - try app.testable(method: .running(port: 0)).test(.HEAD, "/hello/joe") { res in + try app.testable(method: .running(port: 0)).test(.HEAD, "/hello") { res in XCTAssertEqual(res.status, .ok) XCTAssertEqual(res.headers.first(name: .contentLength), "2") XCTAssertEqual(res.body.readableBytes, 0) } } - func testExplicitHeadRouteHandlerOverridesGeneratedHandler() throws { + func testExplicitHeadRouteOverridesForwardingToGet() throws { let app = Application(.testing) defer { app.shutdown() }