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

buildservice.go « buildservice « internal - gitlab.com/gitlab-org/gitlab-pages.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: a6c82766460a9ce9356d6ffa20c0ea3df39b7348 (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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package buildservice

import (
	"fmt"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"regexp"
	"strings"
	"time"

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

const (
	proxyURLTemplate = "%s/api/v4/jobs/%s/proxy/%s/%s"
	domainKeyword    = "proxy"
)

// The domain structure is:
// username.domainKeywork.build_id.service_name.service_port.pages.domain
// Ex: root.proxy.1.service_name.service_port.xip.io:3010
// Service_port can be either a number or a string
var (
	// Captures subgroup + project, job ID and artifacts path
	domainExtractor = regexp.MustCompile(`(?i)\A(.+)\.` + domainKeyword + `\.(\d+)\.(.+)\.(.+)\z`)
)

// Artifact proxies requests for artifact files to the GitLab artifacts API
type BuildService struct {
	server string
	suffix string
	client *http.Client
}

// New when provided the arguments defined herein, returns a pointer to an
// BuildService that is used to proxy requests.
func New(server string, timeoutSeconds int, pagesDomain string) *BuildService {
	return &BuildService{
		server: strings.TrimRight(server, "/"),
		suffix: "." + strings.ToLower(pagesDomain),
		client: &http.Client{
			Timeout:   time.Second * time.Duration(timeoutSeconds),
			Transport: httptransport.Transport,
		},
	}
}

// TryMakeRequest will attempt to proxy a request and write it to the argument
// http.ResponseWriter, ultimately returning a bool that indicates if the
// http.ResponseWriter has been written to in any capacity.
func (a *BuildService) TryMakeRequest(host string, token string, w http.ResponseWriter, r *http.Request) bool {
	if a.server == "" || host == "" || token == "" {
		return false
	}

	rewrittenReq, ok := a.rewriteRequest(host, r)
	if !ok {
		return false
	}

	a.makeRequest(w, rewrittenReq, token)
	return true
}

func (a *BuildService) makeRequest(w http.ResponseWriter, req *http.Request, token string) {
	u, _ := url.Parse(a.server)
	proxy := httputil.NewSingleHostReverseProxy(u)

	req.Header.Add("Authorization", "Bearer "+token)
	proxy.ServeHTTP(w, req)
}

// BuildURL returns a pointer to a url.URL for where the request should be
// proxied to. The returned bool will indicate if there is some sort of issue
// with the url while it is being generated.
//
// The URL is generated from the host (which contains the top-level group and
// ends with the pagesDomain) and the path (which contains any subgroups, the
// project, a job ID
func (a *BuildService) rewriteRequest(host string, r *http.Request) (*http.Request, bool) {
	if !strings.HasSuffix(strings.ToLower(host), a.suffix) {
		return nil, false
	}

	topDomain := host[0 : len(host)-len(a.suffix)]
	domainParts := domainExtractor.FindAllStringSubmatch(topDomain, 1)
	if len(domainParts) != 1 || len(domainParts[0]) != 5 {
		return nil, false
	}

	jobID := domainParts[0][2]
	serviceName := domainParts[0][3]
	servicePort := domainParts[0][4]
	generated := fmt.Sprintf(proxyURLTemplate, a.server, jobID, serviceName, servicePort)

	u, err := url.Parse(generated)
	if err != nil {
		return nil, false
	}

	log.Printf("r.URL.RawQuery: %#+v\n", r.URL.RawQuery)
	q := url.Values{"path": []string{r.URL.Path}}
	q["wrapped_raw_query_"+jobID] = []string{r.URL.RawQuery}
	u.RawQuery = q.Encode()

	// Rewritten request
	r.URL = u
	log.Printf("r.URL.Pathj: %#+v\n", r.URL.Path)
	log.Printf("r.URL.Query(): %#+v\n", r.URL.Query())

	// if err := r.ParseForm(); err != nil {
	// 	return nil, false
	// }

	// r.Form.Set("HTTP_JOB_TOKEN", "2z3OV406fjsxgAF3xUjS0JA/+u9sVpr0vKhU0FuLRwquFJx5")

	return r, true
}