source: code/trunk/partage.go@ 21

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

Remove useless function contenttype()

File size: 5.4 KB
Line 
1package main
2
3import (
4 "fmt"
5 "flag"
6 "io"
7 "io/ioutil"
8 "net/http"
9 "os"
10 "time"
11 "path"
12 "path/filepath"
13 "html/template"
14 "encoding/json"
15
16 "github.com/dustin/go-humanize"
17)
18
19type templatedata struct {
20 Links []string
21 Size string
22 Maxsize string
23}
24
25type metadata struct {
26 Filename string
27 Size int64
28 Expiry int64
29}
30
31var conf struct {
32 bind string
33 baseuri string
34 filepath string
35 metapath string
36 rootdir string
37 templatedir string
38 filectx string
39 metactx string
40 maxsize int64
41 expiry int64
42}
43
44
45func writefile(f *os.File, s io.ReadCloser, contentlength int64) error {
46 buffer := make([]byte, 4096)
47 eof := false
48 sz := int64(0)
49
50 defer f.Sync()
51
52 for !eof {
53 n, err := s.Read(buffer)
54 if err != nil && err != io.EOF {
55 return err
56 } else if err == io.EOF {
57 eof = true
58 }
59
60 /* ensure we don't write more than expected */
61 r := int64(n)
62 if sz+r > contentlength {
63 r = contentlength - sz
64 eof = true
65 }
66
67 _, err = f.Write(buffer[:r])
68 if err != nil {
69 return err
70 }
71 sz += r
72 }
73
74 return nil
75}
76
77func writemeta(filename string, expiry int64) error {
78
79 f, _ := os.Open(filename)
80 stat, _ := f.Stat()
81 size := stat.Size()
82 f.Close()
83
84 meta := metadata{
85 Filename: filepath.Base(filename),
86 Size: size,
87 Expiry: time.Now().Unix() + expiry,
88 }
89
90 f, err := os.Create(conf.metapath + "/" + meta.Filename + ".json")
91 if err != nil {
92 return err
93 }
94 defer f.Close()
95
96 j, err := json.Marshal(meta)
97 if err != nil {
98 return err
99 }
100
101 _, err = f.Write(j)
102
103 return err
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 err = writefile(f, r.Body, r.ContentLength); err != nil {
135 w.WriteHeader(http.StatusInternalServerError)
136 defer os.Remove(tmp.Name())
137 return
138 }
139 writemeta(tmp.Name(), conf.expiry)
140
141 resp := conf.baseuri + conf.filectx + filepath.Base(tmp.Name())
142 w.Write([]byte(resp))
143}
144
145func uploaderPost(w http.ResponseWriter, r *http.Request) {
146 /* read 32Mb at a time */
147 r.ParseMultipartForm(32 << 20)
148
149 links := []string{}
150 for _, h := range r.MultipartForm.File["uck"] {
151 if h.Size > conf.maxsize {
152 w.WriteHeader(http.StatusRequestEntityTooLarge)
153 w.Write([]byte("File is too big"))
154 return
155 }
156
157 post, err := h.Open()
158 if err != nil {
159 w.WriteHeader(http.StatusInternalServerError)
160 return
161 }
162 defer post.Close()
163
164 tmp, _ := ioutil.TempFile(conf.filepath, "*"+path.Ext(h.Filename))
165 f, err := os.Create(tmp.Name())
166 if err != nil {
167 w.WriteHeader(http.StatusInternalServerError)
168 return
169 }
170 defer f.Close()
171
172 if err = writefile(f, post, h.Size); err != nil {
173 w.WriteHeader(http.StatusInternalServerError)
174 defer os.Remove(tmp.Name())
175 return
176 }
177
178 writemeta(tmp.Name(), conf.expiry)
179
180
181 //link := conf.baseuri + conf.filectx + filepath.Base(tmp.Name())
182 link := conf.baseuri + conf.metactx + filepath.Base(tmp.Name()) + ".json"
183 links = append(links, link)
184 }
185
186 if (r.PostFormValue("output") == "html") {
187 data := templatedata{ Links: links }
188 servetemplate(w, "/upload.html", data)
189 return
190 } else {
191 for _, link := range links {
192 w.Write([]byte(link + "\r\n"))
193 }
194 }
195}
196
197func uploaderGet(w http.ResponseWriter, r *http.Request) {
198 // r.URL.Path is sanitized regarding "." and ".."
199 filename := r.URL.Path
200 if r.URL.Path == "/" || r.URL.Path == "/index.html" {
201 data := templatedata{ Maxsize: humanize.IBytes(uint64(conf.maxsize))}
202 servetemplate(w, "/index.html", data)
203 return
204 }
205
206 http.ServeFile(w, r, conf.rootdir + filename)
207}
208
209func uploader(w http.ResponseWriter, r *http.Request) {
210 switch r.Method {
211 case "POST":
212 uploaderPost(w, r)
213 case "PUT":
214 uploaderPut(w, r)
215 case "GET":
216 uploaderGet(w, r)
217 }
218}
219
220func main() {
221 flag.StringVar(&conf.bind, "l", "0.0.0.0:8080", "Address to bind to (default: 0.0.0.0:8080)")
222 flag.StringVar(&conf.baseuri, "b", "http://127.0.0.1:8080", "Base URI to use for links (default: http://127.0.0.1:8080)")
223 flag.StringVar(&conf.filepath, "f", "./files", "Path to save files to (default: ./files)")
224 flag.StringVar(&conf.metapath, "m", "./meta", "Path to save metadata to (default: ./meta)")
225 flag.StringVar(&conf.filectx, "c", "/f/", "Context to serve files from (default: /f/)")
226 flag.StringVar(&conf.metactx, "d", "/m/", "Context to serve metadata from (default: /m/)")
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 flag.Int64Var(&conf.expiry, "e", 86400, "Link expiration time (default: 24h)")
231
232 flag.Parse()
233
234 http.HandleFunc("/", uploader)
235 http.Handle(conf.filectx, http.StripPrefix(conf.filectx, http.FileServer(http.Dir(conf.filepath))))
236 http.Handle(conf.metactx, http.StripPrefix(conf.metactx, http.FileServer(http.Dir(conf.metapath))))
237 http.ListenAndServe("0.0.0.0:8080", nil)
238}
Note: See TracBrowser for help on using the repository browser.