source: code/trunk/partage.go@ 4

Last change on this file since 4 was 4, checked in by dev, 4 years ago

Prevent writing more data than expected

File size: 2.7 KB
Line 
1package main
2
3import (
4 "fmt"
5 "io"
6 "io/ioutil"
7 "net/http"
8 "os"
9 "path"
10 "path/filepath"
11)
12
13var conf struct {
14 bind string
15 filepath string
16 rootdir string
17 baseuri string
18 filectx string
19 maxsize int64
20}
21
22func contenttype(f *os.File) string {
23 buffer := make([]byte, 512)
24
25 _, err := f.Read(buffer)
26 if err != nil {
27 return ""
28 }
29
30 mime := http.DetectContentType(buffer)
31
32 return mime
33}
34
35func writefile(f *os.File, s io.ReadCloser) int64 {
36 buffer := make([]byte, 4096)
37 eof := false
38 sz := int64(0)
39
40 defer f.Sync()
41
42 for !eof {
43 n, err := s.Read(buffer)
44 if err != nil && err != io.EOF {
45 fmt.Println(err)
46 return -1
47 } else if err == io.EOF {
48 eof = true
49 }
50
51 /* ensure we don't write more than expected */
52 r := int64(n)
53 if sz+r > conf.maxsize {
54 r = conf.maxsize - sz
55 eof = true
56 }
57
58 _, err = f.Write(buffer[:r])
59 if err != nil {
60 fmt.Println(err)
61 }
62 sz += r
63 }
64
65 return sz
66}
67
68func servefile(f *os.File, w http.ResponseWriter) {
69 buffer := make([]byte, 4096)
70
71 mime := contenttype(f)
72 w.Header().Set("Content-Type", mime)
73
74 f.Seek(0, 0)
75 for {
76 n, err := f.Read(buffer)
77
78 if err != nil {
79 if err == io.EOF {
80 _, err := w.Write(buffer[:n])
81 if err != nil {
82 fmt.Println(err)
83 }
84 break
85 }
86 fmt.Println(err)
87 return
88 }
89
90 _, err = w.Write(buffer[:n])
91 if err != nil {
92 fmt.Println(err)
93 }
94 }
95}
96
97func parse(w http.ResponseWriter, r *http.Request) {
98
99 fmt.Printf("%s %s\n", r.Method, r.URL.Path)
100
101 // Max 15 Gb uploads
102 if r.ContentLength > conf.maxsize {
103 w.WriteHeader(http.StatusRequestEntityTooLarge)
104 w.Write([]byte("File is too big"))
105 }
106
107 err := r.ParseForm()
108 if err != nil {
109 fmt.Printf("%s %s: %s", r.Method, r.URL.Path, err)
110 }
111
112 switch r.Method {
113 case "PUT":
114 tmp, _ := ioutil.TempFile(conf.filepath, "*"+path.Ext(r.URL.Path))
115 f, err := os.Create(tmp.Name())
116 if err != nil {
117 fmt.Println(err)
118 return
119 }
120 defer f.Close()
121
122 if writefile(f, r.Body) < 0 {
123 w.WriteHeader(http.StatusInternalServerError)
124 return
125 }
126
127 resp := conf.baseuri + conf.filectx + filepath.Base(tmp.Name())
128 w.Write([]byte(resp))
129
130 case "GET":
131 // r.URL.Path is sanitized regarding "." and ".."
132 filename := r.URL.Path
133 if r.URL.Path == "/" {
134 filename = "/index.html"
135 }
136
137 f, err := os.Open(conf.rootdir + filename)
138 if err != nil {
139 w.WriteHeader(http.StatusNotFound)
140 fmt.Println(err)
141 return
142 }
143 defer f.Close()
144
145 servefile(f, w)
146 }
147}
148
149func main() {
150 conf.bind = "0.0.0.0:8080"
151 conf.maxsize = 28 * 1024 * 1024
152 conf.filepath = "/tmp"
153 conf.rootdir = "./static"
154 conf.baseuri = "http://192.168.0.3:8080"
155 conf.filectx = "/f/"
156
157 http.HandleFunc("/", parse)
158 http.Handle(conf.filectx, http.StripPrefix(conf.filectx, http.FileServer(http.Dir(conf.filepath))))
159 http.ListenAndServe("0.0.0.0:8080", nil)
160}
Note: See TracBrowser for help on using the repository browser.