Skip to content

Commit 898f852

Browse files
authored
Fix missing signature key error when pulling Docker images with SERVE_DIRECT enabled (#32365) (#32397)
Backport #32365 Fix #28121 I did some tests and found that the `missing signature key` error is caused by an incorrect `Content-Type` header. Gitea correctly sets the `Content-Type` header when serving files. https://github.com/go-gitea/gitea/blob/348d1d0f322ca57c459acd902f54821d687ca804/routers/api/packages/container/container.go#L712-L717 However, when `SERVE_DIRECT` is enabled, the `Content-Type` header may be set to an incorrect value by the storage service. To fix this issue, we can use query parameters to override response header values. https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html <img width="600px" src="https://github.com/user-attachments/assets/f2ff90f0-f1df-46f9-9680-b8120222c555" /> In this PR, I introduced a new parameter to the `URL` method to support additional parameters. ``` URL(path, name string, reqParams url.Values) (*url.URL, error) ```
1 parent 9d62d7a commit 898f852

File tree

18 files changed

+29
-23
lines changed

18 files changed

+29
-23
lines changed

modules/packages/content_store.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ func (s *ContentStore) ShouldServeDirect() bool {
3737
return setting.Packages.Storage.MinioConfig.ServeDirect
3838
}
3939

40-
func (s *ContentStore) GetServeDirectURL(key BlobHash256Key, filename string) (*url.URL, error) {
41-
return s.store.URL(KeyToRelativePath(key), filename)
40+
func (s *ContentStore) GetServeDirectURL(key BlobHash256Key, filename string, reqParams url.Values) (*url.URL, error) {
41+
return s.store.URL(KeyToRelativePath(key), filename, reqParams)
4242
}
4343

4444
// FIXME: Workaround to be removed in v1.20

modules/storage/helper.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func (s discardStorage) Delete(_ string) error {
3030
return fmt.Errorf("%s", s)
3131
}
3232

33-
func (s discardStorage) URL(_, _ string) (*url.URL, error) {
33+
func (s discardStorage) URL(_, _ string, _ url.Values) (*url.URL, error) {
3434
return nil, fmt.Errorf("%s", s)
3535
}
3636

modules/storage/helper_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func Test_discardStorage(t *testing.T) {
3737
assert.Error(t, err, string(tt))
3838
}
3939
{
40-
got, err := tt.URL("path", "name")
40+
got, err := tt.URL("path", "name", nil)
4141
assert.Nil(t, got)
4242
assert.Errorf(t, err, string(tt))
4343
}

modules/storage/local.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ func (l *LocalStorage) Delete(path string) error {
114114
}
115115

116116
// URL gets the redirect URL to a file
117-
func (l *LocalStorage) URL(path, name string) (*url.URL, error) {
117+
func (l *LocalStorage) URL(path, name string, reqParams url.Values) (*url.URL, error) {
118118
return nil, ErrURLNotSupported
119119
}
120120

modules/storage/minio.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -235,8 +235,12 @@ func (m *MinioStorage) Delete(path string) error {
235235
}
236236

237237
// URL gets the redirect URL to a file. The presigned link is valid for 5 minutes.
238-
func (m *MinioStorage) URL(path, name string) (*url.URL, error) {
239-
reqParams := make(url.Values)
238+
func (m *MinioStorage) URL(path, name string, serveDirectReqParams url.Values) (*url.URL, error) {
239+
// copy serveDirectReqParams
240+
reqParams, err := url.ParseQuery(serveDirectReqParams.Encode())
241+
if err != nil {
242+
return nil, err
243+
}
240244
// TODO it may be good to embed images with 'inline' like ServeData does, but we don't want to have to read the file, do we?
241245
reqParams.Set("response-content-disposition", "attachment; filename=\""+quoteEscaper.Replace(name)+"\"")
242246
u, err := m.client.PresignedGetObject(m.ctx, m.bucket, m.buildMinioPath(path), 5*time.Minute, reqParams)

modules/storage/storage.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ type ObjectStorage interface {
6363
Save(path string, r io.Reader, size int64) (int64, error)
6464
Stat(path string) (os.FileInfo, error)
6565
Delete(path string) error
66-
URL(path, name string) (*url.URL, error)
66+
URL(path, name string, reqParams url.Values) (*url.URL, error)
6767
IterateObjects(path string, iterator func(path string, obj Object) error) error
6868
}
6969

routers/api/actions/artifacts.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ func (ar artifactRoutes) getDownloadArtifactURL(ctx *ArtifactContext) {
429429
for _, artifact := range artifacts {
430430
var downloadURL string
431431
if setting.Actions.ArtifactStorage.MinioConfig.ServeDirect {
432-
u, err := ar.fs.URL(artifact.StoragePath, artifact.ArtifactName)
432+
u, err := ar.fs.URL(artifact.StoragePath, artifact.ArtifactName, nil)
433433
if err != nil && !errors.Is(err, storage.ErrURLNotSupported) {
434434
log.Error("Error getting serve direct url: %v", err)
435435
}

routers/api/actions/artifactsv4.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ func (r *artifactV4Routes) getSignedArtifactURL(ctx *ArtifactContext) {
449449
respData := GetSignedArtifactURLResponse{}
450450

451451
if setting.Actions.ArtifactStorage.MinioConfig.ServeDirect {
452-
u, err := storage.ActionsArtifacts.URL(artifact.StoragePath, artifact.ArtifactPath)
452+
u, err := storage.ActionsArtifacts.URL(artifact.StoragePath, artifact.ArtifactPath, nil)
453453
if u != nil && err == nil {
454454
respData.SignedUrl = u.String()
455455
}

routers/api/packages/container/container.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -715,7 +715,9 @@ func DeleteManifest(ctx *context.Context) {
715715
}
716716

717717
func serveBlob(ctx *context.Context, pfd *packages_model.PackageFileDescriptor) {
718-
s, u, _, err := packages_service.GetPackageBlobStream(ctx, pfd.File, pfd.Blob)
718+
serveDirectReqParams := make(url.Values)
719+
serveDirectReqParams.Set("response-content-type", pfd.Properties.GetByName(container_module.PropertyMediaType))
720+
s, u, _, err := packages_service.GetPackageBlobStream(ctx, pfd.File, pfd.Blob, serveDirectReqParams)
719721
if err != nil {
720722
apiError(ctx, http.StatusInternalServerError, err)
721723
return

routers/api/packages/maven/maven.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ func servePackageFile(ctx *context.Context, params parameters, serveContent bool
215215
return
216216
}
217217

218-
s, u, _, err := packages_service.GetPackageBlobStream(ctx, pf, pb)
218+
s, u, _, err := packages_service.GetPackageBlobStream(ctx, pf, pb, nil)
219219
if err != nil {
220220
apiError(ctx, http.StatusInternalServerError, err)
221221
return

routers/api/v1/repo/file.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ func GetRawFileOrLFS(ctx *context.APIContext) {
203203

204204
if setting.LFS.Storage.MinioConfig.ServeDirect {
205205
// If we have a signed url (S3, object storage), redirect to this directly.
206-
u, err := storage.LFS.URL(pointer.RelativePath(), blob.Name())
206+
u, err := storage.LFS.URL(pointer.RelativePath(), blob.Name(), nil)
207207
if u != nil && err == nil {
208208
ctx.Redirect(u.String())
209209
return
@@ -328,7 +328,7 @@ func download(ctx *context.APIContext, archiveName string, archiver *repo_model.
328328
rPath := archiver.RelativePath()
329329
if setting.RepoArchive.Storage.MinioConfig.ServeDirect {
330330
// If we have a signed url (S3, object storage), redirect to this directly.
331-
u, err := storage.RepoArchives.URL(rPath, downloadName)
331+
u, err := storage.RepoArchives.URL(rPath, downloadName, nil)
332332
if u != nil && err == nil {
333333
ctx.Redirect(u.String())
334334
return

routers/web/base.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func storageHandler(storageSetting *setting.Storage, prefix string, objStore sto
3939
rPath := strings.TrimPrefix(req.URL.Path, "/"+prefix+"/")
4040
rPath = util.PathJoinRelX(rPath)
4141

42-
u, err := objStore.URL(rPath, path.Base(rPath))
42+
u, err := objStore.URL(rPath, path.Base(rPath), nil)
4343
if err != nil {
4444
if os.IsNotExist(err) || errors.Is(err, os.ErrNotExist) {
4545
log.Warn("Unable to find %s %s", prefix, rPath)

routers/web/repo/actions/view.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,7 @@ func ArtifactsDownloadView(ctx *context_module.Context) {
626626
if len(artifacts) == 1 && artifacts[0].ArtifactName+".zip" == artifacts[0].ArtifactPath && artifacts[0].ContentEncoding == "application/zip" {
627627
art := artifacts[0]
628628
if setting.Actions.ArtifactStorage.MinioConfig.ServeDirect {
629-
u, err := storage.ActionsArtifacts.URL(art.StoragePath, art.ArtifactPath)
629+
u, err := storage.ActionsArtifacts.URL(art.StoragePath, art.ArtifactPath, nil)
630630
if u != nil && err == nil {
631631
ctx.Redirect(u.String())
632632
return

routers/web/repo/attachment.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ func ServeAttachment(ctx *context.Context, uuid string) {
129129

130130
if setting.Attachment.Storage.MinioConfig.ServeDirect {
131131
// If we have a signed url (S3, object storage), redirect to this directly.
132-
u, err := storage.Attachments.URL(attach.RelativePath(), attach.Name)
132+
u, err := storage.Attachments.URL(attach.RelativePath(), attach.Name, nil)
133133

134134
if u != nil && err == nil {
135135
ctx.Redirect(u.String())

routers/web/repo/download.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ func ServeBlobOrLFS(ctx *context.Context, blob *git.Blob, lastModified *time.Tim
5555

5656
if setting.LFS.Storage.MinioConfig.ServeDirect {
5757
// If we have a signed url (S3, object storage), redirect to this directly.
58-
u, err := storage.LFS.URL(pointer.RelativePath(), blob.Name())
58+
u, err := storage.LFS.URL(pointer.RelativePath(), blob.Name(), nil)
5959
if u != nil && err == nil {
6060
ctx.Redirect(u.String())
6161
return nil

routers/web/repo/repo.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,7 @@ func download(ctx *context.Context, archiveName string, archiver *repo_model.Rep
494494
rPath := archiver.RelativePath()
495495
if setting.RepoArchive.Storage.MinioConfig.ServeDirect {
496496
// If we have a signed url (S3, object storage), redirect to this directly.
497-
u, err := storage.RepoArchives.URL(rPath, downloadName)
497+
u, err := storage.RepoArchives.URL(rPath, downloadName, nil)
498498
if u != nil && err == nil {
499499
ctx.Redirect(u.String())
500500
return

services/lfs/server.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ func buildObjectResponse(rc *requestContext, pointer lfs_module.Pointer, downloa
455455
var link *lfs_module.Link
456456
if setting.LFS.Storage.MinioConfig.ServeDirect {
457457
// If we have a signed url (S3, object storage), redirect to this directly.
458-
u, err := storage.LFS.URL(pointer.RelativePath(), pointer.Oid)
458+
u, err := storage.LFS.URL(pointer.RelativePath(), pointer.Oid, nil)
459459
if u != nil && err == nil {
460460
// Presigned url does not need the Authorization header
461461
// https://github.com/go-gitea/gitea/issues/21525

services/packages/packages.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -596,12 +596,12 @@ func GetPackageFileStream(ctx context.Context, pf *packages_model.PackageFile) (
596596
return nil, nil, nil, err
597597
}
598598

599-
return GetPackageBlobStream(ctx, pf, pb)
599+
return GetPackageBlobStream(ctx, pf, pb, nil)
600600
}
601601

602602
// GetPackageBlobStream returns the content of the specific package blob
603603
// If the storage supports direct serving and it's enabled, only the direct serving url is returned.
604-
func GetPackageBlobStream(ctx context.Context, pf *packages_model.PackageFile, pb *packages_model.PackageBlob) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
604+
func GetPackageBlobStream(ctx context.Context, pf *packages_model.PackageFile, pb *packages_model.PackageBlob, serveDirectReqParams url.Values) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
605605
key := packages_module.BlobHash256Key(pb.HashSHA256)
606606

607607
cs := packages_module.NewContentStore()
@@ -611,7 +611,7 @@ func GetPackageBlobStream(ctx context.Context, pf *packages_model.PackageFile, p
611611
var err error
612612

613613
if cs.ShouldServeDirect() {
614-
u, err = cs.GetServeDirectURL(key, pf.Name)
614+
u, err = cs.GetServeDirectURL(key, pf.Name, serveDirectReqParams)
615615
if err != nil && !errors.Is(err, storage.ErrURLNotSupported) {
616616
log.Error("Error getting serve direct url: %v", err)
617617
}

0 commit comments

Comments
 (0)