Files
mostlymatter/api4/websocket.go
Agniva De Sarker 4c5ea07aff MM-33836: Detect and upgrade incorrect HTTP version for websocket handshakes (#17142)
Our proxy configuration was historically incorrect, due to which
a lot of customers have that in their setups. As a result, strictly
following the websocket RFC results in a breaking change.

For now, we transparently upgrade the version header to 1.1, if we detect 1.0.
If a client was sending 1.0, it wouldn't have worked anyways because persistent
connections were introduced from 1.1 onwards.

https://mattermost.atlassian.net/browse/MM-33836

```release-note
WebSocket handshakes done with HTTP version lower than 1.1 will result in a warning,
and the server will transparently upgrade the version to 1.1 to comply with the
websocket RFC.

This is done to work around incorrect nginx (and other proxy) configs that do not set
the proxy_http_version directive to 1.1.

This facility will be removed in a future Mattermost version and it is strongly recommended
to fix the proxy configuration to correctly use the websocket protocol.
```

Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
2021-03-15 23:02:24 +05:30

58 строки
1.7 KiB
Go

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package api4
import (
"net/http"
"runtime"
"time"
"github.com/gobwas/ws"
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/shared/mlog"
)
func (api *API) InitWebSocket() {
// Optionally supports a trailing slash
api.BaseRoutes.ApiRoot.Handle("/{websocket:websocket(?:\\/)?}", api.ApiHandlerTrustRequester(connectWebSocket)).Methods("GET")
}
func connectWebSocket(c *Context, w http.ResponseWriter, r *http.Request) {
fn := c.App.OriginChecker()
if fn != nil && !fn(r) {
c.Err = model.NewAppError("origin_check", "api.web_socket.connect.check_origin.app_error", nil, "", http.StatusBadRequest)
return
}
upgrader := ws.HTTPUpgrader{
Timeout: 5 * time.Second,
}
// Uprgade the HTTP version header to 1.1, if we detect a 1.0 header.
// This is a hack to work around a flaw in our proxy configs which sends the protocol version as 1.0.
// It will be removed in a future version.
if r.ProtoMajor == 1 && r.ProtoMinor == 0 {
r.ProtoMinor = 1
mlog.Warn("The HTTP version field was detected as 1.0 during WebSocket handshake. This is most probably due to an incorrect proxy configuration. Please upgrade your proxy config to set the header version to a minimum of 1.1.")
}
conn, _, _, err := upgrader.Upgrade(r, w)
if err != nil {
c.Err = model.NewAppError("connect", "api.web_socket.connect.upgrade.app_error", nil, err.Error(), http.StatusInternalServerError)
return
}
wc := c.App.NewWebConn(conn, *c.App.Session(), c.App.T, "")
if c.App.Session().UserId != "" {
c.App.HubRegister(wc)
}
if runtime.GOOS == "windows" {
wc.BlockingPump()
} else {
go wc.Pump()
}
}