source: code/trunk/partage.go@ 14

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

Replace servefile() with built-in http.ServeFile()

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