From 77c172b823b64ebface655681ab0749b9d2f7081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Benencia?= Date: Fri, 13 Apr 2018 16:30:31 -0700 Subject: First public commit --- internal/handlers/static.go | 127 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 internal/handlers/static.go (limited to 'internal/handlers/static.go') diff --git a/internal/handlers/static.go b/internal/handlers/static.go new file mode 100644 index 0000000..b27fa1a --- /dev/null +++ b/internal/handlers/static.go @@ -0,0 +1,127 @@ +// Copyright 2018 ThousandEyes Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package handlers + +import ( + "fmt" + "io/ioutil" + "net/http" + "os" + "path" + "path/filepath" + "sort" +) + +// StaticConfigFileHandler handles static config files +type StaticConfigFileHandler struct{} + +func (s *StaticConfigFileHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + env := envFromRequest(r) + envName := envNameFromRequest(r) + basePath := path.Join(env.DataDir, "static") + if envName == "" { + http.FileServer(http.Dir(basePath)).ServeHTTP(w, r) + return + } + envPath := filepath.Join(env.DataDir, env.EnvDir, envName, "static") + OverlayFileServer(envPath, basePath).ServeHTTP(w, r) +} + +// StaticConfigFileServer returns a StaticConfigFileHandler instance implementing http.Handler +func StaticConfigFileServer() *StaticConfigFileHandler { + return &StaticConfigFileHandler{} +} + +// OverlayFileServerHandler handles request for overlayer directories +type OverlayFileServerHandler struct { + upper string + lower string +} + +// OverlayFileServer serves static content from two overlayed directories +func OverlayFileServer(upper, lower string) *OverlayFileServerHandler { + return &OverlayFileServerHandler{ + upper: upper, + lower: lower, + } +} + +func (o *OverlayFileServerHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + + fp := filepath.Clean(r.URL.Path) + upper := filepath.Clean(path.Join(o.upper, fp)) + lower := filepath.Clean(path.Join(o.lower, fp)) + + // TODO: try to avoid stat()-ing both if not necessary + infoUpper, errUpper := os.Stat(upper) + infoLower, errLower := os.Stat(lower) + + // If both upper and lower files/dirs do not exist, return 404 + if errUpper != nil && os.IsNotExist(errUpper) && + errLower != nil && os.IsNotExist(errLower) { + http.NotFound(w, r) + return + } + + isDir := false + fileList := make(map[string]os.FileInfo) + + if errUpper == nil && infoUpper.IsDir() { + files, _ := ioutil.ReadDir(upper) + for _, f := range files { + fileList[f.Name()] = f + } + isDir = true + } + if errLower == nil && infoLower.IsDir() { + files, _ := ioutil.ReadDir(lower) + for _, f := range files { + if _, ok := fileList[f.Name()]; !ok { + fileList[f.Name()] = f + } + } + isDir = true + } + + // Generate HTML directory index + if isDir { + fileListIndex := []string{} + for i := range fileList { + fileListIndex = append(fileListIndex, i) + } + sort.Strings(fileListIndex) + w.Write([]byte("
\n"))
+		for _, i := range fileListIndex {
+			f := fileList[i]
+			name := f.Name()
+			if f.IsDir() {
+				name = name + "/"
+			}
+			l := fmt.Sprintf("%s\n", name, name)
+			w.Write([]byte(l))
+		}
+		w.Write([]byte("
\n")) + return + } + + // Serve the file from the upper layer if it exists. + if errUpper == nil { + http.ServeFile(w, r, upper) + // If not serve it from the lower + } else if errLower == nil { + http.ServeFile(w, r, lower) + } + http.NotFound(w, r) +} -- cgit v1.2.3