Commit d89b378e authored by Jacob Vosmaer's avatar Jacob Vosmaer

Create internal/staticpages package

parent beb6dfe7
package upstream package staticpages
import ( import (
"../helper" "../helper"
...@@ -7,10 +7,10 @@ import ( ...@@ -7,10 +7,10 @@ import (
"path/filepath" "path/filepath"
) )
func handleDeployPage(documentRoot string, handler http.Handler) http.HandlerFunc { func (s *Static) DeployPage(handler http.Handler) http.Handler {
deployPage := filepath.Join(documentRoot, "index.html") deployPage := filepath.Join(s.DocumentRoot, "index.html")
return func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
data, err := ioutil.ReadFile(deployPage) data, err := ioutil.ReadFile(deployPage)
if err != nil { if err != nil {
handler.ServeHTTP(w, r) handler.ServeHTTP(w, r)
...@@ -21,5 +21,5 @@ func handleDeployPage(documentRoot string, handler http.Handler) http.HandlerFun ...@@ -21,5 +21,5 @@ func handleDeployPage(documentRoot string, handler http.Handler) http.HandlerFun
w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
w.Write(data) w.Write(data)
} })
} }
package upstream package staticpages
import ( import (
"../helper" "../helper"
...@@ -20,9 +20,10 @@ func TestIfNoDeployPageExist(t *testing.T) { ...@@ -20,9 +20,10 @@ func TestIfNoDeployPageExist(t *testing.T) {
w := httptest.NewRecorder() w := httptest.NewRecorder()
executed := false executed := false
handleDeployPage(dir, http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) { st := &Static{dir}
st.DeployPage(http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {
executed = true executed = true
}))(w, nil) })).ServeHTTP(w, nil)
if !executed { if !executed {
t.Error("The handler should get executed") t.Error("The handler should get executed")
} }
...@@ -41,9 +42,10 @@ func TestIfDeployPageExist(t *testing.T) { ...@@ -41,9 +42,10 @@ func TestIfDeployPageExist(t *testing.T) {
w := httptest.NewRecorder() w := httptest.NewRecorder()
executed := false executed := false
handleDeployPage(dir, http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) { st := &Static{dir}
st.DeployPage(http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {
executed = true executed = true
}))(w, nil) })).ServeHTTP(w, nil)
if executed { if executed {
t.Error("The handler should not get executed") t.Error("The handler should not get executed")
} }
......
package errorpage package staticpages
import ( import (
"../helper" "../helper"
...@@ -60,13 +60,13 @@ func (s *errorPageResponseWriter) Flush() { ...@@ -60,13 +60,13 @@ func (s *errorPageResponseWriter) Flush() {
s.WriteHeader(http.StatusOK) s.WriteHeader(http.StatusOK)
} }
func Inject(documentRoot string, handler http.Handler) http.HandlerFunc { func (st *Static) ErrorPages(handler http.Handler) http.Handler {
return func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
rw := errorPageResponseWriter{ rw := errorPageResponseWriter{
rw: w, rw: w,
path: documentRoot, path: st.DocumentRoot,
} }
defer rw.Flush() defer rw.Flush()
handler.ServeHTTP(&rw, r) handler.ServeHTTP(&rw, r)
} })
} }
package errorpage package staticpages
import ( import (
"../helper" "../helper"
...@@ -26,7 +26,8 @@ func TestIfErrorPageIsPresented(t *testing.T) { ...@@ -26,7 +26,8 @@ func TestIfErrorPageIsPresented(t *testing.T) {
w.WriteHeader(404) w.WriteHeader(404)
fmt.Fprint(w, "Not Found") fmt.Fprint(w, "Not Found")
}) })
Inject(dir, h)(w, nil) st := &Static{dir}
st.ErrorPages(h).ServeHTTP(w, nil)
w.Flush() w.Flush()
helper.AssertResponseCode(t, w, 404) helper.AssertResponseCode(t, w, 404)
...@@ -46,7 +47,8 @@ func TestIfErrorPassedIfNoErrorPageIsFound(t *testing.T) { ...@@ -46,7 +47,8 @@ func TestIfErrorPassedIfNoErrorPageIsFound(t *testing.T) {
w.WriteHeader(404) w.WriteHeader(404)
fmt.Fprint(w, errorResponse) fmt.Fprint(w, errorResponse)
}) })
Inject(dir, h)(w, nil) st := &Static{dir}
st.ErrorPages(h).ServeHTTP(w, nil)
w.Flush() w.Flush()
helper.AssertResponseCode(t, w, 404) helper.AssertResponseCode(t, w, 404)
......
package upstream package staticpages
import ( import (
"../helper" "../helper"
"../urlprefix"
"log" "log"
"net/http" "net/http"
"os" "os"
...@@ -17,12 +18,12 @@ const ( ...@@ -17,12 +18,12 @@ const (
CacheExpireMax CacheExpireMax
) )
func handleServeFile(documentRoot string, prefix urlPrefix, cache CacheMode, notFoundHandler http.Handler) http.Handler { func (s *Static) ServeExisting(prefix urlprefix.Prefix, cache CacheMode, notFoundHandler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
file := filepath.Join(documentRoot, prefix.strip(r.URL.Path)) file := filepath.Join(s.DocumentRoot, prefix.Strip(r.URL.Path))
// The filepath.Join does Clean traversing directories up // The filepath.Join does Clean traversing directories up
if !strings.HasPrefix(file, documentRoot) { if !strings.HasPrefix(file, s.DocumentRoot) {
helper.Fail500(w, &os.PathError{ helper.Fail500(w, &os.PathError{
Op: "open", Op: "open",
Path: file, Path: file,
......
package upstream package staticpages
import ( import (
"../helper" "../helper"
...@@ -17,7 +17,8 @@ func TestServingNonExistingFile(t *testing.T) { ...@@ -17,7 +17,8 @@ func TestServingNonExistingFile(t *testing.T) {
httpRequest, _ := http.NewRequest("GET", "/file", nil) httpRequest, _ := http.NewRequest("GET", "/file", nil)
w := httptest.NewRecorder() w := httptest.NewRecorder()
handleServeFile(dir, "/", CacheDisabled, nil).ServeHTTP(w, httpRequest) st := &Static{dir}
st.ServeExisting("/", CacheDisabled, nil).ServeHTTP(w, httpRequest)
helper.AssertResponseCode(t, w, 404) helper.AssertResponseCode(t, w, 404)
} }
...@@ -30,7 +31,8 @@ func TestServingDirectory(t *testing.T) { ...@@ -30,7 +31,8 @@ func TestServingDirectory(t *testing.T) {
httpRequest, _ := http.NewRequest("GET", "/file", nil) httpRequest, _ := http.NewRequest("GET", "/file", nil)
w := httptest.NewRecorder() w := httptest.NewRecorder()
handleServeFile(dir, "/", CacheDisabled, nil).ServeHTTP(w, httpRequest) st := &Static{dir}
st.ServeExisting("/", CacheDisabled, nil).ServeHTTP(w, httpRequest)
helper.AssertResponseCode(t, w, 404) helper.AssertResponseCode(t, w, 404)
} }
...@@ -39,7 +41,8 @@ func TestServingMalformedUri(t *testing.T) { ...@@ -39,7 +41,8 @@ func TestServingMalformedUri(t *testing.T) {
httpRequest, _ := http.NewRequest("GET", "/../../../static/file", nil) httpRequest, _ := http.NewRequest("GET", "/../../../static/file", nil)
w := httptest.NewRecorder() w := httptest.NewRecorder()
handleServeFile(dir, "/", CacheDisabled, nil).ServeHTTP(w, httpRequest) st := &Static{dir}
st.ServeExisting("/", CacheDisabled, nil).ServeHTTP(w, httpRequest)
helper.AssertResponseCode(t, w, 404) helper.AssertResponseCode(t, w, 404)
} }
...@@ -48,7 +51,8 @@ func TestExecutingHandlerWhenNoFileFound(t *testing.T) { ...@@ -48,7 +51,8 @@ func TestExecutingHandlerWhenNoFileFound(t *testing.T) {
httpRequest, _ := http.NewRequest("GET", "/file", nil) httpRequest, _ := http.NewRequest("GET", "/file", nil)
executed := false executed := false
handleServeFile(dir, "/", CacheDisabled, http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) { st := &Static{dir}
st.ServeExisting("/", CacheDisabled, http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) {
executed = (r == httpRequest) executed = (r == httpRequest)
})).ServeHTTP(nil, httpRequest) })).ServeHTTP(nil, httpRequest)
if !executed { if !executed {
...@@ -69,7 +73,8 @@ func TestServingTheActualFile(t *testing.T) { ...@@ -69,7 +73,8 @@ func TestServingTheActualFile(t *testing.T) {
ioutil.WriteFile(filepath.Join(dir, "file"), []byte(fileContent), 0600) ioutil.WriteFile(filepath.Join(dir, "file"), []byte(fileContent), 0600)
w := httptest.NewRecorder() w := httptest.NewRecorder()
handleServeFile(dir, "/", CacheDisabled, nil).ServeHTTP(w, httpRequest) st := &Static{dir}
st.ServeExisting("/", CacheDisabled, nil).ServeHTTP(w, httpRequest)
helper.AssertResponseCode(t, w, 200) helper.AssertResponseCode(t, w, 200)
if w.Body.String() != fileContent { if w.Body.String() != fileContent {
t.Error("We should serve the file: ", w.Body.String()) t.Error("We should serve the file: ", w.Body.String())
...@@ -100,7 +105,8 @@ func testServingThePregzippedFile(t *testing.T, enableGzip bool) { ...@@ -100,7 +105,8 @@ func testServingThePregzippedFile(t *testing.T, enableGzip bool) {
ioutil.WriteFile(filepath.Join(dir, "file"), []byte(fileContent), 0600) ioutil.WriteFile(filepath.Join(dir, "file"), []byte(fileContent), 0600)
w := httptest.NewRecorder() w := httptest.NewRecorder()
handleServeFile(dir, "/", CacheDisabled, nil).ServeHTTP(w, httpRequest) st := &Static{dir}
st.ServeExisting("/", CacheDisabled, nil).ServeHTTP(w, httpRequest)
helper.AssertResponseCode(t, w, 200) helper.AssertResponseCode(t, w, 200)
if enableGzip { if enableGzip {
helper.AssertResponseHeader(t, w, "Content-Encoding", "gzip") helper.AssertResponseHeader(t, w, "Content-Encoding", "gzip")
......
package staticpages
type Static struct {
DocumentRoot string
}
package upstream package upstream
import ( import (
"../errorpage"
"../git" "../git"
"../lfs" "../lfs"
"../staticpages"
"../upload" "../upload"
"net/http" "net/http"
"regexp" "regexp"
...@@ -33,6 +33,7 @@ func (u *Upstream) Routes() []route { ...@@ -33,6 +33,7 @@ func (u *Upstream) Routes() []route {
} }
func (u *Upstream) configureRoutes() { func (u *Upstream) configureRoutes() {
static := &staticpages.Static{u.DocumentRoot}
u.routes = []route{ u.routes = []route{
// Git Clone // Git Clone
route{"GET", regexp.MustCompile(gitProjectPattern + `info/refs\z`), git.GetInfoRefs(u.API())}, route{"GET", regexp.MustCompile(gitProjectPattern + `info/refs\z`), git.GetInfoRefs(u.API())},
...@@ -63,7 +64,7 @@ func (u *Upstream) configureRoutes() { ...@@ -63,7 +64,7 @@ func (u *Upstream) configureRoutes() {
// Serve assets // Serve assets
route{"", regexp.MustCompile(`^/assets/`), route{"", regexp.MustCompile(`^/assets/`),
handleServeFile(u.DocumentRoot, u.URLPrefix(), CacheExpireMax, static.ServeExisting(u.URLPrefix(), staticpages.CacheExpireMax,
NotFoundUnless(u.DevelopmentMode, NotFoundUnless(u.DevelopmentMode,
u.Proxy(), u.Proxy(),
), ),
...@@ -72,9 +73,9 @@ func (u *Upstream) configureRoutes() { ...@@ -72,9 +73,9 @@ func (u *Upstream) configureRoutes() {
// Serve static files or forward the requests // Serve static files or forward the requests
route{"", nil, route{"", nil,
handleServeFile(u.DocumentRoot, u.URLPrefix(), CacheDisabled, static.ServeExisting(u.URLPrefix(), staticpages.CacheDisabled,
handleDeployPage(u.DocumentRoot, static.DeployPage(
errorpage.Inject(u.DocumentRoot, static.ErrorPages(
u.Proxy(), u.Proxy(),
), ),
), ),
......
...@@ -10,10 +10,12 @@ import ( ...@@ -10,10 +10,12 @@ import (
"../api" "../api"
"../helper" "../helper"
"../proxy" "../proxy"
"../staticpages"
"../urlprefix"
"fmt" "fmt"
"net/http" "net/http"
"net/url" "net/url"
"path" "strings"
"sync" "sync"
"time" "time"
) )
...@@ -34,7 +36,7 @@ type Upstream struct { ...@@ -34,7 +36,7 @@ type Upstream struct {
_proxy *proxy.Proxy _proxy *proxy.Proxy
configureProxyOnce sync.Once configureProxyOnce sync.Once
urlPrefix urlPrefix urlPrefix urlprefix.Prefix
configureURLPrefixOnce sync.Once configureURLPrefixOnce sync.Once
routes []route routes []route
...@@ -42,6 +44,9 @@ type Upstream struct { ...@@ -42,6 +44,9 @@ type Upstream struct {
transport http.RoundTripper transport http.RoundTripper
configureTransportOnce sync.Once configureTransportOnce sync.Once
_static *staticpages.Static
configureStaticOnce sync.Once
} }
func (u *Upstream) Proxy() *proxy.Proxy { func (u *Upstream) Proxy() *proxy.Proxy {
...@@ -66,6 +71,29 @@ func (u *Upstream) configureAPI() { ...@@ -66,6 +71,29 @@ func (u *Upstream) configureAPI() {
} }
} }
func (u *Upstream) URLPrefix() urlprefix.Prefix {
u.configureURLPrefixOnce.Do(u.configureURLPrefix)
return u.urlPrefix
}
func (u *Upstream) configureURLPrefix() {
if u.Backend == nil {
u.Backend = DefaultBackend
}
relativeURLRoot := u.Backend.Path
if !strings.HasSuffix(relativeURLRoot, "/") {
relativeURLRoot += "/"
}
u.urlPrefix = urlprefix.Prefix(relativeURLRoot)
}
// func (u *Upstream) Static() *static.Static {
// u.configureStaticOnce.Do(func() {
// u._static = &static.Static{u.DocumentRoot}
// })
// return u._static
// }
func (u *Upstream) ServeHTTP(ow http.ResponseWriter, r *http.Request) { func (u *Upstream) ServeHTTP(ow http.ResponseWriter, r *http.Request) {
w := newLoggingResponseWriter(ow) w := newLoggingResponseWriter(ow)
defer w.Log(r) defer w.Log(r)
...@@ -83,9 +111,9 @@ func (u *Upstream) ServeHTTP(ow http.ResponseWriter, r *http.Request) { ...@@ -83,9 +111,9 @@ func (u *Upstream) ServeHTTP(ow http.ResponseWriter, r *http.Request) {
} }
// Check URL Root // Check URL Root
URIPath := cleanURIPath(r.URL.Path) URIPath := urlprefix.CleanURIPath(r.URL.Path)
prefix := u.URLPrefix() prefix := u.URLPrefix()
if !prefix.match(URIPath) { if !prefix.Match(URIPath) {
httpError(&w, r, fmt.Sprintf("Not found %q", URIPath), http.StatusNotFound) httpError(&w, r, fmt.Sprintf("Not found %q", URIPath), http.StatusNotFound)
return return
} }
...@@ -98,7 +126,7 @@ func (u *Upstream) ServeHTTP(ow http.ResponseWriter, r *http.Request) { ...@@ -98,7 +126,7 @@ func (u *Upstream) ServeHTTP(ow http.ResponseWriter, r *http.Request) {
continue continue
} }
if ro.regex == nil || ro.regex.MatchString(prefix.strip(URIPath)) { if ro.regex == nil || ro.regex.MatchString(prefix.Strip(URIPath)) {
foundService = true foundService = true
break break
} }
...@@ -121,21 +149,3 @@ func httpError(w http.ResponseWriter, r *http.Request, error string, code int) { ...@@ -121,21 +149,3 @@ func httpError(w http.ResponseWriter, r *http.Request, error string, code int) {
http.Error(w, error, code) http.Error(w, error, code)
} }
// Borrowed from: net/http/server.go
// Return the canonical path for p, eliminating . and .. elements.
func cleanURIPath(p string) string {
if p == "" {
return "/"
}
if p[0] != '/' {
p = "/" + p
}
np := path.Clean(p)
// path.Clean removes trailing slash except for root;
// put the trailing slash back if necessary.
if p[len(p)-1] == '/' && np != "/" {
np += "/"
}
return np
}
package upstream
import (
"strings"
)
type urlPrefix string
func (p urlPrefix) strip(path string) string {
return cleanURIPath(strings.TrimPrefix(path, string(p)))
}
func (p urlPrefix) match(path string) bool {
pre := string(p)
return strings.HasPrefix(path, pre) || path+"/" == pre
}
func (u *Upstream) URLPrefix() urlPrefix {
u.configureURLPrefixOnce.Do(u.configureURLPrefix)
return u.urlPrefix
}
func (u *Upstream) configureURLPrefix() {
if u.Backend == nil {
u.Backend = DefaultBackend
}
relativeURLRoot := u.Backend.Path
if !strings.HasSuffix(relativeURLRoot, "/") {
relativeURLRoot += "/"
}
u.urlPrefix = urlPrefix(relativeURLRoot)
}
package urlprefix
import (
"path"
"strings"
)
type Prefix string
func (p Prefix) Strip(path string) string {
return CleanURIPath(strings.TrimPrefix(path, string(p)))
}
func (p Prefix) Match(path string) bool {
pre := string(p)
return strings.HasPrefix(path, pre) || path+"/" == pre
}
// Borrowed from: net/http/server.go
// Return the canonical path for p, eliminating . and .. elements.
func CleanURIPath(p string) string {
if p == "" {
return "/"
}
if p[0] != '/' {
p = "/" + p
}
np := path.Clean(p)
// path.Clean removes trailing slash except for root;
// put the trailing slash back if necessary.
if p[len(p)-1] == '/' && np != "/" {
np += "/"
}
return np
}
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