air-verse / air

☁️ Live reload for Go apps

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Browser reload script not injected on proxy port

DrVeseli opened this issue · comments

M2 macbook air

Everything except the browser reload works, changes are seen, the app reloads but the browser does not.

There is no <script>new EventSource... at the bottom on 8080 or 8090

I tried both "air" and "air -c .air.toml" . What am I missing?

here is the full .toml file

root = "."
testdata_dir = "testdata"
tmp_dir = "tmp"

[build]
  args_bin = []
  bin = "tmp/main"
  cmd = "go build -o ./tmp/main ."
  delay = 1000
  exclude_dir = ["assets", "tmp", "vendor", "testdata"]
  exclude_file = []
  exclude_regex = ["_test.go"]
  exclude_unchanged = false
  follow_symlink = false
  full_bin = ""
  include_dir = []
  include_ext = ["go", "tpl", "tmpl", "html"]
  include_file = []
  kill_delay = "0s"
  log = "build-errors.log"
  poll = false
  poll_interval = 0
  post_cmd = []
  pre_cmd = []
  rerun = false
  rerun_delay = 500
  send_interrupt = false
  stop_on_error = false

[color]
  app = ""
  build = "yellow"
  main = "magenta"
  runner = "green"
  watcher = "cyan"

[log]
  main_only = false
  time = false

[misc]
  clean_on_exit = false

[screen]
  clear_on_rebuild = true
  keep_scroll = true


[proxy]
  enabled = true
  proxy_port = 8090
  app_port = 8080

Are you accessing localhost:8090?

Im not sure how to check the error code in the browser, sorry. There is essentially no error, I can access the app on both 8080 and 8090, when i inspect them they are identical. The script is not present in either. I have the latest release of air and im on go 1.22.1

edit i do have the body tag

You need to access always the proxy port (8090), and make sure your app returns Content-Type text/html and has a <body></body> tag. The script will be injected before the end of the body tag

I am on 8090. I have and I return text/html. The code is not getting injected.

There is a different script at the end (gtag) could it be interfering in some way?

Can you share your repository link?

Sorry I can't. Here is everything I think might be relevant. If it ends up not being enough i will try to recreate the problem on a smaller project then link it.

mux := http.NewServeMux()
	wrappedMux := gziphandler.GzipHandler(mux)

mux.HandleFunc("/", handleHome)

http.ListenAndServe(":8080", wrappedMux)

func handleHome(w http.ResponseWriter, r *http.Request) {
	// Serve the index.html file
	http.StripPrefix("/", http.FileServer(http.Dir("./src"))).ServeHTTP(w, r)

the index.html file is super simple and does have a body tag so thats not an issue.

Are there any errors in the terminal? When you stop running air, both app and proxy port are gone, and you restart and both ports work?

Correct, and there are no errors. Also everything else works flawlessly. I will need a few hours but I will try to clone the project, strip some sensitive stuff and link it here so you can poke and prod. Thanks for all the support so far

@ndajr Here is the repo https://github.com/DrVeseli/Kreateni

if you are pulling it on your machine export ENV=DEV so you can skip some init work

I ran air locally with you project, and it was weird. When loading /, proxy server called your app multiple times and the headers didn't contain text/html content type, that's why it skipped the script injection. This is because your handleHome function is a file server based on src, stripping /index.html from the final URL, that's why it is able to serve the page, but it's highly dangerous. Your app will be easily exposed to path traversal attacks (since you're serving a file server on the root endpoint) and can end up exposing sensitive files and directories. My suggestion for you is to move all your html pages to a separate folder like views and use go templates for rendering them. Go template/html package will escape the page content and prevents security issues like XSS attacks. I was able to see the injected script by doing the following:

  1. Comment wrappedMux and serve mux directly with http.ListenAndServe(":8080", mux). You can still use gzip for static content, but not for the html pages
  2. handleHome code (please do a proper error handling there as well)
func handleHome(w http.ResponseWriter, r *http.Request) {
	tmpl, _ := template.New("index.html").ParseFiles("./src/index.html")
	_ = tmpl.Execute(w, nil)
}

It visually breaks the page, you'll need to move your assets to a different endpoint like /assets and update the links in your HTML files, see https://blog.devgenius.io/serving-css-in-gos-native-server-8bc58d85d0b2.

Its still text/html on my end.
Screenshot 2024-05-29 at 08 31 31

Was it gzip that was interfering or the FS/strip function? Thanks a lot for all the help.