github.com/kaleido-io/firefly@v0.0.0-20210622132723-8b4b6aacb971/internal/apiserver/static.go (about) 1 // Copyright © 2021 Kaleido, Inc. 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 17 package apiserver 18 19 import ( 20 "encoding/json" 21 "net/http" 22 "os" 23 "path/filepath" 24 "strings" 25 26 "github.com/kaleido-io/firefly/internal/i18n" 27 "github.com/kaleido-io/firefly/internal/log" 28 "github.com/kaleido-io/firefly/pkg/fftypes" 29 ) 30 31 type staticHandler struct { 32 staticPath string 33 indexPath string 34 urlPrefix string 35 os osInterface 36 } 37 38 func newStaticHandler(staticPath, indexPath, urlPrefix string) *staticHandler { 39 return &staticHandler{ 40 staticPath: staticPath, 41 indexPath: indexPath, 42 urlPrefix: urlPrefix, 43 os: &realOS{}, 44 } 45 } 46 47 func (h staticHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 48 path, err := filepath.Rel(h.urlPrefix, r.URL.Path) 49 if err != nil { 50 // if we failed to get the path respond with a 404 51 http.Error(w, err.Error(), http.StatusNotFound) 52 return 53 } 54 55 // prepend the path with the path to the static directory 56 path = filepath.Join(h.staticPath, strings.ReplaceAll(path, "..", "_"), "/") 57 58 // check whether a file exists at the given path 59 _, err = h.os.Stat(path) 60 if os.IsNotExist(err) { 61 // file does not exist, serve index.html 62 http.ServeFile(w, r, filepath.Join(h.staticPath, h.indexPath)) 63 return 64 } else if err != nil { 65 // if we got an error (that wasn't that the file doesn't exist) stating the 66 // file, return a 500 internal server error and stop 67 log.L(r.Context()).Errorf("Failed to serve file: %s", err) 68 w.WriteHeader(500) 69 _ = json.NewEncoder(w).Encode(&fftypes.RESTError{ 70 Error: i18n.ExpandWithCode(r.Context(), i18n.MsgAPIServerStaticFail), 71 }) 72 return 73 } 74 75 // otherwise, use http.FileServer to serve the static dir 76 http.StripPrefix(h.urlPrefix, http.FileServer(http.Dir(h.staticPath))).ServeHTTP(w, r) 77 } 78 79 type osInterface interface { 80 Stat(name string) (os.FileInfo, error) 81 } 82 83 type realOS struct{} 84 85 func (r *realOS) Stat(name string) (os.FileInfo, error) { 86 return os.Stat(name) 87 }