Set a proper HTTP user-agent header (#9482)
Previously, mattermost-server would always request with the default user-agent of Go's net/http package that is `Go-http-client/1.1` or something similar. This has several disadvantages, one is that the default user-agent made it pretty hard to distinguish mattermost requests from other service requests in a network log for example. Now a user-agent of the form `mattermost-<current-version>` is set in the client. - [x] Added or updated unit tests (required for all new features)
Этот коммит содержится в:
коммит произвёл
Christopher Speller
родитель
580b546862
Коммит
cf9b9802a8
@@ -16,12 +16,14 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/dyatlov/go-opengraph/opengraph"
|
"github.com/dyatlov/go-opengraph/opengraph"
|
||||||
|
"golang.org/x/net/html/charset"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/mlog"
|
"github.com/mattermost/mattermost-server/mlog"
|
||||||
"github.com/mattermost/mattermost-server/model"
|
"github.com/mattermost/mattermost-server/model"
|
||||||
"github.com/mattermost/mattermost-server/plugin"
|
"github.com/mattermost/mattermost-server/plugin"
|
||||||
|
"github.com/mattermost/mattermost-server/services/httpservice"
|
||||||
"github.com/mattermost/mattermost-server/store"
|
"github.com/mattermost/mattermost-server/store"
|
||||||
"github.com/mattermost/mattermost-server/utils"
|
"github.com/mattermost/mattermost-server/utils"
|
||||||
"golang.org/x/net/html/charset"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *App) CreatePostAsUser(post *model.Post, clearPushNotifications bool) (*model.Post, *model.AppError) {
|
func (a *App) CreatePostAsUser(post *model.Post, clearPushNotifications bool) (*model.Post, *model.AppError) {
|
||||||
@@ -919,7 +921,7 @@ func (a *App) DoPostAction(postId, actionId, userId, selectedOption string) *mod
|
|||||||
req.Header.Set("Accept", "application/json")
|
req.Header.Set("Accept", "application/json")
|
||||||
|
|
||||||
// Allow access to plugin routes for action buttons
|
// Allow access to plugin routes for action buttons
|
||||||
var httpClient *http.Client
|
var httpClient *httpservice.Client
|
||||||
url, _ := url.Parse(action.Integration.URL)
|
url, _ := url.Parse(action.Integration.URL)
|
||||||
siteURL, _ := url.Parse(*a.Config().ServiceSettings.SiteURL)
|
siteURL, _ := url.Parse(*a.Config().ServiceSettings.SiteURL)
|
||||||
subpath, _ := utils.GetSubpathFromConfig(a.Config())
|
subpath, _ := utils.GetSubpathFromConfig(a.Config())
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/mattermost/mattermost-server/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -28,6 +30,8 @@ func IsReservedIP(ip net.IP) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var defaultUserAgent string
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
for _, cidr := range []string{
|
for _, cidr := range []string{
|
||||||
// See https://tools.ietf.org/html/rfc6890
|
// See https://tools.ietf.org/html/rfc6890
|
||||||
@@ -48,6 +52,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
reservedIPRanges = append(reservedIPRanges, parsed)
|
reservedIPRanges = append(reservedIPRanges, parsed)
|
||||||
}
|
}
|
||||||
|
defaultUserAgent = "mattermost-" + model.CurrentVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
type DialContextFunction func(ctx context.Context, network, addr string) (net.Conn, error)
|
type DialContextFunction func(ctx context.Context, network, addr string) (net.Conn, error)
|
||||||
@@ -97,6 +102,15 @@ func dialContextFilter(dial DialContextFunction, allowHost func(host string) boo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
*http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) Do(req *http.Request) (*http.Response, error) {
|
||||||
|
req.Header.Set("User-Agent", defaultUserAgent)
|
||||||
|
return c.Client.Do(req)
|
||||||
|
}
|
||||||
|
|
||||||
// NewHTTPClient returns a variation the default implementation of Client.
|
// NewHTTPClient returns a variation the default implementation of Client.
|
||||||
// It uses a Transport with the same settings as the default Transport
|
// It uses a Transport with the same settings as the default Transport
|
||||||
// but with the following modifications:
|
// but with the following modifications:
|
||||||
@@ -104,7 +118,7 @@ func dialContextFilter(dial DialContextFunction, allowHost func(host string) boo
|
|||||||
// "connectTimeout")
|
// "connectTimeout")
|
||||||
// - timeout for the end-to-end request (defined as constant
|
// - timeout for the end-to-end request (defined as constant
|
||||||
// "requestTimeout")
|
// "requestTimeout")
|
||||||
func NewHTTPClient(enableInsecureConnections bool, allowHost func(host string) bool, allowIP func(ip net.IP) bool) *http.Client {
|
func NewHTTPClient(enableInsecureConnections bool, allowHost func(host string) bool, allowIP func(ip net.IP) bool) *Client {
|
||||||
dialContext := (&net.Dialer{
|
dialContext := (&net.Dialer{
|
||||||
Timeout: connectTimeout,
|
Timeout: connectTimeout,
|
||||||
KeepAlive: 30 * time.Second,
|
KeepAlive: 30 * time.Second,
|
||||||
@@ -129,5 +143,5 @@ func NewHTTPClient(enableInsecureConnections bool, allowHost func(host string) b
|
|||||||
Timeout: requestTimeout,
|
Timeout: requestTimeout,
|
||||||
}
|
}
|
||||||
|
|
||||||
return client
|
return &Client{Client: client}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,3 +118,24 @@ func TestDialContextFilter(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUserAgentIsSet(t *testing.T) {
|
||||||
|
testUserAgent := "test-user-agent"
|
||||||
|
defaultUserAgent = testUserAgent
|
||||||
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
ua := req.UserAgent()
|
||||||
|
if ua == "" {
|
||||||
|
t.Error("expected user-agent to be non-empty")
|
||||||
|
}
|
||||||
|
if ua != testUserAgent {
|
||||||
|
t.Errorf("expected user-agent to be %q but was %q", testUserAgent, ua)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
defer ts.Close()
|
||||||
|
client := NewHTTPClient(true, nil, nil)
|
||||||
|
req, err := http.NewRequest("GET", ts.URL, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("NewRequest failed", err)
|
||||||
|
}
|
||||||
|
client.Do(req)
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ package httpservice
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/services/configservice"
|
"github.com/mattermost/mattermost-server/services/configservice"
|
||||||
@@ -13,7 +12,7 @@ import (
|
|||||||
|
|
||||||
// Wraps the functionality for creating a new http.Client to encapsulate that and allow it to be mocked when testing
|
// Wraps the functionality for creating a new http.Client to encapsulate that and allow it to be mocked when testing
|
||||||
type HTTPService interface {
|
type HTTPService interface {
|
||||||
MakeClient(trustURLs bool) *http.Client
|
MakeClient(trustURLs bool) *Client
|
||||||
Close()
|
Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,7 +24,7 @@ func MakeHTTPService(configService configservice.ConfigService) HTTPService {
|
|||||||
return &HTTPServiceImpl{configService}
|
return &HTTPServiceImpl{configService}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HTTPServiceImpl) MakeClient(trustURLs bool) *http.Client {
|
func (h *HTTPServiceImpl) MakeClient(trustURLs bool) *Client {
|
||||||
insecure := h.configService.Config().ServiceSettings.EnableInsecureOutgoingConnections != nil && *h.configService.Config().ServiceSettings.EnableInsecureOutgoingConnections
|
insecure := h.configService.Config().ServiceSettings.EnableInsecureOutgoingConnections != nil && *h.configService.Config().ServiceSettings.EnableInsecureOutgoingConnections
|
||||||
|
|
||||||
if trustURLs {
|
if trustURLs {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
package testutils
|
package testutils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/mattermost/mattermost-server/services/httpservice"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
)
|
)
|
||||||
@@ -18,8 +19,8 @@ func MakeMockedHTTPService(handler http.Handler) *MockedHTTPService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *MockedHTTPService) MakeClient(trustURLs bool) *http.Client {
|
func (h *MockedHTTPService) MakeClient(trustURLs bool) *httpservice.Client {
|
||||||
return h.Server.Client()
|
return &httpservice.Client{Client: h.Server.Client()}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *MockedHTTPService) Close() {
|
func (h *MockedHTTPService) Close() {
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user