feat: add withCORSMiddleware for CORS support
sinwoojin committed
Dec 15, 2025 at 13:38 UTC
598b54aded9e29290d48d434ab2371c07182741a
1 file changed
+19
-28
cmd/relay-server/serve.go
+19
-28
@@ -44,23 +44,13 @@ func serveHTTP(addr string, serv *portal.RelayServer, admin *Admin, frontend *Fr
44
}
45
46
// Portal app assets (JS, CSS, etc.) - served from /app/
47
- appMux.HandleFunc("/app/", func(w http.ResponseWriter, r *http.Request) {
48
- utils.SetCORSHeaders(w)
49
- if r.Method == http.MethodOptions {
50
- w.WriteHeader(http.StatusOK)
51
- return
52
- }
47
+ appMux.HandleFunc("/app/", withCORSMiddleware(func(w http.ResponseWriter, r *http.Request) {
48
p := strings.TrimPrefix(r.URL.Path, "/app/")
49
frontend.ServeAppStatic(w, r, p, serv)
55
- })
50
+ }))
51
52
// Portal frontend files (for unified caching)
58
- appMux.HandleFunc("/frontend/", func(w http.ResponseWriter, r *http.Request) {
59
- utils.SetCORSHeaders(w)
60
- if r.Method == http.MethodOptions {
61
- w.WriteHeader(http.StatusOK)
62
- return
63
- }
53
+ appMux.HandleFunc("/frontend/", withCORSMiddleware(func(w http.ResponseWriter, r *http.Request) {
54
p := strings.TrimPrefix(r.URL.Path, "/frontend/")
55
if p == "manifest.json" {
56
frontend.ServeDynamicManifest(w, r)
@@ -68,7 +58,7 @@ func serveHTTP(addr string, serv *portal.RelayServer, admin *Admin, frontend *Fr
58
}
59
60
frontend.ServePortalStaticFile(w, r, p)
71
- })
61
+ }))
62
63
// Tunnel installer script and binaries
64
appMux.HandleFunc("/tunnel", func(w http.ResponseWriter, r *http.Request) {
@@ -133,19 +123,14 @@ func serveHTTP(addr string, serv *portal.RelayServer, admin *Admin, frontend *Fr
123
portalMux := http.NewServeMux()
124
125
// Static file handler for /frontend/ (for unified caching)
136
- portalMux.HandleFunc("/frontend/", func(w http.ResponseWriter, r *http.Request) {
137
- utils.SetCORSHeaders(w)
138
- if r.Method == http.MethodOptions {
139
- w.WriteHeader(http.StatusOK)
140
- return
141
- }
126
+ portalMux.HandleFunc("/frontend/", withCORSMiddleware(func(w http.ResponseWriter, r *http.Request) {
127
p := strings.TrimPrefix(r.URL.Path, "/frontend/")
128
if p == "manifest.json" {
129
frontend.ServeDynamicManifest(w, r)
130
return
131
}
132
frontend.ServePortalStaticFile(w, r, p)
148
- })
133
+ }))
134
135
// Service worker for portal subdomains (serve from dist/wasm)
136
portalMux.HandleFunc("/service-worker.js", func(w http.ResponseWriter, r *http.Request) {
@@ -153,19 +138,14 @@ func serveHTTP(addr string, serv *portal.RelayServer, admin *Admin, frontend *Fr
138
})
139
140
// Root and SPA fallback for portal subdomains
156
- portalMux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
157
- utils.SetCORSHeaders(w)
158
- if r.Method == http.MethodOptions {
159
- w.WriteHeader(http.StatusOK)
160
- return
161
- }
141
+ portalMux.HandleFunc("/", withCORSMiddleware(func(w http.ResponseWriter, r *http.Request) {
142
if r.URL.Path == "/" {
143
// Serve portal HTML from dist/wasm
144
frontend.ServeStaticFile(w, r, "portal.html", "text/html; charset=utf-8")
145
return
146
}
147
frontend.ServePortalStatic(w, r)
168
- })
148
+ }))
149
150
// routes based on host and path
151
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@@ -194,6 +174,17 @@ func serveHTTP(addr string, serv *portal.RelayServer, admin *Admin, frontend *Fr
174
return srv
175
}
176
177
+func withCORSMiddleware(h http.HandlerFunc) http.HandlerFunc {
178
+ return func(w http.ResponseWriter, r *http.Request) {
179
+ utils.SetCORSHeaders(w)
180
+ if r.Method == http.MethodOptions {
181
+ w.WriteHeader(http.StatusOK)
182
+ return
183
+ }
184
+ h(w, r)
185
+ }
186
+}
187
+
188
type leaseRow struct {
189
Peer string
190
Name string