Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-pages.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorIgor Wiedler <iwiedler@gitlab.com>2020-05-04 15:30:39 +0300
committerIgor Wiedler <iwiedler@gitlab.com>2020-11-18 12:48:36 +0300
commit481a5bf0c8fbac9c18889341757ee9806d4ebd63 (patch)
tree12e653b8d164ea1a126eaaf189c9609e667b846a /test
parent12fa24ee96cb9d971a75df2cacfcbb1e014125e9 (diff)
Support for HTTPS over PROXYv2 protocol
Diffstat (limited to 'test')
-rw-r--r--test/acceptance/acceptance_test.go11
-rw-r--r--test/acceptance/helpers_test.go143
-rw-r--r--test/acceptance/proxyv2_test.go52
-rw-r--r--test/acceptance/serving_test.go10
4 files changed, 189 insertions, 27 deletions
diff --git a/test/acceptance/acceptance_test.go b/test/acceptance/acceptance_test.go
index e155ce8b..9921076e 100644
--- a/test/acceptance/acceptance_test.go
+++ b/test/acceptance/acceptance_test.go
@@ -11,7 +11,7 @@ import (
)
const (
- objectStorageMockServer = "127.0.0.1:37003"
+ objectStorageMockServer = "127.0.0.1:38001"
)
var (
@@ -27,11 +27,14 @@ var (
{"https", "::1", "37001"},
{"proxy", "127.0.0.1", "37002"},
{"proxy", "::1", "37002"},
+ {"https-proxyv2", "127.0.0.1", "37003"},
+ {"https-proxyv2", "::1", "37003"},
}
- httpListener = listeners[0]
- httpsListener = listeners[2]
- proxyListener = listeners[4]
+ httpListener = listeners[0]
+ httpsListener = listeners[2]
+ proxyListener = listeners[4]
+ httpsProxyv2Listener = listeners[6]
)
func TestMain(m *testing.M) {
diff --git a/test/acceptance/helpers_test.go b/test/acceptance/helpers_test.go
index 5412f6d5..3506e236 100644
--- a/test/acceptance/helpers_test.go
+++ b/test/acceptance/helpers_test.go
@@ -2,6 +2,7 @@ package acceptance_test
import (
"bytes"
+ "context"
"crypto/tls"
"crypto/x509"
"fmt"
@@ -14,14 +15,18 @@ import (
"os/exec"
"path"
"strings"
+ "sync"
"testing"
"time"
+ proxyproto "github.com/pires/go-proxyproto"
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitlab-pages/internal/request"
)
+// The HTTPS certificate isn't signed by anyone. This http client is set up
+// so it can talk to servers using it.
var (
// The HTTPS certificate isn't signed by anyone. This http client is set up
// so it can talk to servers using it.
@@ -40,8 +45,49 @@ var (
},
}
+ // Proxyv2 client
+ TestProxyv2Client = &http.Client{
+ Transport: &http.Transport{
+ DialContext: Proxyv2DialContext,
+ TLSClientConfig: &tls.Config{RootCAs: TestCertPool},
+ },
+ }
+
+ QuickTimeoutProxyv2Client = &http.Client{
+ Transport: &http.Transport{
+ DialContext: Proxyv2DialContext,
+ TLSClientConfig: &tls.Config{RootCAs: TestCertPool},
+ ResponseHeaderTimeout: 100 * time.Millisecond,
+ },
+ }
+
TestCertPool = x509.NewCertPool()
+ // Proxyv2 will create a dummy request with src 10.1.1.1:1000
+ // and dst 20.2.2.2:2000
+ Proxyv2DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
+ var d net.Dialer
+
+ conn, err := d.DialContext(ctx, network, addr)
+ if err != nil {
+ return nil, err
+ }
+
+ header := &proxyproto.Header{
+ Version: 2,
+ Command: proxyproto.PROXY,
+ TransportProtocol: proxyproto.TCPv4,
+ SourceAddress: net.ParseIP("10.1.1.1"),
+ SourcePort: 1000,
+ DestinationAddress: net.ParseIP("20.2.2.2"),
+ DestinationPort: 2000,
+ }
+
+ _, err = header.WriteTo(conn)
+
+ return conn, err
+ }
+
existingAcmeTokenPath = "/.well-known/acme-challenge/existingtoken"
notExistingAcmeTokenPath = "/.well-known/acme-challenge/notexistingtoken"
)
@@ -56,6 +102,36 @@ func (t *tWriter) Write(b []byte) (int, error) {
return len(b), nil
}
+type LogCaptureBuffer struct {
+ b bytes.Buffer
+ m sync.Mutex
+}
+
+func (b *LogCaptureBuffer) Read(p []byte) (n int, err error) {
+ b.m.Lock()
+ defer b.m.Unlock()
+
+ return b.b.Read(p)
+}
+func (b *LogCaptureBuffer) Write(p []byte) (n int, err error) {
+ b.m.Lock()
+ defer b.m.Unlock()
+
+ return b.b.Write(p)
+}
+func (b *LogCaptureBuffer) String() string {
+ b.m.Lock()
+ defer b.m.Unlock()
+
+ return b.b.String()
+}
+func (b *LogCaptureBuffer) Reset() {
+ b.m.Lock()
+ defer b.m.Unlock()
+
+ b.b.Reset()
+}
+
// ListenSpec is used to point at a gitlab-pages http server, preserving the
// type of port it is (http, https, proxy)
type ListenSpec struct {
@@ -66,7 +142,7 @@ type ListenSpec struct {
func (l ListenSpec) URL(suffix string) string {
scheme := request.SchemeHTTP
- if l.Type == request.SchemeHTTPS {
+ if l.Type == request.SchemeHTTPS || l.Type == "https-proxyv2" {
scheme = request.SchemeHTTPS
}
@@ -90,7 +166,12 @@ func (l ListenSpec) WaitUntilRequestSucceeds(done chan struct{}) error {
return err
}
- response, err := QuickTimeoutHTTPSClient.Transport.RoundTrip(req)
+ client := QuickTimeoutHTTPSClient
+ if l.Type == "https-proxyv2" {
+ client = QuickTimeoutProxyv2Client
+ }
+
+ response, err := client.Transport.RoundTrip(req)
if err != nil {
time.Sleep(100 * time.Millisecond)
continue
@@ -117,19 +198,27 @@ func (l ListenSpec) JoinHostPort() string {
//
// If run as root via sudo, the gitlab-pages process will drop privileges
func RunPagesProcess(t *testing.T, pagesBinary string, listeners []ListenSpec, promPort string, extraArgs ...string) (teardown func()) {
- return runPagesProcess(t, true, pagesBinary, listeners, promPort, nil, extraArgs...)
+ _, cleanup := runPagesProcess(t, true, pagesBinary, listeners, promPort, nil, extraArgs...)
+ return cleanup
}
func RunPagesProcessWithoutWait(t *testing.T, pagesBinary string, listeners []ListenSpec, promPort string, extraArgs ...string) (teardown func()) {
- return runPagesProcess(t, false, pagesBinary, listeners, promPort, nil, extraArgs...)
+ _, cleanup := runPagesProcess(t, false, pagesBinary, listeners, promPort, nil, extraArgs...)
+ return cleanup
}
func RunPagesProcessWithSSLCertFile(t *testing.T, pagesBinary string, listeners []ListenSpec, promPort string, sslCertFile string, extraArgs ...string) (teardown func()) {
- return runPagesProcess(t, true, pagesBinary, listeners, promPort, []string{"SSL_CERT_FILE=" + sslCertFile}, extraArgs...)
+ _, cleanup := runPagesProcess(t, true, pagesBinary, listeners, promPort, []string{"SSL_CERT_FILE=" + sslCertFile}, extraArgs...)
+ return cleanup
}
func RunPagesProcessWithEnvs(t *testing.T, wait bool, pagesBinary string, listeners []ListenSpec, promPort string, envs []string, extraArgs ...string) (teardown func()) {
- return runPagesProcess(t, wait, pagesBinary, listeners, promPort, envs, extraArgs...)
+ _, cleanup := runPagesProcess(t, wait, pagesBinary, listeners, promPort, envs, extraArgs...)
+ return cleanup
+}
+
+func RunPagesProcessWithOutput(t *testing.T, pagesBinary string, listeners []ListenSpec, promPort string, extraArgs ...string) (out *LogCaptureBuffer, teardown func()) {
+ return runPagesProcess(t, true, pagesBinary, listeners, promPort, nil, extraArgs...)
}
func RunPagesProcessWithStubGitLabServer(t *testing.T, wait bool, pagesBinary string, listeners []ListenSpec, promPort string, envs []string, extraArgs ...string) (teardown func()) {
@@ -139,7 +228,7 @@ func RunPagesProcessWithStubGitLabServer(t *testing.T, wait bool, pagesBinary st
gitLabAPISecretKey := CreateGitLabAPISecretKeyFixtureFile(t)
pagesArgs := append([]string{"-gitlab-server", source.URL, "-api-secret-key", gitLabAPISecretKey, "-domain-config-source", "gitlab"}, extraArgs...)
- cleanup := runPagesProcess(t, wait, pagesBinary, listeners, promPort, envs, pagesArgs...)
+ _, cleanup := runPagesProcess(t, wait, pagesBinary, listeners, promPort, envs, pagesArgs...)
return func() {
source.Close()
@@ -153,9 +242,10 @@ func RunPagesProcessWithAuth(t *testing.T, pagesBinary string, listeners []Liste
"auth-redirect-uri=https://projects.gitlab-example.com/auth")
defer cleanup()
- return runPagesProcess(t, true, pagesBinary, listeners, promPort, nil,
+ _, cleanup2 := runPagesProcess(t, true, pagesBinary, listeners, promPort, nil,
"-config="+configFile,
)
+ return cleanup2
}
func RunPagesProcessWithAuthServer(t *testing.T, pagesBinary string, listeners []ListenSpec, promPort string, authServer string) func() {
@@ -191,21 +281,25 @@ func runPagesProcessWithAuthServer(t *testing.T, pagesBinary string, listeners [
"auth-redirect-uri=https://projects.gitlab-example.com/auth")
defer cleanup()
- return runPagesProcess(t, true, pagesBinary, listeners, promPort, extraEnv,
+ _, cleanup2 := runPagesProcess(t, true, pagesBinary, listeners, promPort, extraEnv,
"-config="+configFile)
+ return cleanup2
}
-func runPagesProcess(t *testing.T, wait bool, pagesBinary string, listeners []ListenSpec, promPort string, extraEnv []string, extraArgs ...string) (teardown func()) {
+func runPagesProcess(t *testing.T, wait bool, pagesBinary string, listeners []ListenSpec, promPort string, extraEnv []string, extraArgs ...string) (*LogCaptureBuffer, func()) {
t.Helper()
_, err := os.Stat(pagesBinary)
require.NoError(t, err)
+ logBuf := &LogCaptureBuffer{}
+ out := io.MultiWriter(&tWriter{t}, logBuf)
+
args, tempfiles := getPagesArgs(t, listeners, promPort, extraArgs)
cmd := exec.Command(pagesBinary, args...)
cmd.Env = append(os.Environ(), extraEnv...)
- cmd.Stdout = &tWriter{t}
- cmd.Stderr = &tWriter{t}
+ cmd.Stdout = out
+ cmd.Stderr = out
require.NoError(t, cmd.Start())
t.Logf("Running %s %v", pagesBinary, args)
@@ -232,7 +326,7 @@ func runPagesProcess(t *testing.T, wait bool, pagesBinary string, listeners []Li
}
}
- return cleanup
+ return logBuf, cleanup
}
func getPagesArgs(t *testing.T, listeners []ListenSpec, promPort string, extraArgs []string) (args, tempfiles []string) {
@@ -329,7 +423,7 @@ func GetPageFromListenerWithCookie(t *testing.T, spec ListenSpec, host, urlsuffi
req.Host = host
- return DoPagesRequest(t, req)
+ return DoPagesRequest(t, spec, req)
}
func GetCompressedPageFromListener(t *testing.T, spec ListenSpec, host, urlsuffix string, encoding string) (*http.Response, error) {
@@ -341,7 +435,7 @@ func GetCompressedPageFromListener(t *testing.T, spec ListenSpec, host, urlsuffi
req.Host = host
req.Header.Set("Accept-Encoding", encoding)
- return DoPagesRequest(t, req)
+ return DoPagesRequest(t, spec, req)
}
func GetProxiedPageFromListener(t *testing.T, spec ListenSpec, host, xForwardedHost, urlsuffix string) (*http.Response, error) {
@@ -354,12 +448,16 @@ func GetProxiedPageFromListener(t *testing.T, spec ListenSpec, host, xForwardedH
req.Host = host
req.Header.Set("X-Forwarded-Host", xForwardedHost)
- return DoPagesRequest(t, req)
+ return DoPagesRequest(t, spec, req)
}
-func DoPagesRequest(t *testing.T, req *http.Request) (*http.Response, error) {
+func DoPagesRequest(t *testing.T, spec ListenSpec, req *http.Request) (*http.Response, error) {
t.Logf("curl -X %s -H'Host: %s' %s", req.Method, req.Host, req.URL)
+ if spec.Type == "https-proxyv2" {
+ return TestProxyv2Client.Do(req)
+ }
+
return TestHTTPSClient.Do(req)
}
@@ -395,6 +493,10 @@ func GetRedirectPageWithHeaders(t *testing.T, spec ListenSpec, host, urlsuffix s
req.Host = host
+ if spec.Type == "https-proxyv2" {
+ return TestProxyv2Client.Transport.RoundTrip(req)
+ }
+
return TestHTTPSClient.Transport.RoundTrip(req)
}
@@ -416,7 +518,12 @@ func waitForRoundtrips(t *testing.T, listeners []ListenSpec, timeout time.Durati
t.Fatal(err)
}
- if response, err := QuickTimeoutHTTPSClient.Transport.RoundTrip(req); err == nil {
+ client := QuickTimeoutHTTPSClient
+ if spec.Type == "https-proxyv2" {
+ client = QuickTimeoutProxyv2Client
+ }
+
+ if response, err := client.Transport.RoundTrip(req); err == nil {
nListening++
response.Body.Close()
break
diff --git a/test/acceptance/proxyv2_test.go b/test/acceptance/proxyv2_test.go
new file mode 100644
index 00000000..c407ea19
--- /dev/null
+++ b/test/acceptance/proxyv2_test.go
@@ -0,0 +1,52 @@
+package acceptance_test
+
+import (
+ "io/ioutil"
+ "net/http"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestProxyv2(t *testing.T) {
+ skipUnlessEnabled(t)
+
+ logBuf, teardown := RunPagesProcessWithOutput(t, *pagesBinary, listeners, "")
+ defer teardown()
+
+ // the dummy client IP 10.1.1.1 is set by TestProxyv2Client
+ tests := map[string]struct {
+ host string
+ urlSuffix string
+ expectedStatusCode int
+ expectedContent string
+ expectedLog string
+ }{
+ "basic_proxyv2_request": {
+ host: "group.gitlab-example.com",
+ urlSuffix: "project/",
+ expectedStatusCode: http.StatusOK,
+ expectedContent: "project-subdir\n",
+ expectedLog: "group.gitlab-example.com 10.1.1.1",
+ },
+ }
+
+ for name, tt := range tests {
+ t.Run(name, func(t *testing.T) {
+ logBuf.Reset()
+
+ response, err := GetPageFromListener(t, httpsProxyv2Listener, tt.host, tt.urlSuffix)
+ require.NoError(t, err)
+ defer response.Body.Close()
+
+ require.Equal(t, tt.expectedStatusCode, response.StatusCode)
+
+ body, err := ioutil.ReadAll(response.Body)
+ require.NoError(t, err)
+
+ require.Contains(t, string(body), tt.expectedContent, "content mismatch")
+
+ require.Contains(t, logBuf.String(), tt.expectedLog, "log mismatch")
+ })
+ }
+}
diff --git a/test/acceptance/serving_test.go b/test/acceptance/serving_test.go
index 01935946..4ccdd8f4 100644
--- a/test/acceptance/serving_test.go
+++ b/test/acceptance/serving_test.go
@@ -213,7 +213,7 @@ func TestCORSWhenDisabled(t *testing.T) {
for _, spec := range listeners {
for _, method := range []string{"GET", "OPTIONS"} {
- rsp := doCrossOriginRequest(t, method, method, spec.URL("project/"))
+ rsp := doCrossOriginRequest(t, spec, method, method, spec.URL("project/"))
require.Equal(t, http.StatusOK, rsp.StatusCode)
require.Equal(t, "", rsp.Header.Get("Access-Control-Allow-Origin"))
@@ -229,7 +229,7 @@ func TestCORSAllowsGET(t *testing.T) {
for _, spec := range listeners {
for _, method := range []string{"GET", "OPTIONS"} {
- rsp := doCrossOriginRequest(t, method, method, spec.URL("project/"))
+ rsp := doCrossOriginRequest(t, spec, method, method, spec.URL("project/"))
require.Equal(t, http.StatusOK, rsp.StatusCode)
require.Equal(t, "*", rsp.Header.Get("Access-Control-Allow-Origin"))
@@ -245,7 +245,7 @@ func TestCORSForbidsPOST(t *testing.T) {
defer teardown()
for _, spec := range listeners {
- rsp := doCrossOriginRequest(t, "OPTIONS", "POST", spec.URL("project/"))
+ rsp := doCrossOriginRequest(t, spec, "OPTIONS", "POST", spec.URL("project/"))
require.Equal(t, http.StatusOK, rsp.StatusCode)
require.Equal(t, "", rsp.Header.Get("Access-Control-Allow-Origin"))
@@ -502,7 +502,7 @@ func TestKnownHostInReverseProxySetupReturns200(t *testing.T) {
}
}
-func doCrossOriginRequest(t *testing.T, method, reqMethod, url string) *http.Response {
+func doCrossOriginRequest(t *testing.T, spec ListenSpec, method, reqMethod, url string) *http.Response {
req, err := http.NewRequest(method, url, nil)
require.NoError(t, err)
@@ -513,7 +513,7 @@ func doCrossOriginRequest(t *testing.T, method, reqMethod, url string) *http.Res
var rsp *http.Response
err = fmt.Errorf("no request was made")
for start := time.Now(); time.Since(start) < 1*time.Second; {
- rsp, err = DoPagesRequest(t, req)
+ rsp, err = DoPagesRequest(t, spec, req)
if err == nil {
break
}