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:
authorJacob Vosmaer (GitLab) <jacob@gitlab.com>2018-03-29 17:43:39 +0300
committerNick Thomas <nick@gitlab.com>2018-03-29 17:43:39 +0300
commite7b9a2c510c47f53346f2402eecfec92849e613f (patch)
treebd78ed49680b09eae808ec381dd3202637fa7ca4
parente51175062c0fada8fadc37f6fc96531ff750221b (diff)
Put domain code in a separate package
-rw-r--r--app.go17
-rw-r--r--helpers.go5
-rw-r--r--helpers_test.go74
-rw-r--r--internal/domain/domain.go (renamed from domain.go)72
-rw-r--r--internal/domain/domain_config.go (renamed from domain_config.go)2
-rw-r--r--internal/domain/domain_config_test.go (renamed from domain_config_test.go)2
-rw-r--r--internal/domain/domain_test.go (renamed from domain_test.go)94
-rw-r--r--internal/domain/map.go (renamed from domains.go)39
-rw-r--r--internal/domain/map_test.go (renamed from domains_test.go)22
-rw-r--r--internal/fixture/fixtures.go56
10 files changed, 200 insertions, 183 deletions
diff --git a/app.go b/app.go
index ef436401..0403d028 100644
--- a/app.go
+++ b/app.go
@@ -16,6 +16,7 @@ import (
log "github.com/sirupsen/logrus"
"gitlab.com/gitlab-org/gitlab-pages/internal/artifact"
+ "gitlab.com/gitlab-org/gitlab-pages/internal/domain"
"gitlab.com/gitlab-org/gitlab-pages/internal/httperrors"
"gitlab.com/gitlab-org/gitlab-pages/metrics"
)
@@ -29,7 +30,7 @@ var (
type theApp struct {
appConfig
- dm domainMap
+ dm domain.Map
lock sync.RWMutex
Artifact *artifact.Artifact
}
@@ -38,7 +39,7 @@ func (a *theApp) isReady() bool {
return a.dm != nil
}
-func (a *theApp) domain(host string) *domain {
+func (a *theApp) domain(host string) *domain.D {
host = strings.ToLower(host)
a.lock.RLock()
defer a.lock.RUnlock()
@@ -52,7 +53,7 @@ func (a *theApp) ServeTLS(ch *tls.ClientHelloInfo) (*tls.Certificate, error) {
}
if domain := a.domain(ch.ServerName); domain != nil {
- tls, _ := domain.ensureCertificate()
+ tls, _ := domain.EnsureCertificate()
return tls, nil
}
@@ -76,7 +77,7 @@ func (a *theApp) redirectToHTTPS(w http.ResponseWriter, r *http.Request, statusC
http.Redirect(w, r, u.String(), statusCode)
}
-func (a *theApp) getHostAndDomain(r *http.Request) (host string, domain *domain) {
+func (a *theApp) getHostAndDomain(r *http.Request) (host string, domain *domain.D) {
host, _, err := net.SplitHostPort(r.Host)
if err != nil {
host = r.Host
@@ -85,7 +86,7 @@ func (a *theApp) getHostAndDomain(r *http.Request) (host string, domain *domain)
return host, a.domain(host)
}
-func (a *theApp) tryAuxiliaryHandlers(w http.ResponseWriter, r *http.Request, https bool, host string, domain *domain) bool {
+func (a *theApp) tryAuxiliaryHandlers(w http.ResponseWriter, r *http.Request, https bool, host string, domain *domain.D) bool {
// short circuit content serving to check for a status page
if r.RequestURI == a.appConfig.StatusPath {
a.healthCheck(w, r, https)
@@ -114,7 +115,7 @@ func (a *theApp) tryAuxiliaryHandlers(w http.ResponseWriter, r *http.Request, ht
return true
}
- if !https && domain.isHTTPSOnly(r) {
+ if !https && domain.IsHTTPSOnly(r) {
a.redirectToHTTPS(w, r, http.StatusMovedPermanently)
return true
}
@@ -157,7 +158,7 @@ func (a *theApp) ServeProxy(ww http.ResponseWriter, r *http.Request) {
a.serveContent(ww, r, https)
}
-func (a *theApp) UpdateDomains(dm domainMap) {
+func (a *theApp) UpdateDomains(dm domain.Map) {
a.lock.Lock()
defer a.lock.Unlock()
a.dm = dm
@@ -216,7 +217,7 @@ func (a *theApp) Run() {
}(a.ListenMetrics)
}
- go watchDomains(a.Domain, a.UpdateDomains, time.Second)
+ go domain.Watch(a.Domain, a.UpdateDomains, time.Second)
wg.Wait()
}
diff --git a/helpers.go b/helpers.go
index b418eec3..f83f4db5 100644
--- a/helpers.go
+++ b/helpers.go
@@ -3,7 +3,6 @@ package main
import (
"io/ioutil"
"net"
- "strings"
)
func readFile(file string) (result []byte) {
@@ -28,7 +27,3 @@ func createSocket(addr string) (l net.Listener, fd uintptr) {
fd = f.Fd()
return
}
-
-func endsWithSlash(path string) bool {
- return strings.HasSuffix(path, "/")
-}
diff --git a/helpers_test.go b/helpers_test.go
index 3155e1f6..656585c8 100644
--- a/helpers_test.go
+++ b/helpers_test.go
@@ -15,8 +15,8 @@ import (
"testing"
"time"
- log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitlab-pages/internal/fixture"
)
type tWriter struct {
@@ -29,21 +29,6 @@ func (t *tWriter) Write(b []byte) (int, error) {
return len(b), nil
}
-var chdirSet = false
-
-func setUpTests() {
- if chdirSet {
- return
- }
-
- err := os.Chdir("shared/pages")
- if err != nil {
- log.WithError(err).Print("chdir")
- } else {
- chdirSet = true
- }
-}
-
// The HTTPS certificate isn't signed by anyone. This http client is set up
// so it can talk to servers using it.
var (
@@ -62,62 +47,11 @@ var (
},
}
- CertificateFixture = `-----BEGIN CERTIFICATE-----
-MIIDZDCCAkygAwIBAgIRAOtN9/zy+gFjdsgpKq3QRdQwDQYJKoZIhvcNAQELBQAw
-MzEUMBIGA1UEChMLTG9nIENvdXJpZXIxGzAZBgNVBAMTEmdpdGxhYi1leGFtcGxl
-LmNvbTAgFw0xODAzMjMxODMwMDZaGA8yMTE4MDIyNzE4MzAwNlowMzEUMBIGA1UE
-ChMLTG9nIENvdXJpZXIxGzAZBgNVBAMTEmdpdGxhYi1leGFtcGxlLmNvbTCCASIw
-DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKULsxpnazXX5RsVzayrAQB+lWwr
-Wef5L5eDhSsIsBLbelYp5YB4TmVRt5x7bWKOOJSBsOfwHZHKJXdu+uuX2RenZlhk
-3Qpq9XGaPZjYm/NHi8gBHPAtz5sG5VaKNvkfTzRGnO9CWA9TM1XtYiOBq94dO+H3
-c+5jP5Yw+mJ+hA+i2058zF8nRlUHArEno2ofrHwE0LMZ11VskpXtWnVfs3voLs8p
-r76KXPBFkMJR4qkWrMDF5Y5MbsQ0zisn6KXrTyV0S4MQh4vSyPdFHnEzvJ07rm5x
-4RTWrjgQeQ2DjZjQvRmaDzlVBK9kaMkJ1Si3agK+gpji6d6WZ/Mb2el1GK8CAwEA
-AaNxMG8wDgYDVR0PAQH/BAQDAgKkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1Ud
-EwEB/wQFMAMBAf8wNwYDVR0RBDAwLoIUKi5naXRsYWItZXhhbXBsZS5jb22HBH8A
-AAGHEAAAAAAAAAAAAAAAAAAAAAEwDQYJKoZIhvcNAQELBQADggEBAJ0NM8apK0xI
-YxMstP/dCQXtR0wyREGSD/eOpeY3bWlqCbpRgMFUGjQlrsEozcPZOCSCKX5p+tym
-7GsnYtXkwbsuURoSz+5IlhRPVHcUlUeGRdv3/gCd8fDXiigALCsB6GrkMG5cUfh+
-x5p52AC3eQdWTDoxNou+2gzwkAl8iJc13Ykusst0YUqcsXKqTuei2quxFv0pEBSO
-p8wEixoicLFNqPnIDmgx5894DAn0bccNXgRWtq8lLbdhGUlBbpatevvFMgNvFUbe
-eeGb9D0EfpxmzxUl+L0xZtfg3f7cu5AgLG8tb6l4AK6NPVuXN8DmUgvnauWJjZME
-fgStI+IRNVg=
------END CERTIFICATE-----
-`
-
- KeyFixture = `-----BEGIN RSA PRIVATE KEY-----
-MIIEowIBAAKCAQEApQuzGmdrNdflGxXNrKsBAH6VbCtZ5/kvl4OFKwiwEtt6Vinl
-gHhOZVG3nHttYo44lIGw5/Adkcold27665fZF6dmWGTdCmr1cZo9mNib80eLyAEc
-8C3PmwblVoo2+R9PNEac70JYD1MzVe1iI4Gr3h074fdz7mM/ljD6Yn6ED6LbTnzM
-XydGVQcCsSejah+sfATQsxnXVWySle1adV+ze+guzymvvopc8EWQwlHiqRaswMXl
-jkxuxDTOKyfopetPJXRLgxCHi9LI90UecTO8nTuubnHhFNauOBB5DYONmNC9GZoP
-OVUEr2RoyQnVKLdqAr6CmOLp3pZn8xvZ6XUYrwIDAQABAoIBAHhP5QnUZeTkMtDh
-vgKmzZ4sqIQnvexKTBUo/MR4GtJESBPTisdx68QUI8LgfsafYkNvnyQUd5m1QEam
-Eif3k3uYvhSlwjQ78BwWEdz/2f8oIo9zsEKtQm+CQWAqdRR5bGVxLCmFtWfGgN+c
-ojO77SuHKAX7OvmGQ+4aWgu+qkoyg/chIpPXMduAjLMtN3eg60ZqJ5KrKuIF63Bb
-xkPQvzJueB9SfUurmKjUltDMx6G/9RZyS0OIRGyL9Qp8MZ8jE23cXOcDgm0HhkPq
-W4LU++aWAOLYziTjnhjJ+4Iz9R7U8sCmk1wgnK/tapVcJf41R98WuGluyjXpsXgA
-k7vmofECgYEAzuGun9lZ7xGwPifp6vGanWXnW+JiZgCTGuHWgQLIXWYcLfoI3kpH
-eLBYINBwvjIQ7P6UxsGSSXd+T82t+8W2LLc2fiKFKE1LVySpH99+cfmIPXxrviOz
-GBX9LTdSCdGkgb54m8aJCpNFnKw5wYgcW1L8CaXXly2Z/KNrGR9R/YUCgYEAzDs4
-19HqlutGLTC30/ziiiIfDaBbX9AzBdUfp9GdT53Mi/7bfxpW/sL4RjG2fGgmN6ua
-fh5npT9AB1ldcEg2qfyOJPt1Ubdi6ek9lx8AB2RMhwdihgX+7bjVMFtjg4b8z5C1
-jQbEr1rhFdpaGyNehtAXDgCbDWQBYnBrmM0rCaMCgYBip1Qyfd9ZFcJJoZb2pofo
-jvOo6Weq5JNBungjxUPu5gaCFj2sYxd6Af3EiCF7UTypBy3DKgOsbQMa4yYYbcvV
-vviJZcTB1zoaMC1GObl+eFPzniVy4mtBDRtSOJMyg3pDNKUnA6HOHTSQ5cAU/ecn
-1YbCwwbv3JsV0of7zue2UQKBgQCVc0j3dd9rLSQfcaUz9bx5RNrgh9YV2S9dN0aA
-8f1iA6FpWMiazFWY/GfeRga6JyTAXE0juXAzFoPuXNDpl46Y+f2yxmhlsgMqFMpD
-SiYlQppVvWu1k7GnmDg5uMarux5JbiXM24UWpTRNX4nMjidgE+qrDnpoZCQ3Ovkh
-yhGSbQKBgD3VEnPiSUmXBo39kPcnPg93E3JfdAOiOwIB2qwfYzg9kpmuTWws+DFz
-lKpMI27YkmnPqROQ2NTUfdxYmw3EHHMAsvnmHeMNGn3ijSUZVKmPfV436Qc8iVci
-s4wKoCRhBUZ52sHki/ieb+5hycT3JnVXMDtbJxgXFW5a86usXEpO
------END RSA PRIVATE KEY-----`
-
TestCertPool = x509.NewCertPool()
)
func init() {
- if ok := TestCertPool.AppendCertsFromPEM([]byte(CertificateFixture)); !ok {
+ if ok := TestCertPool.AppendCertsFromPEM([]byte(fixture.Certificate)); !ok {
fmt.Println("Failed to load cert!")
}
}
@@ -133,8 +67,8 @@ func CreateHTTPSFixtureFiles(t *testing.T) (key string, cert string) {
cert = certfile.Name()
certfile.Close()
- require.NoError(t, ioutil.WriteFile(key, []byte(KeyFixture), 0644))
- require.NoError(t, ioutil.WriteFile(cert, []byte(CertificateFixture), 0644))
+ require.NoError(t, ioutil.WriteFile(key, []byte(fixture.Key), 0644))
+ require.NoError(t, ioutil.WriteFile(cert, []byte(fixture.Certificate), 0644))
return keyfile.Name(), certfile.Name()
}
diff --git a/domain.go b/internal/domain/domain.go
index 2d562d04..0333cebe 100644
--- a/domain.go
+++ b/internal/domain/domain.go
@@ -1,4 +1,4 @@
-package main
+package domain
import (
"crypto/tls"
@@ -28,29 +28,31 @@ type project struct {
type projects map[string]*project
-type domain struct {
- Group string
+// D is a domain that gitlab-pages can serve.
+type D struct {
+ group string
// custom domains:
- ProjectName string
- Config *domainConfig
+ projectName string
+ config *domainConfig
certificate *tls.Certificate
certificateError error
// group domains:
- Projects projects
+ projects projects
}
-func (d *domain) String() string {
- if d.Group != "" && d.ProjectName != "" {
- return d.Group + "/" + d.ProjectName
+// String implements Stringer.
+func (d *D) String() string {
+ if d.group != "" && d.projectName != "" {
+ return d.group + "/" + d.projectName
}
- if d.Group != "" {
- return d.Group
+ if d.group != "" {
+ return d.group
}
- return d.ProjectName
+ return d.projectName
}
func (l *locationDirectoryError) Error() string {
@@ -92,9 +94,11 @@ func setContentType(w http.ResponseWriter, fullPath string) {
}
}
-func (d *domain) isHTTPSOnly(r *http.Request) bool {
- if d.Config != nil {
- return d.Config.HTTPSOnly
+// IsHTTPSOnly figures out if the request should be handled with HTTPS
+// only by looking at group and project level config.
+func (d *D) IsHTTPSOnly(r *http.Request) bool {
+ if d.config != nil {
+ return d.config.HTTPSOnly
}
split := strings.SplitN(r.URL.Path, "/", 3)
@@ -102,7 +106,7 @@ func (d *domain) isHTTPSOnly(r *http.Request) bool {
return false
}
- project := d.Projects[split[1]]
+ project := d.projects[split[1]]
if project != nil {
return project.HTTPSOnly
@@ -111,7 +115,7 @@ func (d *domain) isHTTPSOnly(r *http.Request) bool {
return false
}
-func (d *domain) serveFile(w http.ResponseWriter, r *http.Request, origPath string) error {
+func (d *D) serveFile(w http.ResponseWriter, r *http.Request, origPath string) error {
fullPath := handleGZip(w, r, origPath)
file, err := os.Open(fullPath)
@@ -134,7 +138,7 @@ func (d *domain) serveFile(w http.ResponseWriter, r *http.Request, origPath stri
return nil
}
-func (d *domain) serveCustomFile(w http.ResponseWriter, r *http.Request, code int, origPath string) error {
+func (d *D) serveCustomFile(w http.ResponseWriter, r *http.Request, code int, origPath string) error {
fullPath := handleGZip(w, r, origPath)
// Open and serve content of file
@@ -163,8 +167,8 @@ func (d *domain) serveCustomFile(w http.ResponseWriter, r *http.Request, code in
// Resolve the HTTP request to a path on disk, converting requests for
// directories to requests for index.html inside the directory if appropriate.
-func (d *domain) resolvePath(projectName string, subPath ...string) (string, error) {
- publicPath := filepath.Join(d.Group, projectName, "public")
+func (d *D) resolvePath(projectName string, subPath ...string) (string, error) {
+ publicPath := filepath.Join(d.group, projectName, "public")
// Don't use filepath.Join as cleans the path,
// where we want to traverse full path as supplied by user
@@ -202,7 +206,7 @@ func (d *domain) resolvePath(projectName string, subPath ...string) (string, err
return fullPath, nil
}
-func (d *domain) tryNotFound(w http.ResponseWriter, r *http.Request, projectName string) error {
+func (d *D) tryNotFound(w http.ResponseWriter, r *http.Request, projectName string) error {
page404, err := d.resolvePath(projectName, "404.html")
if err != nil {
return err
@@ -215,7 +219,7 @@ func (d *domain) tryNotFound(w http.ResponseWriter, r *http.Request, projectName
return nil
}
-func (d *domain) tryFile(w http.ResponseWriter, r *http.Request, projectName, pathSuffix string, subPath ...string) error {
+func (d *D) tryFile(w http.ResponseWriter, r *http.Request, projectName, pathSuffix string, subPath ...string) error {
fullPath, err := d.resolvePath(projectName, subPath...)
if locationError, _ := err.(*locationDirectoryError); locationError != nil {
@@ -241,7 +245,7 @@ func (d *domain) tryFile(w http.ResponseWriter, r *http.Request, projectName, pa
return d.serveFile(w, r, fullPath)
}
-func (d *domain) serveFromGroup(w http.ResponseWriter, r *http.Request) {
+func (d *D) serveFromGroup(w http.ResponseWriter, r *http.Request) {
// The Path always contains "/" at the beginning
split := strings.SplitN(r.URL.Path, "/", 3)
@@ -269,14 +273,14 @@ func (d *domain) serveFromGroup(w http.ResponseWriter, r *http.Request) {
httperrors.Serve404(w)
}
-func (d *domain) serveFromConfig(w http.ResponseWriter, r *http.Request) {
+func (d *D) serveFromConfig(w http.ResponseWriter, r *http.Request) {
// Try to serve file for http://host/... => /group/project/...
- if d.tryFile(w, r, d.ProjectName, "", r.URL.Path) == nil {
+ if d.tryFile(w, r, d.projectName, "", r.URL.Path) == nil {
return
}
// Try serving not found page for http://host/ => /group/project/404.html
- if d.tryNotFound(w, r, d.ProjectName) == nil {
+ if d.tryNotFound(w, r, d.projectName) == nil {
return
}
@@ -284,8 +288,9 @@ func (d *domain) serveFromConfig(w http.ResponseWriter, r *http.Request) {
httperrors.Serve404(w)
}
-func (d *domain) ensureCertificate() (*tls.Certificate, error) {
- if d.Config == nil {
+// EnsureCertificate parses the PEM-encoded certificate for the domain
+func (d *D) EnsureCertificate() (*tls.Certificate, error) {
+ if d.config == nil {
return nil, errors.New("tls certificates can be loaded only for pages with configuration")
}
@@ -293,7 +298,7 @@ func (d *domain) ensureCertificate() (*tls.Certificate, error) {
return d.certificate, d.certificateError
}
- tls, err := tls.X509KeyPair([]byte(d.Config.Certificate), []byte(d.Config.Key))
+ tls, err := tls.X509KeyPair([]byte(d.config.Certificate), []byte(d.config.Key))
if err != nil {
d.certificateError = err
return nil, err
@@ -303,10 +308,15 @@ func (d *domain) ensureCertificate() (*tls.Certificate, error) {
return d.certificate, nil
}
-func (d *domain) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- if d.Config != nil {
+// ServeHTTP implements http.Handler.
+func (d *D) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ if d.config != nil {
d.serveFromConfig(w, r)
} else {
d.serveFromGroup(w, r)
}
}
+
+func endsWithSlash(path string) bool {
+ return strings.HasSuffix(path, "/")
+}
diff --git a/domain_config.go b/internal/domain/domain_config.go
index f5c3db79..ed7e0820 100644
--- a/domain_config.go
+++ b/internal/domain/domain_config.go
@@ -1,4 +1,4 @@
-package main
+package domain
import (
"encoding/json"
diff --git a/domain_config_test.go b/internal/domain/domain_config_test.go
index 22194ad4..05db0aa3 100644
--- a/domain_config_test.go
+++ b/internal/domain/domain_config_test.go
@@ -1,4 +1,4 @@
-package main
+package domain
import (
"io/ioutil"
diff --git a/domain_test.go b/internal/domain/domain_test.go
index b51e6d7a..130501d6 100644
--- a/domain_test.go
+++ b/internal/domain/domain_test.go
@@ -1,4 +1,4 @@
-package main
+package domain
import (
"compress/gzip"
@@ -7,19 +7,22 @@ import (
"net/http"
"net/http/httptest"
"net/url"
+ "os"
"testing"
"time"
+ log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+ "gitlab.com/gitlab-org/gitlab-pages/internal/fixture"
)
func TestGroupServeHTTP(t *testing.T) {
setUpTests()
- testGroup := &domain{
- Group: "group",
- ProjectName: "",
+ testGroup := &D{
+ group: "group",
+ projectName: "",
}
assert.HTTPBodyContains(t, testGroup.ServeHTTP, "GET", "http://group.test.io/", nil, "main-dir")
@@ -47,10 +50,10 @@ func TestGroupServeHTTP(t *testing.T) {
func TestDomainServeHTTP(t *testing.T) {
setUpTests()
- testDomain := &domain{
- Group: "group",
- ProjectName: "project2",
- Config: &domainConfig{
+ testDomain := &D{
+ group: "group",
+ projectName: "project2",
+ config: &domainConfig{
Domain: "test.domain.com",
},
}
@@ -94,9 +97,9 @@ func testHTTPGzip(t *testing.T, handler http.HandlerFunc, mode, url string, valu
func TestGroupServeHTTPGzip(t *testing.T) {
setUpTests()
- testGroup := &domain{
- Group: "group",
- ProjectName: "",
+ testGroup := &D{
+ group: "group",
+ projectName: "",
}
testSet := []struct {
@@ -157,9 +160,9 @@ func testHTTP404(t *testing.T, handler http.HandlerFunc, mode, url string, value
func TestGroup404ServeHTTP(t *testing.T) {
setUpTests()
- testGroup := &domain{
- Group: "group.404",
- ProjectName: "",
+ testGroup := &D{
+ group: "group.404",
+ projectName: "",
}
testHTTP404(t, testGroup.ServeHTTP, "GET", "http://group.404.test.io/project.404/not/existing-file", nil, "Custom 404 project page")
@@ -174,10 +177,10 @@ func TestGroup404ServeHTTP(t *testing.T) {
func TestDomain404ServeHTTP(t *testing.T) {
setUpTests()
- testDomain := &domain{
- Group: "group.404",
- ProjectName: "domain.404",
- Config: &domainConfig{
+ testDomain := &D{
+ group: "group.404",
+ projectName: "domain.404",
+ config: &domainConfig{
Domain: "domain.404.com",
},
}
@@ -189,60 +192,60 @@ func TestDomain404ServeHTTP(t *testing.T) {
func TestPredefined404ServeHTTP(t *testing.T) {
setUpTests()
- testDomain := &domain{
- Group: "group",
+ testDomain := &D{
+ group: "group",
}
testHTTP404(t, testDomain.ServeHTTP, "GET", "http://group.test.io/not-existing-file", nil, "The page you're looking for could not be found")
}
func TestGroupCertificate(t *testing.T) {
- testGroup := &domain{
- Group: "group",
- ProjectName: "",
+ testGroup := &D{
+ group: "group",
+ projectName: "",
}
- tls, err := testGroup.ensureCertificate()
+ tls, err := testGroup.EnsureCertificate()
assert.Nil(t, tls)
assert.Error(t, err)
}
func TestDomainNoCertificate(t *testing.T) {
- testDomain := &domain{
- Group: "group",
- ProjectName: "project2",
- Config: &domainConfig{
+ testDomain := &D{
+ group: "group",
+ projectName: "project2",
+ config: &domainConfig{
Domain: "test.domain.com",
},
}
- tls, err := testDomain.ensureCertificate()
+ tls, err := testDomain.EnsureCertificate()
assert.Nil(t, tls)
assert.Error(t, err)
- _, err2 := testDomain.ensureCertificate()
+ _, err2 := testDomain.EnsureCertificate()
assert.Error(t, err)
assert.Equal(t, err, err2)
}
func TestDomainCertificate(t *testing.T) {
- testDomain := &domain{
- Group: "group",
- ProjectName: "project2",
- Config: &domainConfig{
+ testDomain := &D{
+ group: "group",
+ projectName: "project2",
+ config: &domainConfig{
Domain: "test.domain.com",
- Certificate: CertificateFixture,
- Key: KeyFixture,
+ Certificate: fixture.Certificate,
+ Key: fixture.Key,
},
}
- tls, err := testDomain.ensureCertificate()
+ tls, err := testDomain.EnsureCertificate()
assert.NotNil(t, tls)
require.NoError(t, err)
}
func TestCacheControlHeaders(t *testing.T) {
- testGroup := &domain{Group: "group"}
+ testGroup := &D{group: "group"}
w := httptest.NewRecorder()
req, err := http.NewRequest("GET", "http://group.test.io/", nil)
require.NoError(t, err)
@@ -261,3 +264,18 @@ func TestCacheControlHeaders(t *testing.T) {
assert.WithinDuration(t, now.UTC().Add(10*time.Minute), expiresTime.UTC(), time.Minute)
}
+
+var chdirSet = false
+
+func setUpTests() {
+ if chdirSet {
+ return
+ }
+
+ err := os.Chdir("../../shared/pages")
+ if err != nil {
+ log.WithError(err).Print("chdir")
+ } else {
+ chdirSet = true
+ }
+}
diff --git a/domains.go b/internal/domain/map.go
index 291b0faa..ad38e84b 100644
--- a/domains.go
+++ b/internal/domain/map.go
@@ -1,4 +1,4 @@
-package main
+package domain
import (
"bytes"
@@ -15,15 +15,16 @@ import (
"gitlab.com/gitlab-org/gitlab-pages/metrics"
)
-type domainMap map[string]*domain
+// Map maps domain names to D instances.
+type Map map[string]*D
-type domainsUpdater func(domainMap)
+type domainsUpdater func(Map)
-func (dm domainMap) addDomain(rootDomain, group, projectName string, config *domainConfig) {
- newDomain := &domain{
- Group: group,
- ProjectName: projectName,
- Config: config,
+func (dm Map) addDomain(rootDomain, group, projectName string, config *domainConfig) {
+ newDomain := &D{
+ group: group,
+ projectName: projectName,
+ config: config,
}
var domainName string
@@ -31,25 +32,25 @@ func (dm domainMap) addDomain(rootDomain, group, projectName string, config *dom
dm[domainName] = newDomain
}
-func (dm domainMap) updateGroupDomain(rootDomain, group, projectName string, httpsOnly bool) {
+func (dm Map) updateGroupDomain(rootDomain, group, projectName string, httpsOnly bool) {
domainName := strings.ToLower(group + "." + rootDomain)
groupDomain := dm[domainName]
if groupDomain == nil {
- groupDomain = &domain{
- Group: group,
- Projects: make(projects),
+ groupDomain = &D{
+ group: group,
+ projects: make(projects),
}
}
- groupDomain.Projects[projectName] = &project{
+ groupDomain.projects[projectName] = &project{
HTTPSOnly: httpsOnly,
}
dm[domainName] = groupDomain
}
-func (dm domainMap) readProjectConfig(rootDomain string, group, projectName string, config *domainsConfig) {
+func (dm Map) readProjectConfig(rootDomain string, group, projectName string, config *domainsConfig) {
if config == nil {
// This is necessary to preserve the previous behaviour where a
// group domain is created even if no config.json files are
@@ -117,7 +118,8 @@ type jobResult struct {
config *domainsConfig
}
-func (dm domainMap) ReadGroups(rootDomain string) error {
+// ReadGroups walks the pages directory and populates dm with all the domains it finds.
+func (dm Map) ReadGroups(rootDomain string) error {
fis, err := godirwalk.ReadDirents(".", nil)
if err != nil {
return err
@@ -180,7 +182,8 @@ const (
updateFile = ".update"
)
-func watchDomains(rootDomain string, updater domainsUpdater, interval time.Duration) {
+// Watch polls the filesystem and kicks off a new domain directory scan when needed.
+func Watch(rootDomain string, updater domainsUpdater, interval time.Duration) {
lastUpdate := []byte("no-update")
for {
@@ -200,7 +203,7 @@ func watchDomains(rootDomain string, updater domainsUpdater, interval time.Durat
lastUpdate = update
started := time.Now()
- dm := make(domainMap)
+ dm := make(Map)
if err := dm.ReadGroups(rootDomain); err != nil {
log.WithError(err).Warn("domain scan failed")
}
@@ -234,7 +237,7 @@ func watchDomains(rootDomain string, updater domainsUpdater, interval time.Durat
}
}
-func logConfiguredDomains(dm domainMap) {
+func logConfiguredDomains(dm Map) {
if log.GetLevel() == log.DebugLevel {
return
}
diff --git a/domains_test.go b/internal/domain/map_test.go
index e1196765..f20f98bd 100644
--- a/domains_test.go
+++ b/internal/domain/map_test.go
@@ -1,4 +1,4 @@
-package main
+package domain
import (
"crypto/rand"
@@ -15,7 +15,7 @@ import (
func TestReadProjects(t *testing.T) {
setUpTests()
- dm := make(domainMap)
+ dm := make(Map)
err := dm.ReadGroups("test.io")
require.NoError(t, err)
@@ -47,10 +47,10 @@ func TestReadProjects(t *testing.T) {
// Check that multiple domains in the same project are recorded faithfully
exp1 := &domainConfig{Domain: "test.domain.com"}
- assert.Equal(t, exp1, dm["test.domain.com"].Config)
+ assert.Equal(t, exp1, dm["test.domain.com"].config)
exp2 := &domainConfig{Domain: "other.domain.com", Certificate: "test", Key: "key"}
- assert.Equal(t, exp2, dm["other.domain.com"].Config)
+ assert.Equal(t, exp2, dm["other.domain.com"].config)
}
// This write must be atomic, otherwise we cannot predict the state of the
@@ -62,7 +62,7 @@ func writeRandomTimestamp(t *testing.T) {
n, _ := rand.Read(b)
require.True(t, n > 0, "read some random bytes")
- temp, err := ioutil.TempFile(".", "TestWatchDomains")
+ temp, err := ioutil.TempFile(".", "TestWatch")
require.NoError(t, err)
_, err = temp.Write(b)
require.NoError(t, err, "write to tempfile")
@@ -71,13 +71,13 @@ func writeRandomTimestamp(t *testing.T) {
require.NoError(t, os.Rename(temp.Name(), updateFile), "rename tempfile")
}
-func TestWatchDomains(t *testing.T) {
+func TestWatch(t *testing.T) {
setUpTests()
require.NoError(t, os.RemoveAll(updateFile))
- update := make(chan domainMap)
- go watchDomains("gitlab.io", func(dm domainMap) {
+ update := make(chan Map)
+ go Watch("gitlab.io", func(dm Map) {
update <- dm
}, time.Microsecond*50)
@@ -95,7 +95,7 @@ func TestWatchDomains(t *testing.T) {
assert.NotNil(t, domains, "if the domains are updated after the timestamp change")
}
-func recvTimeout(t *testing.T, ch <-chan domainMap) domainMap {
+func recvTimeout(t *testing.T, ch <-chan Map) Map {
timeout := 5 * time.Second
select {
@@ -138,9 +138,9 @@ func BenchmarkReadGroups(b *testing.B) {
}
b.Run("ReadGroups", func(b *testing.B) {
- var dm domainMap
+ var dm Map
for i := 0; i < 2; i++ {
- dm = make(domainMap)
+ dm = make(Map)
require.NoError(b, dm.ReadGroups("example.com"))
}
b.Logf("found %d domains", len(dm))
diff --git a/internal/fixture/fixtures.go b/internal/fixture/fixtures.go
new file mode 100644
index 00000000..38bbd375
--- /dev/null
+++ b/internal/fixture/fixtures.go
@@ -0,0 +1,56 @@
+package fixture
+
+const (
+ // Certificate is used for HTTPS tests
+ Certificate = `-----BEGIN CERTIFICATE-----
+MIIDZDCCAkygAwIBAgIRAOtN9/zy+gFjdsgpKq3QRdQwDQYJKoZIhvcNAQELBQAw
+MzEUMBIGA1UEChMLTG9nIENvdXJpZXIxGzAZBgNVBAMTEmdpdGxhYi1leGFtcGxl
+LmNvbTAgFw0xODAzMjMxODMwMDZaGA8yMTE4MDIyNzE4MzAwNlowMzEUMBIGA1UE
+ChMLTG9nIENvdXJpZXIxGzAZBgNVBAMTEmdpdGxhYi1leGFtcGxlLmNvbTCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKULsxpnazXX5RsVzayrAQB+lWwr
+Wef5L5eDhSsIsBLbelYp5YB4TmVRt5x7bWKOOJSBsOfwHZHKJXdu+uuX2RenZlhk
+3Qpq9XGaPZjYm/NHi8gBHPAtz5sG5VaKNvkfTzRGnO9CWA9TM1XtYiOBq94dO+H3
+c+5jP5Yw+mJ+hA+i2058zF8nRlUHArEno2ofrHwE0LMZ11VskpXtWnVfs3voLs8p
+r76KXPBFkMJR4qkWrMDF5Y5MbsQ0zisn6KXrTyV0S4MQh4vSyPdFHnEzvJ07rm5x
+4RTWrjgQeQ2DjZjQvRmaDzlVBK9kaMkJ1Si3agK+gpji6d6WZ/Mb2el1GK8CAwEA
+AaNxMG8wDgYDVR0PAQH/BAQDAgKkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1Ud
+EwEB/wQFMAMBAf8wNwYDVR0RBDAwLoIUKi5naXRsYWItZXhhbXBsZS5jb22HBH8A
+AAGHEAAAAAAAAAAAAAAAAAAAAAEwDQYJKoZIhvcNAQELBQADggEBAJ0NM8apK0xI
+YxMstP/dCQXtR0wyREGSD/eOpeY3bWlqCbpRgMFUGjQlrsEozcPZOCSCKX5p+tym
+7GsnYtXkwbsuURoSz+5IlhRPVHcUlUeGRdv3/gCd8fDXiigALCsB6GrkMG5cUfh+
+x5p52AC3eQdWTDoxNou+2gzwkAl8iJc13Ykusst0YUqcsXKqTuei2quxFv0pEBSO
+p8wEixoicLFNqPnIDmgx5894DAn0bccNXgRWtq8lLbdhGUlBbpatevvFMgNvFUbe
+eeGb9D0EfpxmzxUl+L0xZtfg3f7cu5AgLG8tb6l4AK6NPVuXN8DmUgvnauWJjZME
+fgStI+IRNVg=
+-----END CERTIFICATE-----
+`
+
+ // Key is used for HTTPS tests
+ Key = `-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEApQuzGmdrNdflGxXNrKsBAH6VbCtZ5/kvl4OFKwiwEtt6Vinl
+gHhOZVG3nHttYo44lIGw5/Adkcold27665fZF6dmWGTdCmr1cZo9mNib80eLyAEc
+8C3PmwblVoo2+R9PNEac70JYD1MzVe1iI4Gr3h074fdz7mM/ljD6Yn6ED6LbTnzM
+XydGVQcCsSejah+sfATQsxnXVWySle1adV+ze+guzymvvopc8EWQwlHiqRaswMXl
+jkxuxDTOKyfopetPJXRLgxCHi9LI90UecTO8nTuubnHhFNauOBB5DYONmNC9GZoP
+OVUEr2RoyQnVKLdqAr6CmOLp3pZn8xvZ6XUYrwIDAQABAoIBAHhP5QnUZeTkMtDh
+vgKmzZ4sqIQnvexKTBUo/MR4GtJESBPTisdx68QUI8LgfsafYkNvnyQUd5m1QEam
+Eif3k3uYvhSlwjQ78BwWEdz/2f8oIo9zsEKtQm+CQWAqdRR5bGVxLCmFtWfGgN+c
+ojO77SuHKAX7OvmGQ+4aWgu+qkoyg/chIpPXMduAjLMtN3eg60ZqJ5KrKuIF63Bb
+xkPQvzJueB9SfUurmKjUltDMx6G/9RZyS0OIRGyL9Qp8MZ8jE23cXOcDgm0HhkPq
+W4LU++aWAOLYziTjnhjJ+4Iz9R7U8sCmk1wgnK/tapVcJf41R98WuGluyjXpsXgA
+k7vmofECgYEAzuGun9lZ7xGwPifp6vGanWXnW+JiZgCTGuHWgQLIXWYcLfoI3kpH
+eLBYINBwvjIQ7P6UxsGSSXd+T82t+8W2LLc2fiKFKE1LVySpH99+cfmIPXxrviOz
+GBX9LTdSCdGkgb54m8aJCpNFnKw5wYgcW1L8CaXXly2Z/KNrGR9R/YUCgYEAzDs4
+19HqlutGLTC30/ziiiIfDaBbX9AzBdUfp9GdT53Mi/7bfxpW/sL4RjG2fGgmN6ua
+fh5npT9AB1ldcEg2qfyOJPt1Ubdi6ek9lx8AB2RMhwdihgX+7bjVMFtjg4b8z5C1
+jQbEr1rhFdpaGyNehtAXDgCbDWQBYnBrmM0rCaMCgYBip1Qyfd9ZFcJJoZb2pofo
+jvOo6Weq5JNBungjxUPu5gaCFj2sYxd6Af3EiCF7UTypBy3DKgOsbQMa4yYYbcvV
+vviJZcTB1zoaMC1GObl+eFPzniVy4mtBDRtSOJMyg3pDNKUnA6HOHTSQ5cAU/ecn
+1YbCwwbv3JsV0of7zue2UQKBgQCVc0j3dd9rLSQfcaUz9bx5RNrgh9YV2S9dN0aA
+8f1iA6FpWMiazFWY/GfeRga6JyTAXE0juXAzFoPuXNDpl46Y+f2yxmhlsgMqFMpD
+SiYlQppVvWu1k7GnmDg5uMarux5JbiXM24UWpTRNX4nMjidgE+qrDnpoZCQ3Ovkh
+yhGSbQKBgD3VEnPiSUmXBo39kPcnPg93E3JfdAOiOwIB2qwfYzg9kpmuTWws+DFz
+lKpMI27YkmnPqROQ2NTUfdxYmw3EHHMAsvnmHeMNGn3ijSUZVKmPfV436Qc8iVci
+s4wKoCRhBUZ52sHki/ieb+5hycT3JnVXMDtbJxgXFW5a86usXEpO
+-----END RSA PRIVATE KEY-----`
+)