-
-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #23 from Mattiav8/redirectMiddleware
Add HTTPSRedirection Middleware
- Loading branch information
Showing
4 changed files
with
123 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
25 changes: 25 additions & 0 deletions
25
Sources/VaporSecurityHeaders/Configurations/HTTPSRedirectMiddleware.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import Vapor | ||
|
||
public class HTTPSRedirectMiddleware: Middleware { | ||
|
||
public init() {} | ||
|
||
public func respond(to request: Request, chainingTo next: Responder) -> EventLoopFuture<Response> { | ||
if request.application.environment == .development { | ||
return next.respond(to: request) | ||
} | ||
|
||
let proto = request.headers.first(name: "X-Forwarded-Proto") | ||
?? request.url.scheme | ||
?? "http" | ||
|
||
guard proto == "https" else { | ||
guard let host = request.headers.first(name: .host) else { | ||
return request.eventLoop.makeFailedFuture(Abort(.badRequest)) | ||
} | ||
let httpsURL = "https://" + host + "\(request.url)" | ||
return request.redirect(to: "\(httpsURL)", type: .permanent).encodeResponse(for: request) | ||
} | ||
return next.respond(to: request) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import XCTest | ||
|
||
@testable import Vapor | ||
|
||
import VaporSecurityHeaders | ||
|
||
class RedirectionTest: XCTestCase { | ||
|
||
// MARK: - Properties | ||
|
||
private var application: Application! | ||
private var eventLoopGroup: EventLoopGroup! | ||
private var request: Request! | ||
|
||
override func setUp() { | ||
eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1) | ||
application = Application(.testing, .shared(eventLoopGroup)) | ||
request = Request(application: application, method: .GET, on: eventLoopGroup.next()) | ||
} | ||
|
||
override func tearDownWithError() throws { | ||
application.shutdown() | ||
try eventLoopGroup.syncShutdownGracefully() | ||
} | ||
|
||
func testWithRedirectionMiddleware() throws { | ||
let expectedRedirectStatus: HTTPStatus = HTTPResponseStatus(statusCode: 301, reasonPhrase: "Moved permanently") | ||
request.headers.add(name: .host, value: "localhost:8080") | ||
let responseRedirected = try makeTestResponse(for: request, withRedirection: true) | ||
XCTAssertEqual(expectedRedirectStatus, responseRedirected.status) | ||
} | ||
func testWithoutRedirectionMiddleware() throws { | ||
let expectedNoRedirectStatus: HTTPStatus = HTTPResponseStatus(statusCode: 200, reasonPhrase: "Ok") | ||
request.headers.add(name: .host, value: "localhost:8080") | ||
let response = try makeTestResponse(for: request, withRedirection: false) | ||
XCTAssertEqual(expectedNoRedirectStatus, response.status) | ||
} | ||
|
||
func testOnDevelopmentEnvironment() throws { | ||
let expectedStatus: HTTPStatus = HTTPResponseStatus(statusCode: 200, reasonPhrase: "Ok") | ||
request.headers.add(name: .host, value: "localhost:8080") | ||
let response = try makeTestResponse(for: request, withRedirection: true, environment: .development) | ||
XCTAssertEqual(expectedStatus, response.status) | ||
} | ||
|
||
func testWithoutHost() throws { | ||
let expectedOutcome: String = "Abort.400: Bad Request" | ||
do { | ||
_ = try makeTestResponse(for: request, withRedirection: true) | ||
} catch (let error) { | ||
XCTAssertEqual(expectedOutcome, error.localizedDescription) | ||
} | ||
} | ||
|
||
func testWithProtoSet() throws { | ||
let expectedStatus: HTTPStatus = HTTPResponseStatus(statusCode: 200, reasonPhrase: "Ok") | ||
request.headers.add(name: .xForwardedProto, value: "https") | ||
let response = try makeTestResponse(for: request, withRedirection: true) | ||
XCTAssertEqual(expectedStatus, response.status) | ||
} | ||
|
||
private func makeTestResponse(for request: Request, withRedirection: Bool, environment: Environment? = nil) throws -> Response { | ||
application.middleware = Middlewares() | ||
if let environment = environment { | ||
application.environment = environment | ||
} | ||
if withRedirection == true { | ||
application.middleware.use(HTTPSRedirectMiddleware()) | ||
} | ||
try routes(application) | ||
return try application.responder.respond(to: request).wait() | ||
} | ||
|
||
func routes(_ app: Application) throws { | ||
try app.register(collection: RouteController()) | ||
} | ||
|
||
struct RouteController: RouteCollection { | ||
func boot(routes: RoutesBuilder) throws { | ||
routes.get(use: testing) | ||
} | ||
func testing(req: Request) throws -> String { | ||
return "Test" | ||
} | ||
} | ||
} |