forked from hoisie/web
-
Notifications
You must be signed in to change notification settings - Fork 1
/
servefile.go
71 lines (64 loc) · 1.63 KB
/
servefile.go
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
package web
import (
"io"
"os"
"path"
"utf8"
)
var contentByExt = map[string]string{
".css": "text/css",
".gif": "image/gif",
".html": "text/html; charset=utf-8",
".htm": "text/html; charset=utf-8",
".jpg": "image/jpeg",
".js": "application/x-javascript",
".pdf": "application/pdf",
".png": "image/png",
}
func isText(b []byte) bool {
for len(b) > 0 && utf8.FullRune(b) {
rune, size := utf8.DecodeRune(b)
if size == 1 && rune == utf8.RuneError {
// decoding error
return false
}
if 0x80 <= rune && rune <= 0x9F {
return false
}
if rune < ' ' {
switch rune {
case '\n', '\r', '\t':
// okay
default:
// binary garbage
return false
}
}
b = b[size:]
}
return true
}
func serveFile(ctx *Context, name string) {
f, err := os.Open(name, os.O_RDONLY, 0)
if err != nil {
ctx.Abort(404, "Invalid file")
return
}
defer f.Close()
ext := path.Ext(name)
if ctype, ok := contentByExt[ext]; ok {
ctx.SetHeader("Content-Type", ctype, true)
} else {
// read first chunk to decide between utf-8 text and binary
var buf [1024]byte
n, _ := io.ReadFull(f, &buf)
b := buf[0:n]
if isText(b) {
ctx.SetHeader("Content-Type", "text-plain; charset=utf-8", true)
} else {
ctx.SetHeader("Content-Type", "application/octet-stream", true) // generic binary
}
ctx.Write(b)
}
io.Copy(ctx, f)
}