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
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.
55 lines
2.2 KiB
Go
55 lines
2.2 KiB
Go
package connectsrv
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
)
|
|
|
|
func TestWithNativeCORS(t *testing.T) {
|
|
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) })
|
|
h := withNativeCORS(next)
|
|
|
|
// Native-origin preflight → 204 with the CORS headers, reflecting the requested headers, without
|
|
// reaching the inner handler.
|
|
req := httptest.NewRequest(http.MethodOptions, "/scrabble.edge.v1.Gateway/Execute", nil)
|
|
req.Header.Set("Origin", "https://localhost")
|
|
req.Header.Set("Access-Control-Request-Method", "POST")
|
|
req.Header.Set("Access-Control-Request-Headers", "content-type,connect-protocol-version,x-client-version")
|
|
rec := httptest.NewRecorder()
|
|
h.ServeHTTP(rec, req)
|
|
if rec.Code != http.StatusNoContent {
|
|
t.Fatalf("preflight status = %d, want 204", rec.Code)
|
|
}
|
|
if got := rec.Header().Get("Access-Control-Allow-Origin"); got != "https://localhost" {
|
|
t.Errorf("Allow-Origin = %q, want https://localhost", got)
|
|
}
|
|
if got := rec.Header().Get("Access-Control-Allow-Headers"); got != "content-type,connect-protocol-version,x-client-version" {
|
|
t.Errorf("Allow-Headers = %q, want the reflected set", got)
|
|
}
|
|
|
|
// Native-origin POST → the CORS headers are set and the inner handler runs.
|
|
req = httptest.NewRequest(http.MethodPost, "/scrabble.edge.v1.Gateway/Execute", nil)
|
|
req.Header.Set("Origin", "capacitor://localhost")
|
|
rec = httptest.NewRecorder()
|
|
h.ServeHTTP(rec, req)
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("POST status = %d, want 200 (passed through)", rec.Code)
|
|
}
|
|
if got := rec.Header().Get("Access-Control-Allow-Origin"); got != "capacitor://localhost" {
|
|
t.Errorf("POST Allow-Origin = %q, want capacitor://localhost", got)
|
|
}
|
|
|
|
// A non-native origin gets no CORS headers and still passes through (web is same-origin anyway).
|
|
req = httptest.NewRequest(http.MethodPost, "/scrabble.edge.v1.Gateway/Execute", nil)
|
|
req.Header.Set("Origin", "https://evil.example")
|
|
rec = httptest.NewRecorder()
|
|
h.ServeHTTP(rec, req)
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("non-native POST status = %d, want 200", rec.Code)
|
|
}
|
|
if got := rec.Header().Get("Access-Control-Allow-Origin"); got != "" {
|
|
t.Errorf("non-native Allow-Origin = %q, want empty", got)
|
|
}
|
|
}
|