@@ -473,6 +473,49 @@ func TestAppProxyRouter(t *testing.T) {
473473
474474 // X-Forwarded-For contains the client IP.
475475 assert .NotEmpty (t , appRequest .Header .Get ("X-Forwarded-For" ))
476+
477+ // Origin is rewritten to the upstream hostname (Streamlit/Tornado workaround).
478+ assert .Equal (t , "http://" + appServer .Listener .Addr ().String (), appRequest .Header .Get ("Origin" ))
479+ },
480+ expectedNotifications : map [string ]int {
481+ "123" : 1 ,
482+ },
483+ },
484+ {
485+ // Streamlit (Tornado) rejects WebSocket connections when Origin does not match Host.
486+ // apps-proxy rewrites Host to the upstream hostname for LB routing, so Origin
487+ // (set by the browser to the public domain) would mismatch.
488+ // Verify the temporary workaround: Origin is rewritten to the upstream hostname.
489+ name : "websocket-origin-rewrite-streamlit-workaround" ,
490+ run : func (t * testing.T , client * http.Client , m []* mockoidc.MockOIDC , appServer * testutil.AppServer , service * testutil.DataAppsAPI , fakeClient * k8sfake.FakeDynamicClient , watcher * k8sapp.StateWatcher ) {
491+ ctx , cancel := context .WithTimeout (t .Context (), time .Minute )
492+ defer cancel ()
493+
494+ c , _ , err := websocket .Dial (
495+ ctx ,
496+ "wss://public-123.hub.keboola.local/ws" ,
497+ & websocket.DialOptions {
498+ HTTPClient : client ,
499+ // Simulate browser setting Origin to the public domain.
500+ HTTPHeader : http.Header {
501+ "Origin" : []string {"https://public-123.hub.keboola.local" },
502+ },
503+ },
504+ )
505+ require .NoError (t , err )
506+
507+ var v any
508+ err = wsjson .Read (ctx , c , & v )
509+ require .NoError (t , err )
510+ assert .Equal (t , "Hello websocket" , v )
511+ require .NoError (t , c .Close (websocket .StatusNormalClosure , "" ))
512+
513+ require .Len (t , * appServer .Requests , 1 )
514+ appRequest := (* appServer .Requests )[0 ]
515+
516+ // Origin must be rewritten to the upstream hostname so Tornado's
517+ // check_origin() sees Origin == Host and accepts the connection.
518+ assert .Equal (t , "http://" + appServer .Listener .Addr ().String (), appRequest .Header .Get ("Origin" ))
476519 },
477520 expectedNotifications : map [string ]int {
478521 "123" : 1 ,
0 commit comments