coupergateway / couper

Couper is a lightweight API gateway designed to support developers in building and operating API-driven Web projects
https://couper.io
MIT License
84 stars 15 forks source link

Multiple files sections lead to "route not found" #786

Closed erwinschliske closed 2 months ago

erwinschliske commented 10 months ago

Describe the bug I am trying to deliver a website with assets. The requirement is that everything except the assets is protected by authentication. I have therefore created two files sections, one with authentication, one without. Then I have chosen different base_path and document_root.

As a result, I get a 404 error for both / and /assets/icon.png.

Here is a screenshot of my folder structure and the relevant part of the couper config.

Screenshot 2023-11-13 at 11 55 34

To Reproduce Steps to reproduce the behavior:

  1. Which Couper version? Run couper version or docker run coupergateway/couper version

1.12.1 2023-03-20 233f0d7 go version go1.19.6 darwin/amd64

  1. Provide your configuration file *.hcl. Remove sensitive data.
server {

    files "htdocs" {
        base_path = "/"
        document_root = "../htdocs"
        access_control = ["AccessToken"]
    }

    files "assets" {
        base_path = "/assets"
        document_root = "../assets"
    }
}
  1. Provide a curl call for reproduction

curl 'http://localhost:8080/'

  1. See an error response or error log.
{
  "error": {
    "id":      "cl906224io83a3975kr0",
    "message": "route not found error",
    "path":    "/",
    "status":  404
  }
}

Expected behavior For / index.html is delivered from the htdocs folder, for /assets/icon.png the file icon.png is delivered from the assets folder.

johakoch commented 7 months ago

@erwinschliske I cannot reproduce the 404 on http://localhost:8080/, but a 404 on http://localhost:8080/assets/icon.png.

Unfortunately the "htdocs" files handler is sorted before the "assets" files handler, and so is used even for requests to "/assets/icon.png".

If I add a path segment to the basepaths ("/files" and "/files/assets"), everything is as I'd expect ("longer" "/files/assets" wins against "shorter" "/files" when requesting "/files/assets/icon.png").

@malud Any idea why the sorting in server.SortPathPatterns() sorts "/" before "/a" (while sorting "/**" after "/a/**"), as in TestSortPathPatterns() (server/mux_test.go)? BTW, in RegisterConfigured() (server/mux.go) the utils.JoinOpenAPIPath(path, "/**") for entries of m.opts.FileRoutes is done after sorting.

So I see two options:

johakoch commented 7 months ago

If I have an additional api block (even empty, equivalent to base_path = "/"),

server {
  files "htdocs" {
    base_path = "/"
    document_root = "./htdocs"
  }

  files "assets" {
    base_path = "/assets"
    document_root = "./assets"
  }

  api {
  }
}

I can reproduce the 404 on http://localhost:8080/. That is, because the api block (with implicit base_path = "/") takes precedence over the files block (with explicit base_path = "/").