blob: 7440e6d1291bd8095f1896a289b86fa326db0ac1 [file] [log] [blame]
// Application that serves up the contents of /tmp/glog via HTTP, giving access
// to logs w/o needing to SSH into the server.
package main
import (
"flag"
"fmt"
"html/template"
"net/http"
"net/url"
"os"
"path"
"sort"
"strings"
"github.com/golang/glog"
)
var port = flag.String("port", ":8001", "HTTP service address (e.g., ':8001')")
// FileServer returns a handler that serves HTTP requests
// with the contents of the file system rooted at root.
//
// To use the operating system's file system implementation,
// use http.Dir:
//
// http.Handle("/", FileServer(http.Dir("/tmp")))
//
// Differs from net/http FileServer by making directory listings better.
func FileServer(root http.FileSystem) http.Handler {
return &fileHandler{root}
}
type fileHandler struct {
root http.FileSystem
}
func (f *fileHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
upath := r.URL.Path
if !strings.HasPrefix(upath, "/") {
upath = "/" + upath
r.URL.Path = upath
}
serveFile(w, r, f.root, path.Clean(upath))
}
// FileInfoSlice is for sorting.
type FileInfoSlice []os.FileInfo
func (p FileInfoSlice) Len() int { return len(p) }
func (p FileInfoSlice) Less(i, j int) bool { return p[i].Name() < p[j].Name() }
func (p FileInfoSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func dirList(w http.ResponseWriter, f http.File) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
fmt.Fprintf(w, "<pre>\n")
for {
dirs, err := f.Readdir(10000)
sort.Sort(FileInfoSlice(dirs))
if err != nil || len(dirs) == 0 {
break
}
for _, d := range dirs {
name := d.Name()
if d.IsDir() {
name += "/"
}
url := url.URL{Path: name}
fmt.Fprintf(w, "%s <a href=\"%s\">%s</a>\n", d.ModTime(), url.String(), template.HTMLEscapeString(name))
}
}
fmt.Fprintf(w, "</pre>\n")
}
func serveFile(w http.ResponseWriter, r *http.Request, fs http.FileSystem, name string) {
f, err := fs.Open(name)
if err != nil {
http.NotFound(w, r)
return
}
defer f.Close()
d, err1 := f.Stat()
if err1 != nil {
http.NotFound(w, r)
return
}
url := r.URL.Path
if d.IsDir() {
if url[len(url)-1] != '/' {
w.Header().Set("Location", path.Base(url)+"/")
w.WriteHeader(http.StatusMovedPermanently)
return
}
}
if d.IsDir() {
dirList(w, f)
return
}
http.ServeContent(w, r, d.Name(), d.ModTime(), f)
}
func main() {
flag.Parse()
http.Handle("/", http.StripPrefix("/", FileServer(http.Dir("/tmp/glog"))))
glog.Fatal(http.ListenAndServe(*port, nil))
}