diff --git a/README.md b/README.md index 7ae751e20898483a490e9558ac68d260f081ebc7..d007e8d5384dbd4de04f9cd0e107971cd1e3ca92 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,16 @@ gitlab-workhorse can listen on either a TCP or a Unix domain socket. It can also open a second listening TCP listening socket with the Go [net/http/pprof profiler server](http://golang.org/pkg/net/http/pprof/). +### Relative URL support + +If you are mounting GitLab at a relative URL, e.g. +`example.com/gitlab`, then you should also use this relative URL in +the `authBackend` setting: + +``` +gitlab-workhorse -authBackend http://localhost:8080/gitlab +``` + ## Installation To install into `/usr/local/bin` run `make install`. diff --git a/authorization.go b/authorization.go index c12ac90118d3710e0ebe569cb120531b566c4d1b..4f58a6d270150649666fdf0effd8aa930cb3515d 100644 --- a/authorization.go +++ b/authorization.go @@ -9,7 +9,7 @@ import ( ) func (u *upstream) newUpstreamRequest(r *http.Request, body io.Reader, suffix string) (*http.Request, error) { - url := u.authBackend + r.URL.RequestURI() + suffix + 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 diff --git a/main.go b/main.go index 0c5a9fcb2d4b5816b2149a8ea97a8ea7ff4acced..324e4dc113480552bb45f1cf6bbcc1940f373f32 100644 --- a/main.go +++ b/main.go @@ -36,7 +36,6 @@ var listenUmask = flag.Int("listenUmask", 022, "Umask for Unix socket, default: var authBackend = flag.String("authBackend", "http://localhost:8080", "Authentication/authorization backend") var authSocket = flag.String("authSocket", "", "Optional: Unix domain socket to dial authBackend at") var pprofListenAddr = flag.String("pprofListenAddr", "", "pprof listening address, e.g. 'localhost:6060'") -var relativeURLRoot = flag.String("relativeURLRoot", "/", "GitLab relative URL root") var documentRoot = flag.String("documentRoot", "public", "Path to static files content") var responseHeadersTimeout = flag.Duration("proxyHeadersTimeout", time.Minute, "How long to wait for response headers when proxying the request") var developmentMode = flag.Bool("developmentMode", false, "Allow to serve assets from Rails app") @@ -170,6 +169,5 @@ func main() { } upstream := newUpstream(*authBackend, proxyTransport) - upstream.SetRelativeURLRoot(*relativeURLRoot) log.Fatal(http.Serve(listener, upstream)) } diff --git a/upstream.go b/upstream.go index b6ac589714f675b5057cfc62830f94445c7b337e..bcfbc8a34461e4a698b80cde4bb18db745dc654c 100644 --- a/upstream.go +++ b/upstream.go @@ -64,29 +64,30 @@ type gitRequest struct { } func newUpstream(authBackend string, authTransport http.RoundTripper) *upstream { - u, err := url.Parse(authBackend) + gitlabURL, err := url.Parse(authBackend) if err != nil { log.Fatalln(err) } + relativeURLRoot := gitlabURL.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 = "" up := &upstream{ authBackend: authBackend, httpClient: &http.Client{Transport: authTransport}, - httpProxy: httputil.NewSingleHostReverseProxy(u), - relativeURLRoot: "/", + httpProxy: httputil.NewSingleHostReverseProxy(gitlabURL), + relativeURLRoot: relativeURLRoot, } up.httpProxy.Transport = authTransport return up } -func (u *upstream) SetRelativeURLRoot(relativeURLRoot string) { - u.relativeURLRoot = relativeURLRoot - - if !strings.HasSuffix(u.relativeURLRoot, "/") { - u.relativeURLRoot += "/" - } -} - func (u *upstream) ServeHTTP(ow http.ResponseWriter, r *http.Request) { var g httpRoute @@ -107,7 +108,7 @@ func (u *upstream) ServeHTTP(ow http.ResponseWriter, r *http.Request) { // Check URL Root URIPath := cleanURIPath(r.URL.Path) - if !strings.HasPrefix(URIPath, u.relativeURLRoot) { + if !strings.HasPrefix(URIPath, u.relativeURLRoot) && URIPath+"/" != u.relativeURLRoot { httpError(&w, r, fmt.Sprintf("Not found %q", URIPath), http.StatusNotFound) return }