Skip to content

Commit afd6eba

Browse files
committed
Unified methods.
1 parent 89607a2 commit afd6eba

File tree

2 files changed

+54
-93
lines changed

2 files changed

+54
-93
lines changed

routers/routes/web.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1105,7 +1105,7 @@ func RegisterRoutes(m *web.Route) {
11051105
m.Get("/objects/{oid}/{filename}", lfs.DownloadHandler)
11061106
m.Get("/objects/{oid}", lfs.DownloadHandler)
11071107
m.Put("/objects/{oid}", lfs.UploadHandler)
1108-
m.Post("/verify/{oid}", lfs.CheckAcceptMediaType, lfs.VerifyHandler)
1108+
m.Post("/verify", lfs.CheckAcceptMediaType, lfs.VerifyHandler)
11091109
m.Group("/locks", func() {
11101110
m.Get("/", lfs.GetListLockHandler)
11111111
m.Post("/", lfs.PostLockHandler)

services/lfs/server.go

Lines changed: 53 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,13 @@ func (rc *requestContext) ObjectLink(oid string) string {
4545
}
4646

4747
// VerifyLink builds a URL for verifying the object.
48-
func (rc *requestContext) VerifyLink(oid string) string {
49-
return setting.AppURL + path.Join(rc.User, rc.Repo+".git", "info/lfs/verify", oid)
48+
func (rc *requestContext) VerifyLink() string {
49+
return setting.AppURL + path.Join(rc.User, rc.Repo+".git", "info/lfs/verify")
5050
}
5151

5252
// CheckAcceptMediaType checks if the client accepts the LFS media type.
5353
func CheckAcceptMediaType(ctx *context.Context) {
54-
mediaParts := strings.Split(r.Header.Get("Accept"), ";")
54+
mediaParts := strings.Split(ctx.Req.Header.Get("Accept"), ";")
5555

5656
if mediaParts[0] != lfs_module.MediaType {
5757
log.Info("Calling a LFS method without accepting the correct media type: %s", lfs_module.MediaType)
@@ -95,7 +95,6 @@ func DownloadHandler(ctx *context.Context) {
9595

9696
meta, _ := getAuthenticatedRepoAndMeta(ctx, rc, p, false)
9797
if meta == nil {
98-
// Status already written in getAuthenticatedRepoAndMeta
9998
return
10099
}
101100

@@ -130,7 +129,6 @@ func DownloadHandler(ctx *context.Context) {
130129
contentStore := lfs_module.NewContentStore()
131130
content, err := contentStore.Get(meta.Pointer)
132131
if err != nil {
133-
// Errors are logged in contentStore.Get
134132
writeStatus(ctx, http.StatusNotFound)
135133
return
136134
}
@@ -163,34 +161,38 @@ func DownloadHandler(ctx *context.Context) {
163161
if written, err := io.CopyN(ctx.Resp, content, contentLength); err != nil {
164162
log.Error("Error whilst copying LFS OID[%s] to the response after %d bytes. Error: %v", meta.Oid, written, err)
165163
}
166-
logRequest(ctx.Req, statusCode)
167164
}
168165

169166
// BatchHandler provides the batch api
170167
func BatchHandler(ctx *context.Context) {
171-
bv := unpackbatch(ctx)
168+
var br lfs_module.BatchRequest
169+
if err := decodeJSON(ctx.Req, &br); err != nil {
170+
log.Trace("Unable to decode BATCH request vars: Error: %v", err)
171+
writeStatus(ctx, http.StatusBadRequest)
172+
return
173+
}
172174

173175
var isUpload bool
174-
if bv.Operation == "upload" {
176+
if br.Operation == "upload" {
175177
isUpload = true
176-
} else if bv.Operation == "download" {
178+
} else if br.Operation == "download" {
177179
isUpload = false
178180
} else {
179-
log.Info("Attempt to BATCH with invalid operation: %s", bv.Operation)
181+
log.Trace("Attempt to BATCH with invalid operation: %s", br.Operation)
180182
writeStatus(ctx, http.StatusBadRequest)
181183
return
182184
}
183185

184-
reqCtx := getRequestContext(ctx)
186+
rc := getRequestContext(ctx)
185187

186-
repository, err := models.GetRepositoryByOwnerAndName(reqCtx.User, reqCtx.Repo)
188+
repository, err := models.GetRepositoryByOwnerAndName(rc.User, rc.Repo)
187189
if err != nil {
188-
log.Error("Unable to get repository: %s/%s Error: %v", reqCtx.User, reqCtx.Repo, err)
190+
log.Trace("Unable to get repository: %s/%s Error: %v", rc.User, rc.Repo, err)
189191
writeStatus(ctx, http.StatusNotFound)
190192
return
191193
}
192194

193-
if !authenticate(ctx, repository, reqCtx.Authorization, isUpload) {
195+
if !authenticate(ctx, repository, rc.Authorization, isUpload) {
194196
requireAuth(ctx)
195197
return
196198
}
@@ -199,30 +201,30 @@ func BatchHandler(ctx *context.Context) {
199201

200202
var responseObjects []*lfs_module.ObjectResponse
201203

202-
for _, p := range bv.Objects {
203-
if !object.IsValid() {
204-
responseObjects = append(responseObjects, buildObjectResponse(reqCtx, p, false, false, http.StatusUnprocessableEntity))
204+
for _, p := range br.Objects {
205+
if !p.IsValid() {
206+
responseObjects = append(responseObjects, buildObjectResponse(rc, p, false, false, http.StatusUnprocessableEntity))
205207
continue
206208
}
207209

208210
exists, err := contentStore.Exists(p)
209211
if err != nil {
210-
log.Error("Unable to check if LFS OID[%s] exist on %s/%s. Error: %v", p.Oid, reqCtx.User, reqCtx.Repo, err)
212+
log.Error("Unable to check if LFS OID[%s] exist on %s/%s. Error: %v", p.Oid, rc.User, rc.Repo, err)
211213
writeStatus(ctx, http.StatusInternalServerError)
212214
return
213215
}
214216

215217
meta, metaErr := repository.GetLFSMetaObjectByOid(p.Oid)
216218
if metaErr != nil && metaErr != models.ErrLFSObjectNotExist {
217-
log.Error("Unable to get LFS MetaObject [%s] for %s/%s. Error: %v", p.Oid, reqCtx.User, reqCtx.Repo, metaErr)
219+
log.Error("Unable to get LFS MetaObject [%s] for %s/%s. Error: %v", p.Oid, rc.User, rc.Repo, metaErr)
218220
writeStatus(ctx, http.StatusInternalServerError)
219221
return
220222
}
221223

222224
var responseObject *lfs_module.ObjectResponse
223225
if isUpload {
224-
if !exists && setting.LFS.MaxFileSize > 0 && object.Size > setting.LFS.MaxFileSize {
225-
log.Info("Denied LFS OID[%s] upload of size %d to %s/%s because of LFS_MAX_FILE_SIZE=%d", p.Oid, p.Size, reqCtx.User, reqCtx.Repo, setting.LFS.MaxFileSize)
226+
if !exists && setting.LFS.MaxFileSize > 0 && p.Size > setting.LFS.MaxFileSize {
227+
log.Info("Denied LFS OID[%s] upload of size %d to %s/%s because of LFS_MAX_FILE_SIZE=%d", p.Oid, p.Size, rc.User, rc.Repo, setting.LFS.MaxFileSize)
226228
writeStatus(ctx, http.StatusRequestEntityTooLarge)
227229
return
228230
}
@@ -231,14 +233,14 @@ func BatchHandler(ctx *context.Context) {
231233
if meta == nil {
232234
_, err := models.NewLFSMetaObject(&models.LFSMetaObject{Pointer: p, RepositoryID: repository.ID})
233235
if err != nil {
234-
log.Error("Unable to create LFS MetaObject [%s] for %s/%s. Error: %v", p.Oid, reqCtx.User, reqCtx.Repo, metaErr)
236+
log.Error("Unable to create LFS MetaObject [%s] for %s/%s. Error: %v", p.Oid, rc.User, rc.Repo, metaErr)
235237
writeStatus(ctx, http.StatusInternalServerError)
236238
return
237239
}
238240
}
239241
}
240242

241-
responseObject = buildObjectResponse(reqCtx, p, false, !exists, 0)
243+
responseObject = buildObjectResponse(rc, p, false, !exists, 0)
242244
} else {
243245
errorCode := 0
244246
if !exists || meta == nil {
@@ -247,7 +249,7 @@ func BatchHandler(ctx *context.Context) {
247249
errorCode = http.StatusUnprocessableEntity
248250
}
249251

250-
responseObject = buildObjectResponse(reqCtx, p, true, false, errorCode)
252+
responseObject = buildObjectResponse(rc, p, true, false, errorCode)
251253
}
252254
responseObjects = append(responseObjects, responseObject)
253255
}
@@ -261,7 +263,6 @@ func BatchHandler(ctx *context.Context) {
261263
if err := enc.Encode(respobj); err != nil {
262264
log.Error("Failed to encode representation as json. Error: %v", err)
263265
}
264-
logRequest(ctx.Req, http.StatusOK)
265266
}
266267

267268
// UploadHandler receives data from the client and puts it into the content store
@@ -270,32 +271,33 @@ func UploadHandler(ctx *context.Context) {
270271

271272
meta, repository := getAuthenticatedRepoAndMeta(ctx, rc, p, true)
272273
if meta == nil {
273-
// Status already written in getAuthenticatedRepoAndMeta
274274
return
275275
}
276276

277277
contentStore := lfs_module.NewContentStore()
278278
defer ctx.Req.Body.Close()
279279
if err := contentStore.Put(meta.Pointer, ctx.Req.Body); err != nil {
280-
// Put will log the error itself
281-
ctx.Resp.WriteHeader(http.StatusInternalServerError)
282280
if err == lfs_module.ErrSizeMismatch || err == lfs_module.ErrHashMismatch {
283-
fmt.Fprintf(ctx.Resp, `{"message":"%s"}`, err)
281+
writeStatusMessage(ctx, http.StatusInternalServerError, err)
284282
} else {
285-
fmt.Fprintf(ctx.Resp, `{"message":"Internal Server Error"}`)
283+
writeStatus(ctx, http.StatusInternalServerError)
286284
}
287285
if _, err = repository.RemoveLFSMetaObjectByOid(p.Oid); err != nil {
288-
log.Error("Whilst removing metaobject for LFS OID[%s] due to preceding error there was another Error: %v", p.Oid, err)
286+
log.Error("Error whilst removing metaobject for LFS OID[%s]: %v", p.Oid, err)
289287
}
290288
return
291289
}
292-
293-
logRequest(ctx.Req, http.StatusOK)
294290
}
295291

296292
// VerifyHandler verify oid and its size from the content store
297293
func VerifyHandler(ctx *context.Context) {
298-
rc, p := unpack(ctx)
294+
var p lfs_module.Pointer
295+
if err := decodeJSON(ctx.Req, &p); err != nil {
296+
writeStatus(ctx, http.StatusUnprocessableEntity)
297+
return
298+
}
299+
300+
rc := getRequestContext(ctx)
299301

300302
meta, _ := getAuthenticatedRepoAndMeta(ctx, rc, p, true)
301303
if meta == nil {
@@ -304,20 +306,25 @@ func VerifyHandler(ctx *context.Context) {
304306

305307
contentStore := lfs_module.NewContentStore()
306308
ok, err := contentStore.Verify(meta.Pointer)
307-
if err != nil {
308-
// Error will be logged in Verify
309-
ctx.Resp.WriteHeader(http.StatusInternalServerError)
310-
fmt.Fprintf(ctx.Resp, `{"message":"Internal Server Error"}`)
311-
return
312-
}
313309

314310
status := http.StatusOK
315-
if !ok {
311+
if err != nil {
312+
status = http.StatusInternalServerError
313+
} else if !ok {
316314
status = http.StatusUnprocessableEntity
317315
}
318316
writeStatus(ctx, status)
319317
}
320318

319+
func decodeJSON(req *http.Request, v interface{}) error {
320+
json := jsoniter.ConfigCompatibleWithStandardLibrary
321+
322+
defer req.Body.Close()
323+
324+
dec := json.NewDecoder(req.Body)
325+
return dec.Decode(v)
326+
}
327+
321328
func getRequestContext(ctx *context.Context) *requestContext {
322329
return &requestContext{
323330
User: ctx.Params("username"),
@@ -349,7 +356,7 @@ func buildObjectResponse(rc *requestContext, pointer lfs_module.Pointer, downloa
349356
}
350357
if upload {
351358
rep.Actions["upload"] = &lfs_module.Link{Href: rc.ObjectLink(pointer.Oid), Header: header}
352-
rep.Actions["verify"] = &lfs_module.Link{Href: rc.VerifyLink(pointer.Oid), Header: verifyHeader}
359+
rep.Actions["verify"] = &lfs_module.Link{Href: rc.VerifyLink(), Header: verifyHeader}
353360
}
354361
}
355362
return rep
@@ -359,62 +366,16 @@ func unpack(ctx *context.Context) (*requestContext, lfs_module.Pointer) {
359366
rc := getRequestContext(ctx)
360367
p := lfs_module.Pointer{Oid: ctx.Params("oid")}
361368

362-
if ctx.Req.Method == "POST" { // Maybe also check if +json
363-
var p2 lfs_module.Pointer
364-
bodyReader := ctx.Req.Body
365-
defer bodyReader.Close()
366-
json := jsoniter.ConfigCompatibleWithStandardLibrary
367-
dec := json.NewDecoder(bodyReader)
368-
err := dec.Decode(&p2)
369-
if err != nil {
370-
// The error is logged as a WARN here because this may represent misbehaviour rather than a true error
371-
log.Warn("Unable to decode POST request vars for LFS OID[%s] in %s/%s: Error: %v", p.Oid, rc.User, rc.Repo, err)
372-
return rc, p
373-
}
374-
375-
p.Oid = p2.Oid
376-
p.Size = p2.Size
377-
}
378-
379369
return rc, p
380370
}
381371

382-
// TODO cheap hack, unify with unpack
383-
func unpackbatch(ctx *context.Context) *lfs_module.BatchRequest {
384-
385-
r := ctx.Req
386-
var bv lfs_module.BatchRequest
387-
388-
bodyReader := r.Body
389-
defer bodyReader.Close()
390-
json := jsoniter.ConfigCompatibleWithStandardLibrary
391-
dec := json.NewDecoder(bodyReader)
392-
err := dec.Decode(&bv)
393-
if err != nil {
394-
// The error is logged as a WARN here because this may represent misbehaviour rather than a true error
395-
log.Warn("Unable to decode BATCH request vars in %s/%s: Error: %v", ctx.Params("username"), strings.TrimSuffix(ctx.Params("reponame"), ".git"), err)
396-
return &bv
397-
}
398-
399-
return &bv
400-
}
401-
402372
func writeStatus(ctx *context.Context, status int) {
403-
message := http.StatusText(status)
404-
405-
mediaParts := strings.Split(ctx.Req.Header.Get("Accept"), ";")
406-
mt := mediaParts[0]
407-
if strings.HasSuffix(mt, "+json") {
408-
message = `{"message":"` + message + `"}`
409-
}
410-
411-
ctx.Resp.WriteHeader(status)
412-
fmt.Fprint(ctx.Resp, message)
413-
logRequest(ctx.Req, status)
373+
writeStatusMessage(ctx, status, http.StatusText(status))
414374
}
415375

416-
func logRequest(r *http.Request, status int) {
417-
log.Debug("LFS request - Method: %s, URL: %s, Status %d", r.Method, r.URL, status)
376+
func writeStatusMessage(ctx *context.Context, status int, message interface{}) {
377+
ctx.Resp.WriteHeader(status)
378+
fmt.Fprintf(ctx.Resp, `{"message":"%v"}`, message)
418379
}
419380

420381
// authenticate uses the authorization string to determine whether

0 commit comments

Comments
 (0)