package sitemap import ( "crypto/tls" "net/http/httptest" "os" "path/filepath" "testing" "git.golem15.com/golem15/summercms/modules/backpack" "git.golem15.com/golem15/summercms/modules/compass" ) // TestBackendURL pins the root URL the sitemap's absolute URLs and the // frontend_url rewrite start from: app.url when set; else the request's // Host with https for TLS, or for the last X-Forwarded-Proto hop of a peer // in http.trusted_proxies, while a client that sends the header directly // gets http. func TestBackendURL(t *testing.T) { app := func(t *testing.T, files map[string]string) *backpack.App { t.Helper() dir := t.TempDir() for name, body := range files { if err := os.WriteFile(filepath.Join(dir, name), []byte(body), 0o644); err != nil { t.Fatal(err) } } cfg, err := compass.Open(compass.Options{Dir: dir, Environ: []string{}}) if err != nil { t.Fatal(err) } return backpack.New(cfg) } trusted := app(t, map[string]string{"http.yaml": "trusted_proxies:\n - 10.0.0.0/8\n"}) for _, tc := range []struct { name string app *backpack.App remote string proto []string tls bool want string }{ {"app.url wins", app(t, map[string]string{"app.yaml": "url: https://api.example.test/\n"}), "203.0.113.9:1234", []string{"http"}, false, "https://api.example.test"}, {"plain request", trusted, "203.0.113.9:1234", nil, false, "http://h.test"}, {"TLS", trusted, "203.0.113.9:1234", nil, true, "https://h.test"}, {"trusted proxy says https", trusted, "10.1.2.3:5000", []string{"https"}, false, "https://h.test"}, {"trusted proxy, last hop wins", trusted, "10.1.2.3:5000", []string{"https, http"}, false, "http://h.test"}, {"trusted proxy, last header wins", trusted, "10.1.2.3:5000", []string{"http", "HTTPS"}, false, "https://h.test"}, {"untrusted client says https", trusted, "203.0.113.9:1234", []string{"https"}, false, "http://h.test"}, {"no trusted proxies configured", app(t, nil), "10.1.2.3:5000", []string{"https"}, false, "http://h.test"}, {"nil app", nil, "10.1.2.3:5000", []string{"https"}, false, "http://h.test"}, {"IPv4-mapped trusted peer", trusted, "[::ffff:10.1.2.3]:5000", []string{"https"}, false, "https://h.test"}, {"unparsable peer", trusted, "not-an-address", []string{"https"}, false, "http://h.test"}, } { t.Run(tc.name, func(t *testing.T) { r := httptest.NewRequest("GET", "http://h.test/sitemap.xml", nil) r.RemoteAddr = tc.remote for _, v := range tc.proto { r.Header.Add("X-Forwarded-Proto", v) } if tc.tls { r.TLS = &tls.ConnectionState{} } if got := backendURL(tc.app, r); got != tc.want { t.Fatalf("backendURL = %q, want %q", got, tc.want) } }) } }