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
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
parent12fa24ee96cb9d971a75df2cacfcbb1e014125e9 (diff)
Support for HTTPS over PROXYv2 protocol
-rw-r--r--README.md28
-rw-r--r--app.go28
-rw-r--r--app_config.go15
-rw-r--r--daemon.go1
-rw-r--r--go.mod1
-rw-r--r--go.sum6
-rw-r--r--main.go20
-rw-r--r--server.go20
-rw-r--r--shared/lookups/zip-malformed.gitlab.io.json2
-rw-r--r--shared/lookups/zip-not-found.gitlab.io.json2
-rw-r--r--shared/lookups/zip.gitlab.io.json2
-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
15 files changed, 292 insertions, 49 deletions
diff --git a/README.md b/README.md
index d8016eaf..ab2ac632 100644
--- a/README.md
+++ b/README.md
@@ -185,6 +185,34 @@ We use `gorilla/handlers.ProxyHeaders` middleware. For more information please r
> NOTE: This middleware should only be used when behind a reverse proxy like nginx, HAProxy or Apache. Reverse proxies that don't (or are configured not to) strip these headers from client requests, or where these headers are accepted "as is" from a remote client (e.g. when Go is not behind a proxy), can manifest as a vulnerability if your application uses these headers for validating the 'trustworthiness' of a request.
+### PROXY protocol for HTTPS
+
+The above `listen-proxy` option only works for plaintext HTTP, where the reverse
+proxy was already able to parse the incoming HTTP traffic and inject a header for
+the remote client IP.
+
+This does not work for HTTPS which is generally proxied at the TCP level. In
+order to propagate the remote client IP in this case, you can use the
+[PROXY protocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt).
+This is supported by HAProxy and some third party services such as Cloudflare.
+
+To configure PROXY protocol support, run `gitlab-pages` with the
+`listen-https-proxyv2` flag.
+
+If you are using HAProxy as your TCP load balancer, you can configure the backend
+with the `send-proxy-v2` option, like so:
+
+```
+frontend fe
+ bind 127.0.0.1:12340
+ mode tcp
+ default_backend be
+
+backend be
+ mode tcp
+ server app1 127.0.0.1:1234 send-proxy-v2
+```
+
### GitLab access control
GitLab access control is configured with properties `auth-client-id`, `auth-client-secret`, `auth-redirect-uri`, `auth-server` and `auth-secret`. Client ID, secret and redirect uri are configured in the GitLab and should match. `auth-server` points to a GitLab instance used for authentication. `auth-redirect-uri` should be `http(s)://pages-domain/auth`. Note that if the pages-domain is not handled by GitLab pages, then the `auth-redirect-uri` should use some reserved namespace prefix (such as `http(s)://projects.pages-domain/auth`). Using HTTPS is _strongly_ encouraged. `auth-secret` is used to encrypt the session cookie, and it should be strong enough.
diff --git a/app.go b/app.go
index 218c1be4..ca495073 100644
--- a/app.go
+++ b/app.go
@@ -369,6 +369,11 @@ func (a *theApp) Run() {
a.listenProxyFD(&wg, fd, proxyHandler, limiter)
}
+ // Listen for HTTPS PROXYv2 requests
+ for _, fd := range a.ListenHTTPSProxyv2 {
+ a.ListenHTTPSProxyv2FD(&wg, fd, proxyHandler, limiter)
+ }
+
// Serve metrics for Prometheus
if a.ListenMetrics != 0 {
a.listenMetricsFD(&wg, a.ListenMetrics)
@@ -383,7 +388,7 @@ func (a *theApp) listenHTTPFD(wg *sync.WaitGroup, fd uintptr, httpHandler http.H
wg.Add(1)
go func() {
defer wg.Done()
- err := listenAndServe(fd, httpHandler, a.HTTP2, nil, limiter)
+ err := listenAndServe(fd, httpHandler, a.HTTP2, nil, limiter, false)
if err != nil {
capturingFatal(err, errortracking.WithField("listener", request.SchemeHTTP))
}
@@ -399,7 +404,7 @@ func (a *theApp) listenHTTPSFD(wg *sync.WaitGroup, fd uintptr, httpHandler http.
capturingFatal(err, errortracking.WithField("listener", request.SchemeHTTPS))
}
- err = listenAndServe(fd, httpHandler, a.HTTP2, tlsConfig, limiter)
+ err = listenAndServe(fd, httpHandler, a.HTTP2, tlsConfig, limiter, false)
if err != nil {
capturingFatal(err, errortracking.WithField("listener", request.SchemeHTTPS))
}
@@ -412,7 +417,7 @@ func (a *theApp) listenProxyFD(wg *sync.WaitGroup, fd uintptr, proxyHandler http
wg.Add(1)
go func(fd uintptr) {
defer wg.Done()
- err := listenAndServe(fd, proxyHandler, a.HTTP2, nil, limiter)
+ err := listenAndServe(fd, proxyHandler, a.HTTP2, nil, limiter, false)
if err != nil {
capturingFatal(err, errortracking.WithField("listener", "http proxy"))
}
@@ -420,6 +425,23 @@ func (a *theApp) listenProxyFD(wg *sync.WaitGroup, fd uintptr, proxyHandler http
}()
}
+// https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
+func (a *theApp) ListenHTTPSProxyv2FD(wg *sync.WaitGroup, fd uintptr, httpHandler http.Handler, limiter *netutil.Limiter) {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ tlsConfig, err := a.TLSConfig()
+ if err != nil {
+ capturingFatal(err, errortracking.WithField("listener", request.SchemeHTTPS))
+ }
+
+ err = listenAndServe(fd, httpHandler, a.HTTP2, tlsConfig, limiter, true)
+ if err != nil {
+ capturingFatal(err, errortracking.WithField("listener", request.SchemeHTTPS))
+ }
+ }()
+}
+
func (a *theApp) listenMetricsFD(wg *sync.WaitGroup, fd uintptr) {
wg.Add(1)
go func() {
diff --git a/app_config.go b/app_config.go
index 3bc2197b..bb4aa917 100644
--- a/app_config.go
+++ b/app_config.go
@@ -10,13 +10,14 @@ type appConfig struct {
RootKey []byte
MaxConns int
- ListenHTTP []uintptr
- ListenHTTPS []uintptr
- ListenProxy []uintptr
- ListenMetrics uintptr
- InsecureCiphers bool
- TLSMinVersion uint16
- TLSMaxVersion uint16
+ ListenHTTP []uintptr
+ ListenHTTPS []uintptr
+ ListenProxy []uintptr
+ ListenHTTPSProxyv2 []uintptr
+ ListenMetrics uintptr
+ InsecureCiphers bool
+ TLSMinVersion uint16
+ TLSMaxVersion uint16
HTTP2 bool
RedirectHTTP bool
diff --git a/daemon.go b/daemon.go
index 11fa3e9e..c2404e05 100644
--- a/daemon.go
+++ b/daemon.go
@@ -330,6 +330,7 @@ func updateFds(config *appConfig, cmd *exec.Cmd) {
config.ListenHTTP,
config.ListenHTTPS,
config.ListenProxy,
+ config.ListenHTTPSProxyv2,
} {
daemonUpdateFds(cmd, fds)
}
diff --git a/go.mod b/go.mod
index a2cce75f..00864c04 100644
--- a/go.mod
+++ b/go.mod
@@ -19,6 +19,7 @@ require (
github.com/namsral/flag v1.7.4-pre
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible
+ github.com/pires/go-proxyproto v0.2.0
github.com/prometheus/client_golang v1.6.0
github.com/rs/cors v1.7.0
github.com/sirupsen/logrus v1.4.2
diff --git a/go.sum b/go.sum
index 9c308626..4f69bd34 100644
--- a/go.sum
+++ b/go.sum
@@ -245,6 +245,8 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
+github.com/pires/go-proxyproto v0.2.0 h1:WyYKlv9pkt77b+LjMvPfwrsAxviaGCFhG4KDIy1ofLY=
+github.com/pires/go-proxyproto v0.2.0/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY=
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
@@ -342,10 +344,10 @@ github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FB
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-gitlab.com/gitlab-org/labkit v0.0.0-20201014124351-eb1fe6499318 h1:3xX/pl8dQjEtBZzHPCkex4Bwr7SGmVea/Zu4JdbZrKs=
-gitlab.com/gitlab-org/labkit v0.0.0-20201014124351-eb1fe6499318/go.mod h1:SNfxkfUwVNECgtmluVayv0GWFgEjjBs5AzgsowPQuo0=
gitlab.com/gitlab-org/go-mimedb v1.45.0 h1:PO8dx6HEWzPYU6MQTYnCbpQEJzhJLW/Bh43+2VUHTgc=
gitlab.com/gitlab-org/go-mimedb v1.45.0/go.mod h1:wa9y/zOSFKmTXLyBs4clz2FNVhZQmmEQM9TxslPAjZ0=
+gitlab.com/gitlab-org/labkit v0.0.0-20201014124351-eb1fe6499318 h1:3xX/pl8dQjEtBZzHPCkex4Bwr7SGmVea/Zu4JdbZrKs=
+gitlab.com/gitlab-org/labkit v0.0.0-20201014124351-eb1fe6499318/go.mod h1:SNfxkfUwVNECgtmluVayv0GWFgEjjBs5AzgsowPQuo0=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2 h1:75k/FF0Q2YM8QYo07VPddOLBslDt1MZOdEslOHvmzAs=
diff --git a/main.go b/main.go
index 1d397922..7defd281 100644
--- a/main.go
+++ b/main.go
@@ -32,6 +32,7 @@ func init() {
flag.Var(&listenHTTP, "listen-http", "The address(es) to listen on for HTTP requests")
flag.Var(&listenHTTPS, "listen-https", "The address(es) to listen on for HTTPS requests")
flag.Var(&listenProxy, "listen-proxy", "The address(es) to listen on for proxy requests")
+ flag.Var(&ListenHTTPSProxyv2, "listen-https-proxyv2", "The address(es) to listen on for HTTPS PROXYv2 requests (https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)")
flag.Var(&header, "header", "The additional http header(s) that should be send to the client")
}
@@ -78,9 +79,10 @@ var (
disableCrossOriginRequests = flag.Bool("disable-cross-origin-requests", false, "Disable cross-origin requests")
// See init()
- listenHTTP MultiStringFlag
- listenHTTPS MultiStringFlag
- listenProxy MultiStringFlag
+ listenHTTP MultiStringFlag
+ listenHTTPS MultiStringFlag
+ listenProxy MultiStringFlag
+ ListenHTTPSProxyv2 MultiStringFlag
header MultiStringFlag
)
@@ -274,6 +276,7 @@ func loadConfig() appConfig {
"listen-http": strings.Join(listenHTTP, ","),
"listen-https": strings.Join(listenHTTPS, ","),
"listen-proxy": strings.Join(listenProxy, ","),
+ "listen-https-proxyv2": strings.Join(ListenHTTPSProxyv2, ","),
"log-format": *logFormat,
"metrics-address": *metricsAddress,
"pages-domain": *pagesDomain,
@@ -389,6 +392,17 @@ func createAppListeners(config *appConfig) []io.Closer {
config.ListenProxy = append(config.ListenProxy, f.Fd())
}
+ for _, addr := range ListenHTTPSProxyv2.Split() {
+ l, f := createSocket(addr)
+ closers = append(closers, l, f)
+
+ log.WithFields(log.Fields{
+ "listener": addr,
+ }).Debug("Set up https proxyv2 listener")
+
+ config.ListenHTTPSProxyv2 = append(config.ListenHTTPSProxyv2, f.Fd())
+ }
+
return closers
}
diff --git a/server.go b/server.go
index 04ba818a..678367a3 100644
--- a/server.go
+++ b/server.go
@@ -9,6 +9,7 @@ import (
"time"
"github.com/gorilla/context"
+ proxyproto "github.com/pires/go-proxyproto"
"golang.org/x/net/http2"
"gitlab.com/gitlab-org/gitlab-pages/internal/netutil"
@@ -36,7 +37,7 @@ func (ln *keepAliveListener) Accept() (net.Conn, error) {
return conn, nil
}
-func listenAndServe(fd uintptr, handler http.Handler, useHTTP2 bool, tlsConfig *tls.Config, limiter *netutil.Limiter) error {
+func listenAndServe(fd uintptr, handler http.Handler, useHTTP2 bool, tlsConfig *tls.Config, limiter *netutil.Limiter, proxyv2 bool) error {
// create server
server := &http.Server{Handler: context.ClearHandler(handler), TLSConfig: tlsConfig}
@@ -56,9 +57,20 @@ func listenAndServe(fd uintptr, handler http.Handler, useHTTP2 bool, tlsConfig *
l = netutil.SharedLimitListener(l, limiter)
}
+ l = &keepAliveListener{l}
+
+ if proxyv2 {
+ l = &proxyproto.Listener{
+ Listener: l,
+ Policy: func(upstream net.Addr) (proxyproto.Policy, error) {
+ return proxyproto.REQUIRE, nil
+ },
+ }
+ }
+
if tlsConfig != nil {
- tlsListener := tls.NewListener(&keepAliveListener{l}, server.TLSConfig)
- return server.Serve(tlsListener)
+ l = tls.NewListener(l, server.TLSConfig)
}
- return server.Serve(&keepAliveListener{l})
+
+ return server.Serve(l)
}
diff --git a/shared/lookups/zip-malformed.gitlab.io.json b/shared/lookups/zip-malformed.gitlab.io.json
index 37ad1ddd..8c0185da 100644
--- a/shared/lookups/zip-malformed.gitlab.io.json
+++ b/shared/lookups/zip-malformed.gitlab.io.json
@@ -8,7 +8,7 @@
"prefix": "/",
"project_id": 123,
"source": {
- "path": "http://127.0.0.1:37003/malformed.zip",
+ "path": "http://127.0.0.1:38001/malformed.zip",
"type": "zip"
}
}
diff --git a/shared/lookups/zip-not-found.gitlab.io.json b/shared/lookups/zip-not-found.gitlab.io.json
index 94de4a90..514b8ff2 100644
--- a/shared/lookups/zip-not-found.gitlab.io.json
+++ b/shared/lookups/zip-not-found.gitlab.io.json
@@ -8,7 +8,7 @@
"prefix": "/",
"project_id": 123,
"source": {
- "path": "http://127.0.0.1:37003/not-found.zip",
+ "path": "http://127.0.0.1:38001/not-found.zip",
"type": "zip"
}
}
diff --git a/shared/lookups/zip.gitlab.io.json b/shared/lookups/zip.gitlab.io.json
index cf755a58..0549adc8 100644
--- a/shared/lookups/zip.gitlab.io.json
+++ b/shared/lookups/zip.gitlab.io.json
@@ -8,7 +8,7 @@
"prefix": "/",
"project_id": 123,
"source": {
- "path": "http://127.0.0.1:37003/public.zip",
+ "path": "http://127.0.0.1:38001/public.zip",
"type": "zip"
}
}
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
}