1

I'm having issues with how browser resolves relative path to scripts. The setup is that I have simple go server that serves one html page from root "/" location, the html page contains script tag with relative path to script (the path = "./script.js"). Then, I have a reverse proxy that proxies that server but from location "/hello". The problem I'm facing is that browser resolves path "./script.js" in that html page as "/script.js", which then doesn't go through the proxy, since I proxy at "/hello" and not root.

The question is why ? If the path is relative, shouldn't that mean that if for browser we are at "/hello" then "./script.js" should become "/hello/script.js" ? How do I fix it ?

here's how reverse proxy is set up:

    targetURL, _ := url.Parse("https://127.0.0.1:12345")
    proxy := httputil.NewSingleHostReverseProxy(targetURL)

    http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
        log.Printf("hello request URL: %s\n", r.URL)
        proxy.ServeHTTP(w, r)
        log.Printf("hello response: %+v\n", w)
    })

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        log.Printf("root request URL: %s\n", r.URL)
        log.Printf("root request: %+v\n", r)
    })

    proxy.Director = func(req *http.Request) {
        req.URL.Scheme = targetURL.Scheme
        req.URL.Host = targetURL.Host
        req.Host = req.URL.Host // preserve the original Host

        req.Header.Del("If-None-Match")
        req.Header.Del("If-Modified-Since")
        req.Header.Set("Accept-Encoding", "")

        if strings.Contains(req.URL.Path, "/hello") {
            req.URL.Path = strings.Replace(req.URL.Path, "/hello", "/", 1)
            fmt.Printf("replaced: %s\n", req.URL.Path)
        }
    }

    log.Fatal(http.ListenAndServe(":4321", nil))

Here I replace the "/hello" prefix before sending request to the target along with changing host. Also, I print if there are requests through the root, just to debug if any (and there are for idk the reason, script.js request goes through the root instead of /hello)

And here's the proxied server:

func HelloServer(w http.ResponseWriter, req *http.Request) {
    w.Header().Set("Content-Type", "text/html")
    t := template.New("test")
    t, _ = template.ParseFiles("page.html")
    t.Execute(w, "")
}

func main() {
    http.HandleFunc("/", HelloServer)

    err := http.ListenAndServeTLS(":12345", "combined.pem", "kk.key", nil)
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

in which just one page.html is served from root.

The page.html that contains relative path to the script:

<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Swagger UI</title>
  </head>

  <body>
    <div id="swagger-ui"></div>
    <script src="./script.js" charset="UTF-8"> </script>
  </body>
</html>

I've checked the proxied server on browser "http://127.0.0.1:4321/hello" (Google chrome/Safari), in dev tools I see that html page is loaded, but path to "./script.js" is "http://127.0.0.1:4321/script.js", without the prefix...

oyevtushe
  • 11
  • 1
  • «but path to … is …»–could you clarify this? Do you mean that when you see in the devtools that your browser is making a request to `http://127.0.0.1:4321/hello`, that request is immediately followed by it making a request to `http://127.0.0.1:4321/script.js`? My guess is that you should add `/` to both your URL and your path munging code as `/hello` is interpreted as pointing at a "leaf" resource, so the "base URL" stays `http://127.0.0.1:4321/`. – kostix Jun 06 '23 at 14:32
  • …IOW, when you ask your browser to fetch `http://127.0.0.1:4321/hello`, it understands that as a command to fetch a resource named "hello" located "at" `http://127.0.0.1:4321`, and the base URL is the latter one. Asking instead for `http://127.0.0.1:4321/hello/` would request a representation of the "directory" (that's an incorrect term, but anyway), and that'd be the base URL since it does not name a particular entity under _that_ directory (that is, base). – kostix Jun 06 '23 at 14:34
  • A good rundown about the situation with the trailing slash is [here](http://web.archive.org/web/20200925183436/http://sebastians-pamphlets.com/thou-must-not-steal-the-trailing-slash-from-my-urls/) (the original URL appears to be failing at the moment). – kostix Jun 06 '23 at 14:37
  • To proxy the subtree, use the path `/hello/`: `http.HandleFunc("/hello/" ...`. With this change, the mux redirects `/hello` to `/hello/`. The browser resolves the reference to `./script.js` in `/hello/` to `/hello/script.js`. – Charlie Tumahai Jun 06 '23 at 15:58
  • That was it @kostix, thank you for the link and explanation ! CharlieTumahai, I've changed the code as you've suggested and it works ! You both basically answered the question, but in comments, so you can post it as an answer and I will accept it. – oyevtushe Jun 06 '23 at 21:14
  • 1
    See [Directory listing wrong links in golang http.FileServer()](https://stackoverflow.com/q/46403678/5728991) for a similar question with a detailed answer. The FileServer in that question corresponds to the proxy server in this question. – Charlie Tumahai Jun 07 '23 at 02:02

0 Answers0