22
// A Dir implements http.FileSystem using the native file
23
// system restricted to a specific directory tree.
26
func (d Dir) Open(name string) (File, os.Error) {
27
if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 {
28
return nil, os.NewError("http: invalid character in file path")
30
f, err := os.Open(filepath.Join(string(d), filepath.FromSlash(path.Clean("/"+name))))
37
// A FileSystem implements access to a collection of named files.
38
// The elements in a file path are separated by slash ('/', U+002F)
39
// characters, regardless of host operating system convention.
40
type FileSystem interface {
41
Open(name string) (File, os.Error)
44
// A File is returned by a FileSystem's Open method and can be
45
// served by the FileServer implementation.
48
Stat() (*os.FileInfo, os.Error)
49
Readdir(count int) ([]os.FileInfo, os.Error)
50
Read([]byte) (int, os.Error)
51
Seek(offset int64, whence int) (int64, os.Error)
21
54
// Heuristic: b is text if it is valid UTF-8 and doesn't
22
55
// contain any unprintable ASCII or Unicode characters.
23
56
func isText(b []byte) bool {
47
func dirList(w ResponseWriter, f *os.File) {
80
func dirList(w ResponseWriter, f File) {
48
81
fmt.Fprintf(w, "<pre>\n")
50
83
dirs, err := f.Readdir(100)
63
96
fmt.Fprintf(w, "</pre>\n")
66
func serveFile(w ResponseWriter, r *Request, name string, redirect bool) {
99
// name is '/'-separated, not filepath.Separator.
100
func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirect bool) {
67
101
const indexPage = "/index.html"
69
103
// redirect .../index.html to .../
113
147
// use contents of index.html for directory, if present
114
148
if d.IsDirectory() {
115
149
index := name + filepath.FromSlash(indexPage)
116
ff, err := os.Open(index)
150
ff, err := fs.Open(index)
119
153
dd, err := ff.Stat()
157
191
// TODO(adg): handle multiple ranges
158
192
ranges, err := parseRange(r.Header.Get("Range"), size)
159
193
if err == nil && len(ranges) > 1 {
160
err = os.ErrorString("multiple ranges not supported")
194
err = os.NewError("multiple ranges not supported")
163
197
Error(w, err.String(), StatusRequestedRangeNotSatisfiable)
189
223
// ServeFile replies to the request with the contents of the named file or directory.
190
224
func ServeFile(w ResponseWriter, r *Request, name string) {
191
serveFile(w, r, name, false)
225
serveFile(w, r, Dir(name), "", false)
194
228
type fileHandler struct {
199
232
// FileServer returns a handler that serves HTTP requests
200
233
// with the contents of the file system rooted at root.
201
// It strips prefix from the incoming requests before
202
// looking up the file name in the file system.
203
func FileServer(root, prefix string) Handler { return &fileHandler{root, prefix} }
235
// To use the operating system's file system implementation,
238
// http.Handle("/", http.FileServer(http.Dir("/tmp")))
239
func FileServer(root FileSystem) Handler {
240
return &fileHandler{root}
205
243
func (f *fileHandler) ServeHTTP(w ResponseWriter, r *Request) {
207
if !strings.HasPrefix(path, f.prefix) {
211
path = path[len(f.prefix):]
212
serveFile(w, r, filepath.Join(f.root, filepath.FromSlash(path)), true)
244
serveFile(w, r, f.root, path.Clean(r.URL.Path), true)
215
247
// httpRange specifies the byte range to be sent to the client.
227
259
return nil, os.NewError("invalid range")
229
261
var ranges []httpRange
230
for _, ra := range strings.Split(s[len(b):], ",", -1) {
262
for _, ra := range strings.Split(s[len(b):], ",") {
231
263
i := strings.Index(ra, "-")
233
265
return nil, os.NewError("invalid range")