From cff33472d57d2d34942b8a34425190da250c771c Mon Sep 17 00:00:00 2001
From: Kamil Trzcinski <ayufan@ayufan.eu>
Date: Wed, 9 Dec 2015 14:16:07 +0100
Subject: [PATCH] Support relativeUrlRoot allowing to serve the app from
 subpath

---
 error_pages.go |  2 +-
 main.go        |  8 +++++++-
 sendfile.go    |  4 ++--
 servefile.go   |  2 +-
 upstream.go    | 12 +++++++++---
 5 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/error_pages.go b/error_pages.go
index 26364f21e56da..4f09ff2b70549 100644
--- a/error_pages.go
+++ b/error_pages.go
@@ -3,8 +3,8 @@ package main
 import (
 	"fmt"
 	"io/ioutil"
-	"net/http"
 	"log"
+	"net/http"
 )
 
 type errorPageResponseWriter struct {
diff --git a/main.go b/main.go
index 7956f5c64c236..7bc445bf8e264 100644
--- a/main.go
+++ b/main.go
@@ -22,6 +22,7 @@ import (
 	_ "net/http/pprof"
 	"os"
 	"regexp"
+	"strings"
 	"syscall"
 	"time"
 )
@@ -35,6 +36,7 @@ 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")
 
 type httpRoute struct {
 	method     string
@@ -84,6 +86,10 @@ func main() {
 		os.Exit(0)
 	}
 
+	if !strings.HasSuffix(*relativeUrlRoot, "/") {
+		*relativeUrlRoot += "/"
+	}
+
 	log.Printf("Starting %s", version)
 
 	// Good housekeeping for Unix sockets: unlink before binding
@@ -128,6 +134,6 @@ func main() {
 	// Because net/http/pprof installs itself in the DefaultServeMux
 	// we create a fresh one for the Git server.
 	serveMux := http.NewServeMux()
-	serveMux.Handle("/", newUpstream(*authBackend, authTransport))
+	serveMux.Handle(*relativeUrlRoot, newUpstream(*authBackend, authTransport))
 	log.Fatal(http.Serve(listener, serveMux))
 }
diff --git a/sendfile.go b/sendfile.go
index 39cc6227ed594..4b77eff94134c 100644
--- a/sendfile.go
+++ b/sendfile.go
@@ -22,8 +22,8 @@ type sendFileResponseWriter struct {
 
 func newSendFileResponseWriter(rw http.ResponseWriter, req *http.Request) *sendFileResponseWriter {
 	s := &sendFileResponseWriter{
-		rw:     rw,
-		req:    req,
+		rw:  rw,
+		req: req,
 	}
 	req.Header.Set("X-Sendfile-Type", "X-Sendfile")
 	return s
diff --git a/servefile.go b/servefile.go
index bd7998575d819..497bb8441c2c1 100644
--- a/servefile.go
+++ b/servefile.go
@@ -16,7 +16,7 @@ func handleServeFile(rootDir string, notFoundHandler serviceHandleFunc) serviceH
 	}
 
 	return func(w http.ResponseWriter, r *gitRequest) {
-		file := filepath.Join(rootDir, r.URL.Path)
+		file := filepath.Join(rootDir, r.relativeUriPath)
 		file, err := filepath.Abs(file)
 		if err != nil {
 			fail500(w, fmt.Errorf("invalid path:"+file, err))
diff --git a/upstream.go b/upstream.go
index ebc3681566e67..6a4b03feb98d0 100644
--- a/upstream.go
+++ b/upstream.go
@@ -11,6 +11,7 @@ import (
 	"net/http"
 	"net/http/httputil"
 	"net/url"
+	"strings"
 )
 
 type serviceHandleFunc func(w http.ResponseWriter, r *gitRequest)
@@ -53,6 +54,7 @@ type authorizationResponse struct {
 // GitLab Rails application.
 type gitRequest struct {
 	*http.Request
+	relativeUriPath string
 	authorizationResponse
 	u *upstream
 }
@@ -78,6 +80,9 @@ func (u *upstream) ServeHTTP(ow http.ResponseWriter, r *http.Request) {
 	w := newLoggingResponseWriter(ow)
 	defer w.Log(r)
 
+	// Strip prefix and add "/"
+	relativeUriPath := "/" + strings.TrimPrefix(r.RequestURI, *relativeUrlRoot)
+
 	// Look for a matching Git service
 	foundService := false
 	for _, g = range httpRoutes {
@@ -85,7 +90,7 @@ func (u *upstream) ServeHTTP(ow http.ResponseWriter, r *http.Request) {
 			continue
 		}
 
-		if g.regex == nil || g.regex.MatchString(r.URL.Path) {
+		if g.regex == nil || g.regex.MatchString(relativeUriPath) {
 			foundService = true
 			break
 		}
@@ -98,8 +103,9 @@ func (u *upstream) ServeHTTP(ow http.ResponseWriter, r *http.Request) {
 	}
 
 	request := gitRequest{
-		Request: r,
-		u:       u,
+		Request:         r,
+		relativeUriPath: relativeUriPath,
+		u:               u,
 	}
 
 	g.handleFunc(w, &request)
-- 
GitLab