mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-11-25 21:26:40 +00:00
[bugfix] send back Sec-Websocket-Protocol header for streaming WebSocket (#3169)
* [bugfix] send back Sec-Websocket-Protocol header for streaming WebSocket Chrome expects the selected Sec-Websocket-Protocol to be sent back on the WebSocket upgrade request (RFC6455 1.9). * fiddle a bit to avoid getting headers multiple times * add some explanatory notes --------- Co-authored-by: tobi <tobi.smethurst@protonmail.com>
This commit is contained in:
parent
b78be9fd4a
commit
4697271cef
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"net/http"
|
||||||
"slices"
|
"slices"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -151,15 +152,24 @@
|
||||||
// description: bad request
|
// description: bad request
|
||||||
func (m *Module) StreamGETHandler(c *gin.Context) {
|
func (m *Module) StreamGETHandler(c *gin.Context) {
|
||||||
var (
|
var (
|
||||||
|
token string
|
||||||
|
tokenInHeader bool
|
||||||
account *gtsmodel.Account
|
account *gtsmodel.Account
|
||||||
errWithCode gtserror.WithCode
|
errWithCode gtserror.WithCode
|
||||||
)
|
)
|
||||||
|
|
||||||
// Try query param access token.
|
if t := c.Query(AccessTokenQueryKey); t != "" {
|
||||||
token := c.Query(AccessTokenQueryKey)
|
// Token was provided as
|
||||||
if token == "" {
|
// query param, no problem.
|
||||||
// Try fallback HTTP header provided token.
|
token = t
|
||||||
token = c.GetHeader(AccessTokenHeader)
|
} else if t := c.GetHeader(AccessTokenHeader); t != "" {
|
||||||
|
// Token was provided in "Sec-Websocket-Protocol" header.
|
||||||
|
//
|
||||||
|
// This is hacky and not technically correct but some
|
||||||
|
// clients do it since Mastodon allows it, so we must
|
||||||
|
// also allow it to avoid breaking expectations.
|
||||||
|
token = t
|
||||||
|
tokenInHeader = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if token != "" {
|
if token != "" {
|
||||||
|
@ -230,7 +240,16 @@ func (m *Module) StreamGETHandler(c *gin.Context) {
|
||||||
//
|
//
|
||||||
// If the upgrade fails, then Upgrade replies to the client
|
// If the upgrade fails, then Upgrade replies to the client
|
||||||
// with an HTTP error response.
|
// with an HTTP error response.
|
||||||
wsConn, err := m.wsUpgrade.Upgrade(c.Writer, c.Request, nil)
|
var responseHeader http.Header
|
||||||
|
if tokenInHeader {
|
||||||
|
// Return the token in the response,
|
||||||
|
// else Chrome fails to connect.
|
||||||
|
//
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Protocol_upgrade_mechanism#sec-websocket-protocol
|
||||||
|
responseHeader = http.Header{AccessTokenHeader: {token}}
|
||||||
|
}
|
||||||
|
|
||||||
|
wsConn, err := m.wsUpgrade.Upgrade(c.Writer, c.Request, responseHeader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Errorf("error upgrading websocket connection: %v", err)
|
l.Errorf("error upgrading websocket connection: %v", err)
|
||||||
stream.Close()
|
stream.Close()
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
@ -236,7 +236,7 @@ func (suite *StreamingTestSuite) TestSecurityHeader() {
|
||||||
|
|
||||||
result := recorder.Result()
|
result := recorder.Result()
|
||||||
defer result.Body.Close()
|
defer result.Body.Close()
|
||||||
b, err := ioutil.ReadAll(result.Body)
|
b, err := io.ReadAll(result.Body)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
|
||||||
// check response
|
// check response
|
||||||
|
|
Loading…
Reference in a new issue