Skip to content

Commit fbe34c8

Browse files
committed
lfs: ask client to always send the same value for the HTTP header (#6369)
# Conflicts: # go.sum
1 parent e6b4c46 commit fbe34c8

File tree

4 files changed

+73
-8
lines changed

4 files changed

+73
-8
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ All notable changes to Gogs are documented in this file.
2222
- Commit message contains keywords look like an issue reference no longer fails the push entirely. [#6289](https://github.com/gogs/gogs/issues/6289)
2323
- _Regression:_ When running Gogs on Windows, push commits no longer fail on a daily basis with the error "pre-receive hook declined". [#6316](https://github.com/gogs/gogs/issues/6316)
2424
- Auto-linked commit SHAs now have correct links. [#6300](https://github.com/gogs/gogs/issues/6300)
25+
- Git LFS client (with version >= 2.5.0) wasn't able to upload files with known format (e.g. PNG, JPEG), and the server is expecting the HTTP Header `Content-Type` to be `application/octet-stream`. The server now tells the LFS client to always use `Content-Type: application/octet-stream` when upload files.
2526

2627
### Removed
2728

internal/route/lfs/batch.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ func serveBatch(c *macaron.Context, owner *db.User, repo *db.Repository) {
4444
actions = batchActions{
4545
Upload: &batchAction{
4646
Href: fmt.Sprintf("%s/%s", baseHref, obj.Oid),
47+
Header: map[string]string{
48+
// NOTE: git-lfs v2.5.0 sets the Content-Type based on the uploaded file.
49+
// This ensures that the client always uses the designated value for the header.
50+
"Content-Type": "application/octet-stream",
51+
},
4752
},
4853
Verify: &batchAction{
4954
Href: fmt.Sprintf("%s/verify", baseHref),
@@ -136,7 +141,8 @@ type batchError struct {
136141
}
137142

138143
type batchAction struct {
139-
Href string `json:"href"`
144+
Href string `json:"href"`
145+
Header map[string]string `json:"header,omitempty"`
140146
}
141147

142148
type batchActions struct {

internal/route/lfs/batch_test.go

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package lfs
66

77
import (
88
"bytes"
9+
"encoding/json"
910
"io/ioutil"
1011
"net/http"
1112
"net/http/httptest"
@@ -42,7 +43,7 @@ func Test_serveBatch(t *testing.T) {
4243
name: "unrecognized operation",
4344
body: `{"operation": "update"}`,
4445
expStatusCode: http.StatusBadRequest,
45-
expBody: `{"message":"Operation not recognized"}` + "\n",
46+
expBody: `{"message": "Operation not recognized"}` + "\n",
4647
},
4748
{
4849
name: "upload: contains invalid oid",
@@ -53,7 +54,25 @@ func Test_serveBatch(t *testing.T) {
5354
{"oid": "ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f", "size": 123}
5455
]}`,
5556
expStatusCode: http.StatusOK,
56-
expBody: `{"transfer":"basic","objects":[{"oid":"bad_oid","size":123,"actions":{"error":{"code":422,"message":"Object has invalid oid"}}},{"oid":"ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f","size":123,"actions":{"upload":{"href":"https://gogs.example.com/owner/repo.git/info/lfs/objects/basic/ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f"},"verify":{"href":"https://gogs.example.com/owner/repo.git/info/lfs/objects/basic/verify"}}}]}` + "\n",
57+
expBody: `{
58+
"transfer": "basic",
59+
"objects": [
60+
{"oid": "bad_oid", "size":123, "actions": {"error": {"code": 422, "message": "Object has invalid oid"}}},
61+
{
62+
"oid": "ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f",
63+
"size": 123,
64+
"actions": {
65+
"upload": {
66+
"href": "https://gogs.example.com/owner/repo.git/info/lfs/objects/basic/ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f",
67+
"header": {"Content-Type": "application/octet-stream"}
68+
},
69+
"verify": {
70+
"href": "https://gogs.example.com/owner/repo.git/info/lfs/objects/basic/verify"
71+
}
72+
}
73+
}
74+
]
75+
}` + "\n",
5776
},
5877
{
5978
name: "download: contains non-existent oid and mismatched size",
@@ -78,7 +97,26 @@ func Test_serveBatch(t *testing.T) {
7897
},
7998
},
8099
expStatusCode: http.StatusOK,
81-
expBody: `{"transfer":"basic","objects":[{"oid":"bad_oid","size":123,"actions":{"error":{"code":404,"message":"Object does not exist"}}},{"oid":"ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f","size":123,"actions":{"error":{"code":422,"message":"Object size mismatch"}}},{"oid":"5cac0a318669fadfee734fb340a5f5b70b428ac57a9f4b109cb6e150b2ba7e57","size":456,"actions":{"download":{"href":"https://gogs.example.com/owner/repo.git/info/lfs/objects/basic/5cac0a318669fadfee734fb340a5f5b70b428ac57a9f4b109cb6e150b2ba7e57"}}}]}` + "\n",
100+
expBody: `{
101+
"transfer": "basic",
102+
"objects": [
103+
{"oid": "bad_oid", "size": 123, "actions": {"error": {"code": 404, "message": "Object does not exist"}}},
104+
{
105+
"oid": "ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f",
106+
"size": 123,
107+
"actions": {"error": {"code": 422, "message": "Object size mismatch"}}
108+
},
109+
{
110+
"oid": "5cac0a318669fadfee734fb340a5f5b70b428ac57a9f4b109cb6e150b2ba7e57",
111+
"size": 456,
112+
"actions": {
113+
"download": {
114+
"href": "https://gogs.example.com/owner/repo.git/info/lfs/objects/basic/5cac0a318669fadfee734fb340a5f5b70b428ac57a9f4b109cb6e150b2ba7e57"
115+
}
116+
}
117+
}
118+
]
119+
}` + "\n",
82120
},
83121
}
84122
for _, test := range tests {
@@ -100,7 +138,20 @@ func Test_serveBatch(t *testing.T) {
100138
if err != nil {
101139
t.Fatal(err)
102140
}
103-
assert.Equal(t, test.expBody, string(body))
141+
142+
var expBody bytes.Buffer
143+
err = json.Indent(&expBody, []byte(test.expBody), "", " ")
144+
if err != nil {
145+
t.Fatal(err)
146+
}
147+
148+
var gotBody bytes.Buffer
149+
err = json.Indent(&gotBody, body, "", " ")
150+
if err != nil {
151+
t.Fatal(err)
152+
}
153+
154+
assert.Equal(t, expBody.String(), gotBody.String())
104155
})
105156
}
106157
}

internal/route/lfs/route.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ func authorize(mode db.AccessMode) macaron.Handler {
135135
return
136136
}
137137

138+
log.Trace("[LFS] Authorized user %q to %q", actor.Name, username+"/"+reponame)
139+
138140
c.Map(owner) // NOTE: Override actor
139141
c.Map(repo)
140142
}
@@ -144,10 +146,15 @@ func authorize(mode db.AccessMode) macaron.Handler {
144146
// When not, response given "failCode" as status code.
145147
func verifyHeader(key, value string, failCode int) macaron.Handler {
146148
return func(c *macaron.Context) {
147-
if !strings.Contains(c.Req.Header.Get(key), value) {
148-
c.Status(failCode)
149-
return
149+
vals := c.Req.Header.Values(key)
150+
for _, val := range vals {
151+
if strings.Contains(val, value) {
152+
return
153+
}
150154
}
155+
156+
log.Trace("[LFS] HTTP header %q does not contain value %q", key, value)
157+
c.Status(failCode)
151158
}
152159
}
153160

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy