Files
scrabble-game/gateway/internal/connectsrv/cors.go
T
Ilia Denisov f0b7ad47d4
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 11s
CI / integration (pull_request) Successful in 23s
CI / ui (pull_request) Has been skipped
CI / conformance (pull_request) Successful in 11s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m54s
fix(gateway): allow the native WebView origin via CORS
The packaged native app (Capacitor) serves the bundled SPA from a localhost scheme, so its Connect calls to erudit-game.ru are cross-origin. The gateway had no CORS handling, so the preflight OPTIONS returned 405 with no Access-Control-Allow-Origin and the WebView blocked every RPC — a native build could never reach the gateway and stayed stuck offline (the native online path was never exercised on-device; on-device D was airplane-mode only). Add a CORS middleware that answers the preflight and sets the response headers for the native localhost origins (https/http/capacitor://localhost); web is same-origin and untouched. Fixes the native emulator 'starts offline, can't go online' report.
2026-07-14 21:21:53 +02:00

48 lines
2.2 KiB
Go

package connectsrv
import "net/http"
// nativeWebViewOrigins are the browser Origins of the packaged native apps. Capacitor serves the
// bundled SPA from a localhost scheme, so its Connect calls to the gateway are cross-origin; the web
// app is same-origin and needs no entry. Requests carry Authorization, so the allowlist reflects the
// exact origin rather than "*".
var nativeWebViewOrigins = map[string]bool{
"https://localhost": true, // Capacitor Android (default https scheme)
"http://localhost": true, // Capacitor with the http scheme
"capacitor://localhost": true, // Capacitor iOS default scheme
}
// withNativeCORS answers the CORS preflight and adds the CORS response headers for the packaged
// native apps' cross-origin calls to the Connect edge. Without it the WebView blocks every RPC on the
// preflight (the gateway otherwise returns 405 with no Access-Control-Allow-Origin), so a native
// build can never reach the gateway and stays stuck offline. Same-origin (web) and any non-native
// origin are untouched.
func withNativeCORS(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
origin := r.Header.Get("Origin")
if nativeWebViewOrigins[origin] {
h := w.Header()
h.Set("Access-Control-Allow-Origin", origin)
h.Add("Vary", "Origin")
h.Set("Access-Control-Allow-Credentials", "true")
// The client interceptor reads the soft-tier update signal off the response.
h.Set("Access-Control-Expose-Headers", "X-Update-Recommended")
if r.Method == http.MethodOptions {
h.Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
// Reflect the requested headers (the origin is already allowlisted): the Connect client
// sends Connect-Protocol-Version / Connect-Timeout-Ms plus X-Client-Version and
// Authorization, and the exact set varies by call.
if reqHeaders := r.Header.Get("Access-Control-Request-Headers"); reqHeaders != "" {
h.Set("Access-Control-Allow-Headers", reqHeaders)
} else {
h.Set("Access-Control-Allow-Headers", "Content-Type, Connect-Protocol-Version, X-Client-Version, Authorization")
}
h.Set("Access-Control-Max-Age", "86400")
w.WriteHeader(http.StatusNoContent)
return
}
}
next.ServeHTTP(w, r)
})
}