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:
authorGrzegorz Bizon <grzesiek.bizon@gmail.com>2019-09-26 15:14:51 +0300
committerGrzegorz Bizon <grzesiek.bizon@gmail.com>2019-09-27 12:49:36 +0300
commit3cc7bc556307adbc8fac6942240bafceb0ff5d5d (patch)
treeaa959a2b56a2fcb78830740cb5b639d8ffe39637 /internal/domain/domain.go
parentbf3b3983eae2cb83e82224d4f936ccee1b4322ef (diff)
Unify how we handle custom and group domain in serving
Diffstat (limited to 'internal/domain/domain.go')
-rw-r--r--internal/domain/domain.go138
1 files changed, 73 insertions, 65 deletions
diff --git a/internal/domain/domain.go b/internal/domain/domain.go
index 361c3b87..1dd5be51 100644
--- a/internal/domain/domain.go
+++ b/internal/domain/domain.go
@@ -5,31 +5,23 @@ import (
"errors"
"net/http"
"sync"
- "time"
"gitlab.com/gitlab-org/gitlab-pages/internal/httperrors"
"gitlab.com/gitlab-org/gitlab-pages/internal/serving"
)
-// GroupConfig represents a per-request config for a group domain
-type GroupConfig interface {
- IsHTTPSOnly(*http.Request) bool
- HasAccessControl(*http.Request) bool
- IsNamespaceProject(*http.Request) bool
- ProjectID(*http.Request) uint64
- ProjectExists(*http.Request) bool
- ProjectWithSubpath(*http.Request) (string, string, error)
-}
-
// Domain is a domain that gitlab-pages can serve.
type Domain struct {
- Group string
- Project string
+ Name string
+ Location string
+ CertificateCert string
+ CertificateKey string
+ Customized bool // TODO we should get rid of this
- GroupConfig GroupConfig // handles group domain config
- ProjectConfig *ProjectConfig
+ Resolver Resolver
- serving serving.Serving
+ lookupPaths map[string]*Project
+ serving serving.Serving
certificate *tls.Certificate
certificateError error
@@ -38,15 +30,7 @@ type Domain struct {
// String implements Stringer.
func (d *Domain) String() string {
- if d.Group != "" && d.Project != "" {
- return d.Group + "/" + d.Project
- }
-
- if d.Group != "" {
- return d.Group
- }
-
- return d.Project
+ return d.Name
}
func (d *Domain) isCustomDomain() bool {
@@ -54,7 +38,7 @@ func (d *Domain) isCustomDomain() bool {
panic("project config and group config should not be nil at the same time")
}
- return d.ProjectConfig != nil && d.GroupConfig == nil
+ return d.Customized
}
func (d *Domain) isUnconfigured() bool {
@@ -62,22 +46,52 @@ func (d *Domain) isUnconfigured() bool {
return true
}
- return d.ProjectConfig == nil && d.GroupConfig == nil
+ return d.Resolver == nil
+}
+
+func (d *Domain) resolve(r *http.Request) (*Project, string) {
+ // TODO use lookupPaths first
+
+ project, subpath, _ := d.Resolver.Resolve(r)
+ // current implementation does not return errors in any case
+
+ if project == nil {
+ return nil, ""
+ }
+
+ return project, subpath
+}
+
+func (d *Domain) getProject(r *http.Request) *Project {
+ project, _ := d.resolve(r)
+
+ return project
}
// Serving returns domain serving driver
func (d *Domain) Serving() serving.Serving {
if d.serving == nil {
- if d.isCustomDomain() {
- d.serving = serving.NewProjectDiskServing(d.Project, d.Group)
- } else {
- d.serving = serving.NewGroupDiskServing(d.Group, d.GroupConfig)
- }
+ d.serving = serving.NewDiskServing(d.Name, d.Location)
}
return d.serving
}
+func (d *Domain) toHandler(w http.ResponseWriter, r *http.Request) *handler {
+ project, subpath := d.resolve(r)
+
+ return &handler{
+ writer: w,
+ request: r,
+ project: project,
+ subpath: subpath,
+ }
+}
+
+func (d *Domain) hasProject(r *http.Request) bool {
+ return d.getProject(r) != nil
+}
+
// IsHTTPSOnly figures out if the request should be handled with HTTPS
// only by looking at group and project level config.
func (d *Domain) IsHTTPSOnly(r *http.Request) bool {
@@ -85,13 +99,11 @@ func (d *Domain) IsHTTPSOnly(r *http.Request) bool {
return false
}
- // Check custom domain config (e.g. http://example.com)
- if d.isCustomDomain() {
- return d.ProjectConfig.HTTPSOnly
+ if project := d.getProject(r); project != nil {
+ return project.IsHTTPSOnly
}
- // Check projects served under the group domain, including the default one
- return d.GroupConfig.IsHTTPSOnly(r)
+ return false
}
// IsAccessControlEnabled figures out if the request is to a project that has access control enabled
@@ -100,22 +112,20 @@ func (d *Domain) IsAccessControlEnabled(r *http.Request) bool {
return false
}
- // Check custom domain config (e.g. http://example.com)
- if d.isCustomDomain() {
- return d.ProjectConfig.AccessControl
+ if project := d.getProject(r); project != nil {
+ return project.HasAccessControl
}
- // Check projects served under the group domain, including the default one
- return d.GroupConfig.HasAccessControl(r)
+ return false
}
// HasAcmeChallenge checks domain directory contains particular acme challenge
-func (d *Domain) HasAcmeChallenge(token string) bool {
- if d.isUnconfigured() || !d.isCustomDomain() {
+func (d *Domain) HasAcmeChallenge(r *http.Request, token string) bool {
+ if d.isUnconfigured() || !d.isCustomDomain() || !d.hasProject(r) {
return false
}
- return d.Serving().HasAcmeChallenge(token)
+ return d.Serving().HasAcmeChallenge(d.toHandler(nil, r), token) // TODO
}
// IsNamespaceProject figures out if the request is to a namespace project
@@ -126,12 +136,15 @@ func (d *Domain) IsNamespaceProject(r *http.Request) bool {
// If request is to a custom domain, we do not handle it as a namespace project
// as there can't be multiple projects under the same custom domain
- if d.isCustomDomain() {
+ if d.isCustomDomain() { // TODO do we need a separate path for this
return false
}
- // Check projects served under the group domain, including the default one
- return d.GroupConfig.IsNamespaceProject(r)
+ if project := d.getProject(r); project != nil {
+ return project.IsNamespaceProject
+ }
+
+ return false
}
// GetID figures out what is the ID of the project user tries to access
@@ -140,11 +153,11 @@ func (d *Domain) GetID(r *http.Request) uint64 {
return 0
}
- if d.isCustomDomain() {
- return d.ProjectConfig.ProjectID
+ if project := d.getProject(r); project != nil {
+ return project.ID
}
- return d.GroupConfig.ProjectID(r)
+ return 0
}
// HasProject figures out if the project exists that the user tries to access
@@ -153,15 +166,16 @@ func (d *Domain) HasProject(r *http.Request) bool {
return false
}
- if d.isCustomDomain() {
+ if project := d.getProject(r); project != nil {
return true
}
- return d.GroupConfig.ProjectExists(r)
+ return false
}
// EnsureCertificate parses the PEM-encoded certificate for the domain
func (d *Domain) EnsureCertificate() (*tls.Certificate, error) {
+ // TODO check len certificates instead of custom domain!
if d.isUnconfigured() || !d.isCustomDomain() {
return nil, errors.New("tls certificates can be loaded only for pages with configuration")
}
@@ -169,8 +183,8 @@ func (d *Domain) EnsureCertificate() (*tls.Certificate, error) {
d.certificateOnce.Do(func() {
var cert tls.Certificate
cert, d.certificateError = tls.X509KeyPair(
- []byte(d.ProjectConfig.Certificate),
- []byte(d.ProjectConfig.Key),
+ []byte(d.CertificateCert),
+ []byte(d.CertificateKey),
)
if d.certificateError == nil {
d.certificate = &cert
@@ -182,26 +196,20 @@ func (d *Domain) EnsureCertificate() (*tls.Certificate, error) {
// ServeFileHTTP returns true if something was served, false if not.
func (d *Domain) ServeFileHTTP(w http.ResponseWriter, r *http.Request) bool {
- if d.isUnconfigured() {
+ if d.isUnconfigured() || !d.hasProject(r) {
httperrors.Serve404(w)
return true
}
- if !d.IsAccessControlEnabled(r) {
- // Set caching headers
- w.Header().Set("Cache-Control", "max-age=600")
- w.Header().Set("Expires", time.Now().Add(10*time.Minute).Format(time.RFC1123))
- }
-
- return d.Serving().ServeFileHTTP(w, r)
+ return d.Serving().ServeFileHTTP(d.toHandler(w, r))
}
// ServeNotFoundHTTP serves the not found pages from the projects.
func (d *Domain) ServeNotFoundHTTP(w http.ResponseWriter, r *http.Request) {
- if d.isUnconfigured() {
+ if d.isUnconfigured() || !d.hasProject(r) {
httperrors.Serve404(w)
return
}
- d.Serving().ServeNotFoundHTTP(w, r)
+ d.Serving().ServeNotFoundHTTP(d.toHandler(w, r))
}