Commit d89b378e authored by Jacob Vosmaer's avatar Jacob Vosmaer

Create internal/staticpages package

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