source: code/trunk/partage.go@ 13

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

Turn all config options into flags

File size: 4.9 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 servefile(f *os.File, w http.ResponseWriter) {
81 buffer := make([]byte, 4096)
82
83 mime := contenttype(f)
84 w.Header().Set("Content-Type", mime)
85
86 f.Seek(0, 0)
87 for {
88 n, err := f.Read(buffer)
89
90 if err != nil {
91 if err == io.EOF {
92 if _, err := w.Write(buffer[:n]); err != nil {
93 fmt.Println(err)
94 }
95 break
96 }
97 fmt.Println(err)
98 return
99 }
100
101 if _, err = w.Write(buffer[:n]); err != nil {
102 fmt.Println(err)
103 }
104 }
105}
106
107func servetemplate(w http.ResponseWriter, f string, d templatedata) {
108 t, err := template.ParseFiles(conf.templatedir + "/" + f)
109 if err != nil {
110 w.WriteHeader(http.StatusInternalServerError)
111 return
112 }
113
114 err = t.Execute(w, d)
115 if err != nil {
116 fmt.Println(err)
117 }
118}
119
120func uploaderPut(w http.ResponseWriter, r *http.Request) {
121 /* limit upload size */
122 if r.ContentLength > conf.maxsize {
123 w.WriteHeader(http.StatusRequestEntityTooLarge)
124 w.Write([]byte("File is too big"))
125 }
126
127 tmp, _ := ioutil.TempFile(conf.filepath, "*"+path.Ext(r.URL.Path))
128 f, err := os.Create(tmp.Name())
129 if err != nil {
130 fmt.Println(err)
131 return
132 }
133 defer f.Close()
134
135 if writefile(f, r.Body, r.ContentLength) < 0 {
136 w.WriteHeader(http.StatusInternalServerError)
137 return
138 }
139
140 resp := conf.baseuri + conf.filectx + filepath.Base(tmp.Name())
141 w.Write([]byte(resp))
142}
143
144func uploaderPost(w http.ResponseWriter, r *http.Request) {
145 /* read 32Mb at a time */
146 r.ParseMultipartForm(32 << 20)
147
148 links := []string{}
149 for _, h := range r.MultipartForm.File["uck"] {
150 if h.Size > conf.maxsize {
151 w.WriteHeader(http.StatusRequestEntityTooLarge)
152 w.Write([]byte("File is too big"))
153 return
154 }
155
156 post, err := h.Open()
157 if err != nil {
158 w.WriteHeader(http.StatusInternalServerError)
159 return
160 }
161 defer post.Close()
162
163 tmp, _ := ioutil.TempFile(conf.filepath, "*"+path.Ext(h.Filename))
164 f, err := os.Create(tmp.Name())
165 if err != nil {
166 w.WriteHeader(http.StatusInternalServerError)
167 return
168 }
169 defer f.Close()
170
171 if writefile(f, post, h.Size) < 0 {
172 w.WriteHeader(http.StatusInternalServerError)
173 return
174 }
175
176 link := conf.baseuri + conf.filectx + filepath.Base(tmp.Name())
177 links = append(links, link)
178 }
179
180 if (r.PostFormValue("output") == "html") {
181 data := templatedata{ Links: links }
182 servetemplate(w, "/upload.html", data)
183 return
184 } else {
185 for _, link := range links {
186 w.Write([]byte(link + "\r\n"))
187 }
188 }
189}
190
191func uploaderGet(w http.ResponseWriter, r *http.Request) {
192 // r.URL.Path is sanitized regarding "." and ".."
193 filename := r.URL.Path
194 if r.URL.Path == "/" || r.URL.Path == "/index" {
195 data := templatedata{ Maxsize: humanize.IBytes(uint64(conf.maxsize))}
196 servetemplate(w, "/index.html", data)
197 return
198 }
199
200 f, err := os.Open(conf.rootdir + filename)
201 if err != nil {
202 w.WriteHeader(http.StatusNotFound)
203 fmt.Println(err)
204 return
205 }
206 defer f.Close()
207
208 servefile(f, w)
209}
210
211func uploader(w http.ResponseWriter, r *http.Request) {
212 switch r.Method {
213 case "POST":
214 uploaderPost(w, r)
215 case "PUT":
216 uploaderPut(w, r)
217 case "GET":
218 uploaderGet(w, r)
219 }
220}
221
222func main() {
223 flag.StringVar(&conf.bind, "l", "0.0.0.0:8080", "Address to bind to (default: 0.0.0.0:8080)")
224 flag.StringVar(&conf.baseuri, "b", "http://127.0.0.1:8080", "Base URI to use for links (default: http://127.0.0.1:8080)")
225 flag.StringVar(&conf.filepath, "f", "/tmp", "Path to save files to (default: /tmp)")
226 flag.StringVar(&conf.filectx, "c", "/f/", "Context to serve files from (default: /f/)")
227 flag.StringVar(&conf.rootdir, "r", "./static", "Root directory (default: ./static)")
228 flag.StringVar(&conf.templatedir, "t", "./templates", "Templates directory (default: ./templates)")
229 flag.Int64Var(&conf.maxsize, "s", 30064771072, "Maximum file size (default: 28Gib)")
230
231 flag.Parse()
232
233 http.HandleFunc("/", uploader)
234 http.Handle(conf.filectx, http.StripPrefix(conf.filectx, http.FileServer(http.Dir(conf.filepath))))
235 http.ListenAndServe("0.0.0.0:8080", nil)
236}
Note: See TracBrowser for help on using the repository browser.