Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Directory Handler for static files #49

Open
gotev opened this issue Dec 9, 2022 · 2 comments
Open

Directory Handler for static files #49

gotev opened this issue Dec 9, 2022 · 2 comments

Comments

@gotev
Copy link

gotev commented Dec 9, 2022

First of all, thanks for this really good library!

With this setup:

let server = HTTPServer(port: 8080)

let root = URL(fileURLWithPath: "/Users/myUser/myStaticDir")

let route = HTTPRoute(method: .GET, path: "/static/*")
let handler = DirectoryHTTPHandler(root: root, serverPath: "static")

await server.appendRoute(route, to: handler)

try await server.start()

When I perform:

curl -L -vv http://localhost:8080/static/index.html

I'm always getting a 404.

That's because:

guard request.path.hasPrefix(serverPath) else {

never matches, because request.path will always be /static/index.html, so I find this example to be wrong: https://github.com/swhitty/FlyingFox#directoryhttphandler

To make it work I had to write the handler like this:

let handler = DirectoryHTTPHandler(root: root, serverPath: "/static/")

But then I found out that if I want to also handle the default file to be index.html when not explicitly specifying it:

curl -L -vv http://localhost:8080/static/

or

curl -L -vv http://localhost:8080/static

I have to also add:

let fileRoute = HTTPRoute(method: .GET, path: "/static")
let fileHandler = FileHTTPHandler(path: root.appendingPathComponent("index.html"), contentType: "text/html")
await server.appendRoute(fileRoute, to: fileHandler)

Then I thought this is a very common scenario one would expect to work with minimal work, so I written this extension:

extension HTTPServer {
    func appendStaticRoute(_ route: String, root: URL, defaultFileName: String = "index.html", withContentType contentType: String = "text/html") {
        appendRoute(HTTPRoute(method: .GET, path: "/\(route)/*"), to: DirectoryHTTPHandler(root: root, serverPath: "/\(route)/"))
        appendRoute(HTTPRoute(method: .GET, path: "/\(route)/"), to: FileHTTPHandler(path: root.appendingPathComponent(defaultFileName), contentType: contentType))
        appendRoute(HTTPRoute(method: .GET, path: "/\(route)"), to: .redirect(to: "/\(route)/"))
    }

    func appendStaticRoute(_ route: String, bundle: Bundle = .main, defaultFileName: String = "index.html", withContentType contentType: String = "text/html") throws {
        guard let root = bundle.resourceURL else { throw HTTPUnhandledError() }
        appendStaticRoute(route, root: root, defaultFileName: defaultFileName, withContentType: contentType)
    }
}

Which allows you to achieve the same with only:

let server = HTTPServer(port: 8080)

let root = URL(fileURLWithPath: "/Users/myUser/myStaticDir")

await server.appendStaticRoute("static", root: root)

try await server.start()

And so here I am, posting this. If you think it's a valuable addition, feel free to add it in the library 🍻

@dom-do-more
Copy link

Excellent! Just what I needed! Many thanks.

@swhitty
Copy link
Owner

swhitty commented Mar 5, 2023

Thank you for reporting this discrepancy in the docs and annoyance.

I have merged a change that is more lenient when processing the serverPath making the leading and trialing / delimiters optional.
#55

I will have a think about severing a default file within the handler.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants