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

Create API type

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