@@ -58,8 +58,20 @@ type ObjectError struct {
58
58
Message string `json:"message"`
59
59
}
60
60
61
- // ObjectLink builds a URL linking to the object.
62
- func (v * RequestVars ) ObjectLink () string {
61
+ // DownloadLink builds a URL to download the object.
62
+ func (v * RequestVars ) DownloadLink () string {
63
+ return v .internalLink ("objects" )
64
+ }
65
+
66
+ // UploadLink builds a URL to upload the object.
67
+ func (v * RequestVars ) UploadLink (useTus bool ) string {
68
+ if useTus {
69
+ return v .tusLink ()
70
+ }
71
+ return v .internalLink ("objects" )
72
+ }
73
+
74
+ func (v * RequestVars ) internalLink (subpath string ) string {
63
75
path := ""
64
76
65
77
if len (v .User ) > 0 {
@@ -70,7 +82,25 @@ func (v *RequestVars) ObjectLink() string {
70
82
path += fmt .Sprintf ("/%s" , v .Repo )
71
83
}
72
84
73
- path += fmt .Sprintf ("/objects/%s" , v .Oid )
85
+ path += fmt .Sprintf ("/%s/%s" , subpath , v .Oid )
86
+
87
+ if Config .IsHTTPS () {
88
+ return fmt .Sprintf ("%s://%s%s" , Config .Scheme , Config .Host , path )
89
+ }
90
+
91
+ return fmt .Sprintf ("http://%s%s" , Config .Host , path )
92
+ }
93
+
94
+ func (v * RequestVars ) tusLink () string {
95
+ link , err := tusServer .Create (v .Oid , v .Size )
96
+ if err != nil {
97
+ logger .Fatal (kv {"fn" : fmt .Sprintf ("Unable to create tus link for %s: %v" , v .Oid , err )})
98
+ }
99
+ return link
100
+ }
101
+
102
+ func (v * RequestVars ) VerifyLink () string {
103
+ path := fmt .Sprintf ("/verify/%s" , v .Oid )
74
104
75
105
if Config .IsHTTPS () {
76
106
return fmt .Sprintf ("%s://%s%s" , Config .Scheme , Config .Host , path )
@@ -115,6 +145,8 @@ func NewApp(content *ContentStore, meta *MetaStore) *App {
115
145
116
146
r .HandleFunc ("/objects" , app .PostHandler ).Methods ("POST" ).MatcherFunc (MetaMatcher )
117
147
148
+ r .HandleFunc ("/verify/{oid}" , app .VerifyHandler ).Methods ("POST" )
149
+
118
150
app .addMgmt (r )
119
151
120
152
app .router = r
@@ -191,7 +223,7 @@ func (a *App) GetMetaHandler(w http.ResponseWriter, r *http.Request) {
191
223
192
224
if r .Method == "GET" {
193
225
enc := json .NewEncoder (w )
194
- enc .Encode (a .Represent (rv , meta , true , false ))
226
+ enc .Encode (a .Represent (rv , meta , true , false , false ))
195
227
}
196
228
197
229
logRequest (r , 200 )
@@ -219,7 +251,7 @@ func (a *App) PostHandler(w http.ResponseWriter, r *http.Request) {
219
251
w .WriteHeader (sentStatus )
220
252
221
253
enc := json .NewEncoder (w )
222
- enc .Encode (a .Represent (rv , meta , meta .Existing , true ))
254
+ enc .Encode (a .Represent (rv , meta , meta .Existing , true , false ))
223
255
logRequest (r , sentStatus )
224
256
}
225
257
@@ -229,11 +261,21 @@ func (a *App) BatchHandler(w http.ResponseWriter, r *http.Request) {
229
261
230
262
var responseObjects []* Representation
231
263
264
+ var useTus bool
265
+ if bv .Operation == "upload" && Config .IsUsingTus () {
266
+ for _ , t := range bv .Transfers {
267
+ if t == "tus" {
268
+ useTus = true
269
+ break
270
+ }
271
+ }
272
+ }
273
+
232
274
// Create a response object
233
275
for _ , object := range bv .Objects {
234
276
meta , err := a .metaStore .Get (object )
235
277
if err == nil && a .contentStore .Exists (meta ) { // Object is found and exists
236
- responseObjects = append (responseObjects , a .Represent (object , meta , true , false ))
278
+ responseObjects = append (responseObjects , a .Represent (object , meta , true , false , false ))
237
279
continue
238
280
}
239
281
@@ -245,13 +287,17 @@ func (a *App) BatchHandler(w http.ResponseWriter, r *http.Request) {
245
287
// Object is not found
246
288
meta , err = a .metaStore .Put (object )
247
289
if err == nil {
248
- responseObjects = append (responseObjects , a .Represent (object , meta , meta .Existing , true ))
290
+ responseObjects = append (responseObjects , a .Represent (object , meta , meta .Existing , true , useTus ))
249
291
}
250
292
}
251
293
252
294
w .Header ().Set ("Content-Type" , metaMediaType )
253
295
254
296
respobj := & BatchResponse {Objects : responseObjects }
297
+ // Respond with TUS support if advertised
298
+ if useTus {
299
+ respobj .Transfer = "tus"
300
+ }
255
301
256
302
enc := json .NewEncoder (w )
257
303
enc .Encode (respobj )
@@ -281,9 +327,21 @@ func (a *App) PutHandler(w http.ResponseWriter, r *http.Request) {
281
327
logRequest (r , 200 )
282
328
}
283
329
330
+ func (a * App ) VerifyHandler (w http.ResponseWriter , r * http.Request ) {
331
+ vars := mux .Vars (r )
332
+ oid := vars ["oid" ]
333
+ err := tusServer .Finish (oid , a .contentStore )
334
+
335
+ if err != nil {
336
+ logger .Fatal (kv {"fn" : "VerifyHandler" , "err" : fmt .Sprintf ("Failed to verify %s: %v" , oid , err )})
337
+ }
338
+
339
+ logRequest (r , 200 )
340
+ }
341
+
284
342
// Represent takes a RequestVars and Meta and turns it into a Representation suitable
285
343
// for json encoding
286
- func (a * App ) Represent (rv * RequestVars , meta * MetaObject , download , upload bool ) * Representation {
344
+ func (a * App ) Represent (rv * RequestVars , meta * MetaObject , download , upload , useTus bool ) * Representation {
287
345
rep := & Representation {
288
346
Oid : meta .Oid ,
289
347
Size : meta .Size ,
@@ -296,11 +354,14 @@ func (a *App) Represent(rv *RequestVars, meta *MetaObject, download, upload bool
296
354
header ["Authorization" ] = rv .Authorization
297
355
}
298
356
if download {
299
- rep .Actions ["download" ] = & link {Href : rv .ObjectLink (), Header : header }
357
+ rep .Actions ["download" ] = & link {Href : rv .DownloadLink (), Header : header }
300
358
}
301
359
302
360
if upload {
303
- rep .Actions ["upload" ] = & link {Href : rv .ObjectLink (), Header : header }
361
+ rep .Actions ["upload" ] = & link {Href : rv .UploadLink (useTus ), Header : header }
362
+ if useTus {
363
+ rep .Actions ["verify" ] = & link {Href : rv .VerifyLink (), Header : header }
364
+ }
304
365
}
305
366
return rep
306
367
}
0 commit comments