I'm currently working with the maintainer of the beautiful sql-studio to make it possible to serve the application from a subpath, which would allow me to add support for running sql-studio as dependency-management-data's web interface.

As part of some investigations around this, I wanted to make a somewhat cursed attempt to perform some server-side rewriting so I could make changes like:

- <script type="module" crossorigin src="https://www.jvt.me/assets/index-Dc4xAj-D.js"></script> - <link rel="stylesheet" crossorigin href="https://www.jvt.me/assets/index-DpDMcPjm.css"> + <script type="module" crossorigin src="https://www.jvt.me/sql-studio/assets/index-Dc4xAj-D.js"></script> + <link rel="stylesheet" crossorigin href="https://www.jvt.me/sql-studio/assets/index-DpDMcPjm.css"> </head>

To do this, I've been using httputil.ReverseProxy, with an initial setup like:

package main import ( "log" "net/http" "net/http/httputil" "net/url" ) func main() { u, err := url.Parse("http://localhost:3030") if err != nil { log.Fatal(err) } proxy := httputil.NewSingleHostReverseProxy(u) mux := http.NewServeMux() mux.Handle("/sql-studio", proxy) log.Fatal(http.ListenAndServe(":8080", mux)) }

To perform the rewriting inside the proxy, I found this StackOverflow which indicated that I should use the ModifyResponse function, which allows us to do something like:

package main import ( "bytes" "io" "log" "net/http" "net/http/httputil" "net/url" "strconv" "strings" ) func main() { u, err := url.Parse("http://localhost:3030") if err != nil { log.Fatal(err) } proxy := httputil.NewSingleHostReverseProxy(u) proxy.ModifyResponse = func(r *http.Response) error { b, err := io.ReadAll(r.Body) if err != nil { return err } defer r.Body.Close() // this is pretty hacky, but as a step towards https://github.com/frectonz/sql-studio/issues/16 in the meantime of upstream support b = bytes.Replace(b, []byte("href=\"/"), []byte("href=\"/sql-studio/"), -1) // ... // make sure we set the body, and the relevant headers for well-formed clients to respect r.Body = io.NopCloser(bytes.NewReader(b)) r.ContentLength = int64(len(b)) r.Header.Set("Content-Length", strconv.Itoa(len(b))) return nil } mux := http.NewServeMux() mux.Handle("/sql-studio/", proxy) log.Fatal(http.ListenAndServe(":8080", mux)) }

Et voila, we can now rewrite the response body from the proxied service, but before it goes back to the caller.

Recent content in articles on Jamie Tanna | Software Engineer

https://www.jvt.me/kind/articles/