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

validations.go « redirects « internal - gitlab.com/gitlab-org/gitlab-pages.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 4e5eb86ae5d0733126a5d686bd50062e391c2cb6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package redirects

import (
	"net/http"
	"net/url"
	"regexp"
	"strings"

	netlifyRedirects "github.com/tj/go-redirects"

	"gitlab.com/gitlab-org/gitlab-pages/internal/feature"
)

var (
	regexPlaceholder            = regexp.MustCompile(`(?i)^:[a-z]+$`)
	regexSplat                  = regexp.MustCompile(`^\*$`)
	regexPlaceholderReplacement = regexp.MustCompile(`(?i):(?P<placeholder>[a-z]+)`)
)

// validateURL runs validations against a rule URL.
// Returns `nil` if the URL is valid.
func validateURL(urlText string) error {
	url, err := url.Parse(urlText)
	if err != nil {
		return errFailedToParseURL
	}

	// No support for domain-level redirects to outside sites:
	// - `https://google.com`
	// - `//google.com`
	// - `/\google.com`
	if url.Host != "" || url.Scheme != "" || strings.HasPrefix(url.Path, "/\\") {
		return errNoDomainLevelRedirects
	}

	// No parent traversing relative URL's with `./` or `../`
	// No ambiguous URLs like bare domains `GitLab.com`
	if !strings.HasPrefix(url.Path, "/") {
		return errNoStartingForwardSlashInURLPath
	}

	if feature.RedirectsPlaceholders.Enabled() {
		// Limit the number of path segments a rule can contain.
		// This prevents the matching logic from generating regular
		// expressions that are too large/complex.
		if strings.Count(url.Path, "/") > cfg.Redirects.MaxPathSegments {
			return errTooManyPathSegments
		}
	} else {
		// No support for splats, https://docs.netlify.com/routing/redirects/redirect-options/#splats
		if strings.Contains(url.Path, "*") {
			return errNoSplats
		}

		// No support for placeholders, https://docs.netlify.com/routing/redirects/redirect-options/#placeholders
		if regexpPlaceholder.MatchString(url.Path) {
			return errNoPlaceholders
		}
	}

	return nil
}

// validateRule runs all validation rules on the provided rule.
// Returns `nil` if the rule is valid
func validateRule(r netlifyRedirects.Rule) error {
	if err := validateURL(r.From); err != nil {
		return err
	}

	if err := validateURL(r.To); err != nil {
		return err
	}

	// No support for query parameters, https://docs.netlify.com/routing/redirects/redirect-options/#query-parameters
	if r.Params != nil {
		return errNoParams
	}

	// We strictly validate return status codes
	switch r.Status {
	case http.StatusOK, http.StatusMovedPermanently, http.StatusFound:
		// noop
	default:
		return errUnsupportedStatus
	}

	// No support for rules that use ! force
	if r.Force {
		return errNoForce
	}

	return nil
}