Commit 4ab87246 authored by Jacob Vosmaer's avatar Jacob Vosmaer

Create API type

parent ae365421
......@@ -4,8 +4,8 @@ import (
"net/http"
)
func (u *upstream) artifactsAuthorizeHandler(h httpHandleFunc) httpHandleFunc {
return u.preAuthorizeHandler(func(w http.ResponseWriter, r *http.Request, a *authorizationResponse) {
func (api API) artifactsAuthorizeHandler(h httpHandleFunc) httpHandleFunc {
return api.preAuthorizeHandler(func(w http.ResponseWriter, r *http.Request, a *authorizationResponse) {
r.Header.Set(tempPathHeader, a.TempPath)
h(w, r)
}, "/authorize")
......
......@@ -4,20 +4,21 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"strings"
)
func (u *upstream) newUpstreamRequest(r *http.Request, body io.Reader, suffix string) (*http.Request, error) {
url := u.authBackend + "/" + strings.TrimPrefix(r.URL.RequestURI(), u.relativeURLRoot) + suffix
authReq, err := http.NewRequest(r.Method, url, body)
if err != nil {
return nil, err
func (api *API) newUpstreamRequest(r *http.Request, body io.Reader, suffix string) (*http.Request, error) {
url := *api.URL
url.Path = r.URL.RequestURI() + suffix
authReq := &http.Request{
Method: r.Method,
URL: &url,
Header: headerClone(r.Header),
}
// Forward all headers from our client to the auth backend. This includes
// HTTP Basic authentication credentials (the 'Authorization' header).
for k, v := range r.Header {
authReq.Header[k] = v
if body != nil {
authReq.Body = ioutil.NopCloser(body)
}
// Clean some headers when issuing a new request without body
......@@ -51,15 +52,15 @@ func (u *upstream) newUpstreamRequest(r *http.Request, body io.Reader, suffix st
return authReq, nil
}
func (u *upstream) preAuthorizeHandler(h serviceHandleFunc, suffix string) httpHandleFunc {
func (api *API) preAuthorizeHandler(h serviceHandleFunc, suffix string) httpHandleFunc {
return func(w http.ResponseWriter, r *http.Request) {
authReq, err := u.newUpstreamRequest(r, nil, suffix)
authReq, err := api.newUpstreamRequest(r, nil, suffix)
if err != nil {
fail500(w, fmt.Errorf("preAuthorizeHandler: newUpstreamRequest: %v", err))
return
}
authResponse, err := u.httpClient.Do(authReq)
authResponse, err := api.Do(authReq)
if err != nil {
fail500(w, fmt.Errorf("preAuthorizeHandler: do %v: %v", authReq.URL.Path, err))
return
......
......@@ -23,10 +23,10 @@ func runPreAuthorizeHandler(t *testing.T, suffix string, url *regexp.Regexp, aut
if err != nil {
t.Fatal(err)
}
u := newUpstream(ts.URL, nil)
api := newUpstream(ts.URL, nil).API
response := httptest.NewRecorder()
u.preAuthorizeHandler(okHandler, suffix)(response, httpRequest)
api.preAuthorizeHandler(okHandler, suffix)(response, httpRequest)
assertResponseCode(t, response, expectedCode)
return response
}
......
......@@ -26,8 +26,8 @@ func looksLikeRepo(p string) bool {
return true
}
func (u *upstream) repoPreAuthorizeHandler(handleFunc serviceHandleFunc) httpHandleFunc {
return u.preAuthorizeHandler(func(w http.ResponseWriter, r *http.Request, a *authorizationResponse) {
func (api *API) repoPreAuthorizeHandler(handleFunc serviceHandleFunc) httpHandleFunc {
return api.preAuthorizeHandler(func(w http.ResponseWriter, r *http.Request, a *authorizationResponse) {
if a.RepoPath == "" {
fail500(w, errors.New("repoPreAuthorizeHandler: RepoPath empty"))
return
......
......@@ -17,8 +17,8 @@ import (
"path/filepath"
)
func (u *upstream) lfsAuthorizeHandler(handleFunc serviceHandleFunc) httpHandleFunc {
return u.preAuthorizeHandler(func(w http.ResponseWriter, r *http.Request, a *authorizationResponse) {
func (api *API) lfsAuthorizeHandler(handleFunc serviceHandleFunc) httpHandleFunc {
return api.preAuthorizeHandler(func(w http.ResponseWriter, r *http.Request, a *authorizationResponse) {
if a.StoreLFSPath == "" {
fail500(w, errors.New("lfsAuthorizeHandler: StoreLFSPath empty"))
......
......@@ -62,26 +62,27 @@ const ciAPIPattern = `^/ci/api/`
var httpRoutes []httpRoute
func compileRoutes(u *upstream) {
api := u.API
httpRoutes = []httpRoute{
// Git Clone
httpRoute{"GET", regexp.MustCompile(gitProjectPattern + `info/refs\z`), u.repoPreAuthorizeHandler(handleGetInfoRefs)},
httpRoute{"POST", regexp.MustCompile(gitProjectPattern + `git-upload-pack\z`), contentEncodingHandler(u.repoPreAuthorizeHandler(handlePostRPC))},
httpRoute{"POST", regexp.MustCompile(gitProjectPattern + `git-receive-pack\z`), contentEncodingHandler(u.repoPreAuthorizeHandler(handlePostRPC))},
httpRoute{"PUT", regexp.MustCompile(gitProjectPattern + `gitlab-lfs/objects/([0-9a-f]{64})/([0-9]+)\z`), u.lfsAuthorizeHandler(u.handleStoreLfsObject)},
httpRoute{"GET", regexp.MustCompile(gitProjectPattern + `info/refs\z`), api.repoPreAuthorizeHandler(handleGetInfoRefs)},
httpRoute{"POST", regexp.MustCompile(gitProjectPattern + `git-upload-pack\z`), contentEncodingHandler(api.repoPreAuthorizeHandler(handlePostRPC))},
httpRoute{"POST", regexp.MustCompile(gitProjectPattern + `git-receive-pack\z`), contentEncodingHandler(api.repoPreAuthorizeHandler(handlePostRPC))},
httpRoute{"PUT", regexp.MustCompile(gitProjectPattern + `gitlab-lfs/objects/([0-9a-f]{64})/([0-9]+)\z`), api.lfsAuthorizeHandler(u.handleStoreLfsObject)},
// Repository Archive
httpRoute{"GET", regexp.MustCompile(projectPattern + `repository/archive\z`), u.repoPreAuthorizeHandler(handleGetArchive)},
httpRoute{"GET", regexp.MustCompile(projectPattern + `repository/archive.zip\z`), u.repoPreAuthorizeHandler(handleGetArchive)},
httpRoute{"GET", regexp.MustCompile(projectPattern + `repository/archive.tar\z`), u.repoPreAuthorizeHandler(handleGetArchive)},
httpRoute{"GET", regexp.MustCompile(projectPattern + `repository/archive.tar.gz\z`), u.repoPreAuthorizeHandler(handleGetArchive)},
httpRoute{"GET", regexp.MustCompile(projectPattern + `repository/archive.tar.bz2\z`), u.repoPreAuthorizeHandler(handleGetArchive)},
httpRoute{"GET", regexp.MustCompile(projectPattern + `repository/archive\z`), api.repoPreAuthorizeHandler(handleGetArchive)},
httpRoute{"GET", regexp.MustCompile(projectPattern + `repository/archive.zip\z`), api.repoPreAuthorizeHandler(handleGetArchive)},
httpRoute{"GET", regexp.MustCompile(projectPattern + `repository/archive.tar\z`), api.repoPreAuthorizeHandler(handleGetArchive)},
httpRoute{"GET", regexp.MustCompile(projectPattern + `repository/archive.tar.gz\z`), api.repoPreAuthorizeHandler(handleGetArchive)},
httpRoute{"GET", regexp.MustCompile(projectPattern + `repository/archive.tar.bz2\z`), api.repoPreAuthorizeHandler(handleGetArchive)},
// Repository Archive API
httpRoute{"GET", regexp.MustCompile(projectsAPIPattern + `repository/archive\z`), u.repoPreAuthorizeHandler(handleGetArchive)},
httpRoute{"GET", regexp.MustCompile(projectsAPIPattern + `repository/archive.zip\z`), u.repoPreAuthorizeHandler(handleGetArchive)},
httpRoute{"GET", regexp.MustCompile(projectsAPIPattern + `repository/archive.tar\z`), u.repoPreAuthorizeHandler(handleGetArchive)},
httpRoute{"GET", regexp.MustCompile(projectsAPIPattern + `repository/archive.tar.gz\z`), u.repoPreAuthorizeHandler(handleGetArchive)},
httpRoute{"GET", regexp.MustCompile(projectsAPIPattern + `repository/archive.tar.bz2\z`), u.repoPreAuthorizeHandler(handleGetArchive)},
httpRoute{"GET", regexp.MustCompile(projectsAPIPattern + `repository/archive\z`), api.repoPreAuthorizeHandler(handleGetArchive)},
httpRoute{"GET", regexp.MustCompile(projectsAPIPattern + `repository/archive.zip\z`), api.repoPreAuthorizeHandler(handleGetArchive)},
httpRoute{"GET", regexp.MustCompile(projectsAPIPattern + `repository/archive.tar\z`), api.repoPreAuthorizeHandler(handleGetArchive)},
httpRoute{"GET", regexp.MustCompile(projectsAPIPattern + `repository/archive.tar.gz\z`), api.repoPreAuthorizeHandler(handleGetArchive)},
httpRoute{"GET", regexp.MustCompile(projectsAPIPattern + `repository/archive.tar.bz2\z`), api.repoPreAuthorizeHandler(handleGetArchive)},
// CI Artifacts API
httpRoute{"POST", regexp.MustCompile(ciAPIPattern + `v1/builds/[0-9]+/artifacts\z`), contentEncodingHandler(u.artifactsAuthorizeHandler(u.handleFileUploads))},
......
......@@ -17,8 +17,14 @@ import (
type serviceHandleFunc func(http.ResponseWriter, *http.Request, *authorizationResponse)
type API struct {
*http.Client
*url.URL
}
type upstream struct {
httpClient *http.Client
*API
httpProxy *httputil.ReverseProxy
authBackend string
relativeURLRoot string
......@@ -53,24 +59,24 @@ type authorizationResponse struct {
}
func newUpstream(authBackend string, authTransport http.RoundTripper) *upstream {
gitlabURL, err := url.Parse(authBackend)
parsedURL, err := url.Parse(authBackend)
if err != nil {
log.Fatalln(err)
}
relativeURLRoot := gitlabURL.Path
relativeURLRoot := parsedURL.Path
if !strings.HasSuffix(relativeURLRoot, "/") {
relativeURLRoot += "/"
}
// If the relative URL is '/foobar' and we tell httputil.ReverseProxy to proxy
// to 'http://example.com/foobar' then we get a redirect loop, so we clear the
// Path field here.
gitlabURL.Path = ""
// Modify a copy of parsedURL
proxyURL := *parsedURL
proxyURL.Path = ""
up := &upstream{
authBackend: authBackend,
httpClient: &http.Client{Transport: authTransport},
httpProxy: httputil.NewSingleHostReverseProxy(gitlabURL),
API: &API{Client: &http.Client{Transport: authTransport}, URL: parsedURL},
httpProxy: httputil.NewSingleHostReverseProxy(&proxyURL),
relativeURLRoot: relativeURLRoot,
}
up.httpProxy.Transport = authTransport
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment