source: code/trunk/partage.go@ 12

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

Print a report page when uploading files from a form

File size: 4.4 KB
Line 
1package main
2
3import (
4 "fmt"
5 "io"
6 "io/ioutil"
7 "net/http"
8 "os"
9 "path"
10 "path/filepath"
11 "html/template"
12
13 "github.com/dustin/go-humanize"
14)
15
16type templatedata struct {
17 Links []string
18 Size string
19 Maxsize string
20}
21
22var conf struct {
23 bind string
24 baseuri string
25 filepath string
26 rootdir string
27 templatedir string
28 filectx string
29 maxsize int64
30}
31
32
33func contenttype(f *os.File) string {
34 buffer := make([]byte, 512)
35
36 _, err := f.Read(buffer)
37 if err != nil {
38 return ""
39 }
40
41 mime := http.DetectContentType(buffer)
42
43 return mime
44}
45
46func writefile(f *os.File, s io.ReadCloser, contentlength int64) int64 {
47 buffer := make([]byte, 4096)
48 eof := false
49 sz := int64(0)
50
51 defer f.Sync()
52
53 for !eof {
54 n, err := s.Read(buffer)
55 if err != nil && err != io.EOF {
56 fmt.Println(err)
57 return -1
58 } else if err == io.EOF {
59 eof = true
60 }
61
62 /* ensure we don't write more than expected */
63 r := int64(n)
64 if sz+r > contentlength {
65 r = contentlength - sz
66 eof = true
67 }
68
69 _, err = f.Write(buffer[:r])
70 if err != nil {
71 fmt.Println(err)
72 }
73 sz += r
74 }
75
76 return sz
77}
78
79func servefile(f *os.File, w http.ResponseWriter) {
80 buffer := make([]byte, 4096)
81
82 mime := contenttype(f)
83 w.Header().Set("Content-Type", mime)
84
85 f.Seek(0, 0)
86 for {
87 n, err := f.Read(buffer)
88
89 if err != nil {
90 if err == io.EOF {
91 if _, err := w.Write(buffer[:n]); err != nil {
92 fmt.Println(err)
93 }
94 break
95 }
96 fmt.Println(err)
97 return
98 }
99
100 if _, err = w.Write(buffer[:n]); err != nil {
101 fmt.Println(err)
102 }
103 }
104}
105
106func servetemplate(w http.ResponseWriter, f string, d templatedata) {
107 t, err := template.ParseFiles(conf.templatedir + "/" + f)
108 if err != nil {
109 w.WriteHeader(http.StatusInternalServerError)
110 return
111 }
112
113 err = t.Execute(w, d)
114 if err != nil {
115 fmt.Println(err)
116 }
117}
118
119func uploaderPut(w http.ResponseWriter, r *http.Request) {
120 /* limit upload size */
121 if r.ContentLength > conf.maxsize {
122 w.WriteHeader(http.StatusRequestEntityTooLarge)
123 w.Write([]byte("File is too big"))
124 }
125
126 tmp, _ := ioutil.TempFile(conf.filepath, "*"+path.Ext(r.URL.Path))
127 f, err := os.Create(tmp.Name())
128 if err != nil {
129 fmt.Println(err)
130 return
131 }
132 defer f.Close()
133
134 if writefile(f, r.Body, r.ContentLength) < 0 {
135 w.WriteHeader(http.StatusInternalServerError)
136 return
137 }
138
139 resp := conf.baseuri + conf.filectx + filepath.Base(tmp.Name())
140 w.Write([]byte(resp))
141}
142
143func uploaderPost(w http.ResponseWriter, r *http.Request) {
144 /* read 32Mb at a time */
145 r.ParseMultipartForm(32 << 20)
146
147 links := []string{}
148 for _, h := range r.MultipartForm.File["uck"] {
149 if h.Size > conf.maxsize {
150 w.WriteHeader(http.StatusRequestEntityTooLarge)
151 w.Write([]byte("File is too big"))
152 return
153 }
154
155 post, err := h.Open()
156 if err != nil {
157 w.WriteHeader(http.StatusInternalServerError)
158 return
159 }
160 defer post.Close()
161
162 tmp, _ := ioutil.TempFile(conf.filepath, "*"+path.Ext(h.Filename))
163 f, err := os.Create(tmp.Name())
164 if err != nil {
165 w.WriteHeader(http.StatusInternalServerError)
166 return
167 }
168 defer f.Close()
169
170 if writefile(f, post, h.Size) < 0 {
171 w.WriteHeader(http.StatusInternalServerError)
172 return
173 }
174
175 link := conf.baseuri + conf.filectx + filepath.Base(tmp.Name())
176 links = append(links, link)
177 }
178
179 if (r.PostFormValue("output") == "html") {
180 data := templatedata{ Links: links }
181 servetemplate(w, "/upload.html", data)
182 return
183 } else {
184 for _, link := range links {
185 w.Write([]byte(link + "\r\n"))
186 }
187 }
188}
189
190func uploaderGet(w http.ResponseWriter, r *http.Request) {
191 // r.URL.Path is sanitized regarding "." and ".."
192 filename := r.URL.Path
193 if r.URL.Path == "/" || r.URL.Path == "/index" {
194 data := templatedata{ Maxsize: humanize.IBytes(uint64(conf.maxsize))}
195 servetemplate(w, "/index.html", data)
196 return
197 }
198
199 f, err := os.Open(conf.rootdir + filename)
200 if err != nil {
201 w.WriteHeader(http.StatusNotFound)
202 fmt.Println(err)
203 return
204 }
205 defer f.Close()
206
207 servefile(f, w)
208}
209
210func uploader(w http.ResponseWriter, r *http.Request) {
211 switch r.Method {
212 case "POST":
213 uploaderPost(w, r)
214 case "PUT":
215 uploaderPut(w, r)
216 case "GET":
217 uploaderGet(w, r)
218 }
219}
220
221func main() {
222 conf.bind = "0.0.0.0:8080"
223 conf.maxsize = 30064771072 // 28Gib
224 conf.filepath = "/tmp"
225 conf.rootdir = "./static"
226 conf.baseuri = "http://192.168.0.3:8080"
227 conf.filectx = "/f/"
228 conf.templatedir = "./templates"
229
230 http.HandleFunc("/", uploader)
231 http.Handle(conf.filectx, http.StripPrefix(conf.filectx, http.FileServer(http.Dir(conf.filepath))))
232 http.ListenAndServe("0.0.0.0:8080", nil)
233}
Note: See TracBrowser for help on using the repository browser.