@@ -21,9 +21,9 @@ func (app *App) HandleHome(w http.ResponseWriter, r *http.Request) {
2121 "MaxMB" : app .Conf .MaxMB ,
2222 "Host" : r .Host ,
2323 })
24- if err != nil {
25- app .Logger .Error ("Template error" , "err" , err )
26- }
24+ if err != nil {
25+ app .Logger .Error ("Template error" , "err" , err )
26+ }
2727}
2828
2929func (app * App ) HandleUpload (w http.ResponseWriter , r * http.Request ) {
@@ -32,17 +32,27 @@ func (app *App) HandleUpload(w http.ResponseWriter, r *http.Request) {
3232
3333 file , header , err := r .FormFile ("file" )
3434 if err != nil {
35+ if err .Error () == "http: request body too large" {
36+ app .SendError (w , r , http .StatusRequestEntityTooLarge )
37+ return
38+ }
3539 app .SendError (w , r , http .StatusBadRequest )
3640 return
3741 }
3842 defer file .Close ()
3943
4044 tmpPath := filepath .Join (app .Conf .StorageDir , "tmp" , fmt .Sprintf ("up_%d" , os .Getpid ()))
41- tmp , _ := os .Create (tmpPath )
45+ tmp , err := os .Create (tmpPath )
46+ if err != nil {
47+ app .Logger .Error ("Failed to create temp file" , "err" , err )
48+ app .SendError (w , r , http .StatusInternalServerError )
49+ return
50+ }
4251 defer os .Remove (tmpPath )
4352 defer tmp .Close ()
4453
4554 if _ , err := io .Copy (tmp , file ); err != nil {
55+ app .Logger .Error ("Failed to write temp file" , "err" , err )
4656 app .SendError (w , r , http .StatusRequestEntityTooLarge )
4757 return
4858 }
@@ -51,53 +61,124 @@ func (app *App) HandleUpload(w http.ResponseWriter, r *http.Request) {
5161}
5262
5363func (app * App ) HandleChunk (w http.ResponseWriter , r * http.Request ) {
64+ r .Body = http .MaxBytesReader (w , r .Body , 10 << 20 )
65+
5466 uid := r .FormValue ("upload_id" )
55- idx , _ := strconv .Atoi (r .FormValue ("index" ))
67+ idx , err := strconv .Atoi (r .FormValue ("index" ))
68+ if err != nil {
69+ app .SendError (w , r , http .StatusBadRequest )
70+ return
71+ }
5672
57- if ! reUploadID .MatchString (uid ) || idx > 1000 {
73+ const chunkSize = 8 << 20
74+ maxChunks := int ((app .Conf .MaxMB << 20 )/ chunkSize ) + 2
75+
76+ if ! reUploadID .MatchString (uid ) || idx > maxChunks || idx < 0 {
5877 app .SendError (w , r , http .StatusBadRequest )
5978 return
6079 }
6180
6281 file , _ , err := r .FormFile ("chunk" )
6382 if err != nil {
83+ if err .Error () == "http: request body too large" {
84+ app .SendError (w , r , http .StatusRequestEntityTooLarge )
85+ return
86+ }
87+ app .SendError (w , r , http .StatusBadRequest )
6488 return
6589 }
6690 defer file .Close ()
6791
6892 dir := filepath .Join (app .Conf .StorageDir , "tmp" , uid )
69- os .MkdirAll (dir , 0700 )
93+ if err := os .MkdirAll (dir , 0700 ); err != nil {
94+ app .Logger .Error ("Failed to create chunk dir" , "err" , err )
95+ app .SendError (w , r , http .StatusInternalServerError )
96+ return
97+ }
7098
71- dest , _ := os .Create (filepath .Join (dir , strconv .Itoa (idx )))
99+ dest , err := os .Create (filepath .Join (dir , strconv .Itoa (idx )))
100+ if err != nil {
101+ app .Logger .Error ("Failed to create chunk file" , "err" , err )
102+ app .SendError (w , r , http .StatusInternalServerError )
103+ return
104+ }
72105 defer dest .Close ()
73- io .Copy (dest , file )
106+
107+ if _ , err := io .Copy (dest , file ); err != nil {
108+ app .Logger .Error ("Failed to save chunk" , "err" , err )
109+ app .SendError (w , r , http .StatusInternalServerError )
110+ return
111+ }
74112}
75113
76114func (app * App ) HandleFinish (w http.ResponseWriter , r * http.Request ) {
77115 uid := r .FormValue ("upload_id" )
78- total , _ := strconv .Atoi (r .FormValue ("total" ))
116+ total , err := strconv .Atoi (r .FormValue ("total" ))
117+ if err != nil {
118+ app .SendError (w , r , http .StatusBadRequest )
119+ return
120+ }
121+
122+ const chunkSize = 8 << 20
123+ maxChunks := int ((app .Conf .MaxMB << 20 )/ chunkSize ) + 2
79124
80- if ! reUploadID .MatchString (uid ) || total > 1000 {
125+ if ! reUploadID .MatchString (uid ) || total > maxChunks || total <= 0 {
81126 app .SendError (w , r , http .StatusBadRequest )
82127 return
83128 }
84129
85130 tmpPath := filepath .Join (app .Conf .StorageDir , "tmp" , "m_" + uid )
86- merged , _ := os .Create (tmpPath )
131+ merged , err := os .Create (tmpPath )
132+ if err != nil {
133+ app .Logger .Error ("Failed to create merge file" , "err" , err )
134+ app .SendError (w , r , http .StatusInternalServerError )
135+ return
136+ }
87137 defer os .Remove (tmpPath )
88138 defer merged .Close ()
89139
140+ limit := app .Conf .MaxMB << 20
141+ var written int64
142+
90143 for i := range total {
91144 partPath := filepath .Join (app .Conf .StorageDir , "tmp" , uid , strconv .Itoa (i ))
92145 part , err := os .Open (partPath )
93146 if err != nil {
94- continue
147+ app .Logger .Error ("Missing chunk during merge" , "uid" , uid , "index" , i , "err" , err )
148+ app .SendError (w , r , http .StatusBadRequest )
149+ return
95150 }
96- io .Copy (merged , part )
151+
152+ n , err := io .Copy (merged , part )
97153 part .Close ()
154+ if err != nil {
155+ app .Logger .Error ("Failed to append chunk" , "err" , err )
156+ app .SendError (w , r , http .StatusInternalServerError )
157+ return
158+ }
159+
160+ written += n
161+ if written > limit {
162+ app .SendError (w , r , http .StatusRequestEntityTooLarge )
163+ return
164+ }
165+ }
166+
167+ if err := merged .Close (); err != nil {
168+ app .Logger .Error ("Failed to close merged file" , "err" , err )
169+ app .SendError (w , r , http .StatusInternalServerError )
170+ return
171+ }
172+
173+ mergedRead , err := os .Open (tmpPath )
174+ if err != nil {
175+ app .Logger .Error ("Failed to open merged file" , "err" , err )
176+ app .SendError (w , r , http .StatusInternalServerError )
177+ return
98178 }
179+ defer mergedRead .Close ()
99180
100- app .FinalizeFile (w , r , merged , r .FormValue ("filename" ))
181+ app .FinalizeFile (w , r , mergedRead , r .FormValue ("filename" ))
101182 os .RemoveAll (filepath .Join (app .Conf .StorageDir , "tmp" , uid ))
102183}
103184
@@ -126,10 +207,21 @@ func (app *App) HandleGetFile(w http.ResponseWriter, r *http.Request) {
126207 return
127208 }
128209
129- f , _ := os .Open (path )
210+ f , err := os .Open (path )
211+ if err != nil {
212+ app .Logger .Error ("Failed to open file" , "path" , path , "err" , err )
213+ app .SendError (w , r , http .StatusInternalServerError )
214+ return
215+ }
130216 defer f .Close ()
131217
132- streamer , _ := crypto .NewGCMStreamer (key )
218+ streamer , err := crypto .NewGCMStreamer (key )
219+ if err != nil {
220+ app .Logger .Error ("Failed to create crypto streamer" , "err" , err )
221+ app .SendError (w , r , http .StatusInternalServerError )
222+ return
223+ }
224+
133225 decryptor := crypto .NewDecryptor (f , streamer .AEAD , info .Size ())
134226
135227 contentType := mime .TypeByExtension (ext )
@@ -146,29 +238,70 @@ func (app *App) HandleGetFile(w http.ResponseWriter, r *http.Request) {
146238}
147239
148240func (app * App ) FinalizeFile (w http.ResponseWriter , r * http.Request , src * os.File , filename string ) {
149- src .Seek (0 , 0 )
150- key , _ := crypto .DeriveKey (src )
241+ if _ , err := src .Seek (0 , 0 ); err != nil {
242+ app .Logger .Error ("Seek failed" , "err" , err )
243+ app .SendError (w , r , http .StatusInternalServerError )
244+ return
245+ }
246+
247+ key , err := crypto .DeriveKey (src )
248+ if err != nil {
249+ app .Logger .Error ("Key derivation failed" , "err" , err )
250+ app .SendError (w , r , http .StatusInternalServerError )
251+ return
252+ }
151253
152254 ext := filepath .Ext (filename )
153255 id := crypto .GetID (key , ext )
154256
155- src .Seek (0 , 0 )
257+ if _ , err := src .Seek (0 , 0 ); err != nil {
258+ app .Logger .Error ("Seek failed" , "err" , err )
259+ app .SendError (w , r , http .StatusInternalServerError )
260+ return
261+ }
262+
156263 finalPath := filepath .Join (app .Conf .StorageDir , id )
157264
158265 if _ , err := os .Stat (finalPath ); err == nil {
159266 app .RespondWithLink (w , r , key , filename )
160267 return
161268 }
162269
163- out , _ := os .Create (finalPath + ".tmp" )
164- streamer , _ := crypto .NewGCMStreamer (key )
165- if err := streamer .EncryptStream (out , src ); err != nil {
270+ out , err := os .Create (finalPath + ".tmp" )
271+ if err != nil {
272+ app .Logger .Error ("Failed to create final file" , "err" , err )
273+ app .SendError (w , r , http .StatusInternalServerError )
274+ return
275+ }
276+ defer func () {
166277 out .Close ()
167278 os .Remove (finalPath + ".tmp" )
279+ }()
280+
281+ streamer , err := crypto .NewGCMStreamer (key )
282+ if err != nil {
283+ app .Logger .Error ("Failed to create streamer" , "err" , err )
168284 app .SendError (w , r , http .StatusInternalServerError )
169285 return
170286 }
171- out .Close ()
172- os .Rename (finalPath + ".tmp" , finalPath )
287+
288+ if err := streamer .EncryptStream (out , src ); err != nil {
289+ app .Logger .Error ("Encryption failed" , "err" , err )
290+ app .SendError (w , r , http .StatusInternalServerError )
291+ return
292+ }
293+
294+ if err := out .Close (); err != nil {
295+ app .Logger .Error ("Failed to close final file" , "err" , err )
296+ app .SendError (w , r , http .StatusInternalServerError )
297+ return
298+ }
299+
300+ if err := os .Rename (finalPath + ".tmp" , finalPath ); err != nil {
301+ app .Logger .Error ("Failed to rename final file" , "err" , err )
302+ app .SendError (w , r , http .StatusInternalServerError )
303+ return
304+ }
305+
173306 app .RespondWithLink (w , r , key , filename )
174307}
0 commit comments