-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhttpserve.go
More file actions
119 lines (107 loc) · 2.46 KB
/
Copy pathhttpserve.go
File metadata and controls
119 lines (107 loc) · 2.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package main
import (
"errors"
"fmt"
"io"
"net/http"
"os"
"strconv"
"strings"
"time"
)
func RequestLogger(targetMux http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
targetMux.ServeHTTP(w, r)
referer := r.Referer()
if referer == "" {
referer = "-"
}
// Apache combined log format, but since we don't have access to content-length it's the request timing instead
fmt.Printf(
"%s - %s [%s] \"%s %s %s\" %d %v %s \"%s\"\n",
r.RemoteAddr,
"-", // user assumed to be empty because we don't have authentication
start.Format("02/Jan/2006:15:04:05 -0700"),
r.Method,
r.RequestURI,
r.Proto,
200, // we don't have access to the Response, so we assume everything is a 200
time.Since(start),
referer,
r.UserAgent(),
)
})
}
func filterFilename(name string) bool {
parts := strings.Split(name, "/")
for _, part := range parts {
if strings.HasPrefix(part, ".") {
return true
}
}
return false
}
type filteredFilename struct {
http.File
}
func (f filteredFilename) Readdir(n int) (fis []os.FileInfo, err error) {
files, err := f.File.Readdir(n)
for _, file := range files {
if !filterFilename(file.Name()) {
fis = append(fis, file)
}
}
return
}
type filteredFileSystem struct {
http.FileSystem
}
func (fs filteredFileSystem) Open(name string) (http.File, error) {
if filterFilename(name) { // If dot file, return 403 response
return nil, os.ErrPermission
}
file, err := fs.FileSystem.Open(name)
if err != nil {
return nil, err
}
return filteredFilename{file}, err
}
func ServeDirViaHTTP(args []string, _ io.Reader) error {
var directory string
port := "8080"
switch len(args) {
default:
directory = "."
case 2:
ok, err := pathIsDir(args[1])
if err != nil {
return err
}
if ok {
directory = args[1]
} else {
return errors.New(args[1] + " is not a valid directory")
}
case 3:
ok, err := pathIsDir(args[1])
if err != nil {
return err
}
if ok {
directory = args[1]
} else {
return errors.New(args[1] + " is not a valid directory")
}
_, err = strconv.Atoi(args[2])
if err != nil {
return err
}
port = args[2]
}
fs := filteredFileSystem{http.Dir(directory)}
fileHandler := http.FileServer(fs)
http.Handle("/", fileHandler)
fmt.Fprintf(os.Stderr, "Serving %s on http://localhost:%s. Combined log format to stdout:\n", directory, port)
return http.ListenAndServe(":"+port, RequestLogger(fileHandler))
}