From fdf1164aee36d60b34ca82c07fe02b68e972f53a Mon Sep 17 00:00:00 2001 From: Torsten Juergeleit Date: Wed, 31 May 2017 16:34:05 +0200 Subject: PLT-5705 Created a single source of http.Client creation logic with internet proxy support, reasonable timeouts and optional insecure connections (#6503) --- utils/httpclient.go | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ utils/httpclient_test.go | 42 +++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 utils/httpclient.go create mode 100644 utils/httpclient_test.go (limited to 'utils') diff --git a/utils/httpclient.go b/utils/httpclient.go new file mode 100644 index 000000000..da366a29d --- /dev/null +++ b/utils/httpclient.go @@ -0,0 +1,60 @@ +// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package utils + +import ( + "crypto/tls" + "net" + "net/http" + "time" +) + +const ( + connectTimeout = 3 * time.Second + requestTimeout = 5 * time.Second +) + +// HttpClient returns a variation the default implementation of Client. +// It uses a Transport with the same settings as the default Transport +// but with the following modifications: +// - shorter timeout for dial and TLS handshake (defined as constant +// "connectTimeout") +// - timeout for the end-to-end request (defined as constant +// "requestTimeout") +// - skipping server certificate check if specified in "config.json" +// via "ServiceSettings.EnableInsecureOutgoingConnections" +func HttpClient() *http.Client { + if Cfg.ServiceSettings.EnableInsecureOutgoingConnections != nil && *Cfg.ServiceSettings.EnableInsecureOutgoingConnections { + return insecureHttpClient + } + return secureHttpClient +} + +var ( + secureHttpClient = createHttpClient(false) + insecureHttpClient = createHttpClient(true) +) + +func createHttpClient(enableInsecureConnections bool) *http.Client { + client := &http.Client{ + Transport: &http.Transport{ + Proxy: http.ProxyFromEnvironment, + DialContext: (&net.Dialer{ + Timeout: connectTimeout, + KeepAlive: 30 * time.Second, + DualStack: true, + }).DialContext, + MaxIdleConns: 100, + IdleConnTimeout: 90 * time.Second, + TLSHandshakeTimeout: connectTimeout, + ExpectContinueTimeout: 1 * time.Second, + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: enableInsecureConnections, + }, + }, + Timeout: requestTimeout, + } + + return client +} diff --git a/utils/httpclient_test.go b/utils/httpclient_test.go new file mode 100644 index 000000000..17353a4e7 --- /dev/null +++ b/utils/httpclient_test.go @@ -0,0 +1,42 @@ +// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package utils + +import ( + "fmt" + "io/ioutil" + "net/http" + "net/http/httptest" + "os" + "testing" +) + +func TestHttpClientWithProxy(t *testing.T) { + proxy := createProxyServer() + defer proxy.Close() + os.Setenv("HTTP_PROXY", proxy.URL) + + client := HttpClient() + resp, err := client.Get("http://acme.com") + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + if string(body) != "proxy" { + t.FailNow() + } +} + +func createProxyServer() *httptest.Server { + return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(200) + w.Header().Set("Content-Type", "text/plain; charset=us-ascii") + fmt.Fprint(w, "proxy") + })) +} -- cgit v1.2.3-1-g7c22