From 844f9a4bd8c5c35a9dab598442b4b3d58153f026 Mon Sep 17 00:00:00 2001
From: Marat Radchenko <marat@slonopotamus.org>
Date: Sat, 25 May 2019 00:21:00 +0300
Subject: [PATCH] Fix /verify LFS handler expecting wrong content-type (#7015)

Fixes #6960

According to [spec][1], /verify requests must have `Accept: application/vnd.git-lfs+json`

Previous code works because `git-lfs` also [violates spec and doesn't send any Accept header at all][2]
For other clients that DO set `Accept: application/vnd.git-lfs+json`, addition of `Accept: application/vnd.git-lfs`
either forces them to violate the spec or is ignored, depending on order in what they create header list.

[1]: https://github.com/git-lfs/git-lfs/blob/master/docs/api/basic-transfers.md#verification
[2]: https://github.com/git-lfs/git-lfs/issues/3662
---
 modules/lfs/server.go | 33 +++++++++++++++------------------
 1 file changed, 15 insertions(+), 18 deletions(-)

diff --git a/modules/lfs/server.go b/modules/lfs/server.go
index 8ae6326842..7e20aa8515 100644
--- a/modules/lfs/server.go
+++ b/modules/lfs/server.go
@@ -22,8 +22,7 @@ import (
 )
 
 const (
-	contentMediaType = "application/vnd.git-lfs"
-	metaMediaType    = contentMediaType + "+json"
+	metaMediaType = "application/vnd.git-lfs+json"
 )
 
 // RequestVars contain variables from the HTTP request. Variables from routing, json body decoding, and
@@ -101,11 +100,10 @@ func ObjectOidHandler(ctx *context.Context) {
 			getMetaHandler(ctx)
 			return
 		}
-		if ContentMatcher(ctx.Req) || len(ctx.Params("filename")) > 0 {
-			getContentHandler(ctx)
-			return
-		}
-	} else if ctx.Req.Method == "PUT" && ContentMatcher(ctx.Req) {
+
+		getContentHandler(ctx)
+		return
+	} else if ctx.Req.Method == "PUT" {
 		PutHandler(ctx)
 		return
 	}
@@ -348,7 +346,7 @@ func VerifyHandler(ctx *context.Context) {
 		return
 	}
 
-	if !ContentMatcher(ctx.Req) {
+	if !MetaMatcher(ctx.Req) {
 		writeStatus(ctx, 400)
 		return
 	}
@@ -385,7 +383,6 @@ func Represent(rv *RequestVars, meta *models.LFSMetaObject, download, upload boo
 	}
 
 	header := make(map[string]string)
-	header["Accept"] = contentMediaType
 
 	if rv.Authorization == "" {
 		//https://github.com/github/git-lfs/issues/1088
@@ -404,20 +401,20 @@ func Represent(rv *RequestVars, meta *models.LFSMetaObject, download, upload boo
 
 	if upload && !download {
 		// Force client side verify action while gitea lacks proper server side verification
-		rep.Actions["verify"] = &link{Href: rv.VerifyLink(), Header: header}
+		verifyHeader := make(map[string]string)
+		for k, v := range header {
+			verifyHeader[k] = v
+		}
+
+		// This is only needed to workaround https://github.com/git-lfs/git-lfs/issues/3662
+		verifyHeader["Accept"] = metaMediaType
+
+		rep.Actions["verify"] = &link{Href: rv.VerifyLink(), Header: verifyHeader}
 	}
 
 	return rep
 }
 
-// ContentMatcher provides a mux.MatcherFunc that only allows requests that contain
-// an Accept header with the contentMediaType
-func ContentMatcher(r macaron.Request) bool {
-	mediaParts := strings.Split(r.Header.Get("Accept"), ";")
-	mt := mediaParts[0]
-	return mt == contentMediaType
-}
-
 // MetaMatcher provides a mux.MatcherFunc that only allows requests that contain
 // an Accept header with the metaMediaType
 func MetaMatcher(r macaron.Request) bool {