netboot/pixiecore/ui.go
2016-09-19 03:56:42 -07:00

97 lines
2.6 KiB
Go

// Copyright 2016 Google 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 pixiecore
import (
"bytes"
"html/template"
"io/ioutil"
"mime"
"net/http"
"path/filepath"
"strings"
"time"
"go.universe.tf/netboot/pixiecore/ui"
)
//go:generate go-bindata -o ui/autogen.go -ignore autogen.go -pkg ui -nometadata -nomemcopy -prefix ui/ ui/
const assetsPath = "/_/assets/"
func (s *Server) serveUI(mux *http.ServeMux) {
mux.HandleFunc("/", s.handleUI)
mux.HandleFunc(assetsPath, s.handleUI)
}
func (s *Server) handleUI(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/" {
r.URL.Path = assetsPath + "index.html"
}
if !strings.HasPrefix(r.URL.Path, assetsPath) {
http.NotFound(w, r)
return
}
// Sticking a / in front of the path before cleaning it will strip
// out any "../" attempts at path traversal. Then we remove the
// leading /, and we end up with a path we can filepath.Join or
// fetch from asset data.
path := filepath.Clean("/" + r.URL.Path[len(assetsPath):])[1:]
t, err := s.getTemplate(path)
if err != nil {
s.log("UI", "Failed to parse template for %q: %s", path, err)
http.Error(w, "internal server error", http.StatusInternalServerError)
return
}
var b bytes.Buffer
s.eventsMu.Lock()
defer s.eventsMu.Unlock()
if err = t.Execute(&b, s.events); err != nil {
s.log("UI", "Failed to expand template for %q: %s", path, err)
http.Error(w, "internal server error", http.StatusInternalServerError)
return
}
mimetype := mime.TypeByExtension(filepath.Ext(path))
if mimetype != "" {
w.Header().Set("Content-Type", mimetype)
}
b.WriteTo(w)
}
func (s *Server) getTemplate(name string) (*template.Template, error) {
var (
bs []byte
err error
)
if s.UIAssetsDir != "" {
bs, err = ioutil.ReadFile(filepath.Join(s.UIAssetsDir, name))
} else {
bs, err = ui.Asset(name)
}
if err != nil {
return nil, err
}
funcs := template.FuncMap{
"dec": func(i int) int {
return i - 1
},
"timestamp_millis": func(t time.Time) int64 {
return t.UnixNano() / int64(time.Millisecond)
},
}
return template.New(name).Funcs(funcs).Parse(string(bs))
}