Skip to content

Commit 18dc41d

Browse files
GiteaBotwxiaoguang
andauthored
Fix "oras" OCI client compatibility (#34666) (#34671)
Backport #34666 by wxiaoguang Fix #25846 1. the ImageConfig can be empty, fall back to default 2. the blob size can be empty, it still needs "Content-Length" header Co-authored-by: wxiaoguang <[email protected]>
1 parent bf5d000 commit 18dc41d

File tree

4 files changed

+35
-8
lines changed

4 files changed

+35
-8
lines changed

modules/packages/container/metadata.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package container
55

66
import (
7+
"errors"
78
"fmt"
89
"io"
910
"strings"
@@ -83,7 +84,8 @@ func ParseImageConfig(mt string, r io.Reader) (*Metadata, error) {
8384

8485
func parseOCIImageConfig(r io.Reader) (*Metadata, error) {
8586
var image oci.Image
86-
if err := json.NewDecoder(r).Decode(&image); err != nil {
87+
// EOF means empty input, still use the default data
88+
if err := json.NewDecoder(r).Decode(&image); err != nil && !errors.Is(err, io.EOF) {
8789
return nil, err
8890
}
8991

modules/packages/container/metadata_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
oci "github.com/opencontainers/image-spec/specs-go/v1"
1313
"github.com/stretchr/testify/assert"
14+
"github.com/stretchr/testify/require"
1415
)
1516

1617
func TestParseImageConfig(t *testing.T) {
@@ -59,3 +60,9 @@ func TestParseImageConfig(t *testing.T) {
5960
assert.Equal(t, projectURL, metadata.ProjectURL)
6061
assert.Equal(t, repositoryURL, metadata.RepositoryURL)
6162
}
63+
64+
func TestParseOCIImageConfig(t *testing.T) {
65+
metadata, err := parseOCIImageConfig(strings.NewReader(""))
66+
require.NoError(t, err)
67+
assert.Equal(t, &Metadata{Type: TypeOCI, Platform: DefaultPlatform, ImageLayers: []string{}}, metadata)
68+
}

routers/api/packages/container/container.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"code.gitea.io/gitea/modules/httplib"
2222
"code.gitea.io/gitea/modules/json"
2323
"code.gitea.io/gitea/modules/log"
24+
"code.gitea.io/gitea/modules/optional"
2425
packages_module "code.gitea.io/gitea/modules/packages"
2526
container_module "code.gitea.io/gitea/modules/packages/container"
2627
"code.gitea.io/gitea/modules/setting"
@@ -50,7 +51,7 @@ type containerHeaders struct {
5051
Range string
5152
Location string
5253
ContentType string
53-
ContentLength int64
54+
ContentLength optional.Option[int64]
5455
}
5556

5657
// https://github.com/opencontainers/distribution-spec/blob/main/spec.md#legacy-docker-support-http-headers
@@ -64,8 +65,8 @@ func setResponseHeaders(resp http.ResponseWriter, h *containerHeaders) {
6465
if h.ContentType != "" {
6566
resp.Header().Set("Content-Type", h.ContentType)
6667
}
67-
if h.ContentLength != 0 {
68-
resp.Header().Set("Content-Length", strconv.FormatInt(h.ContentLength, 10))
68+
if h.ContentLength.Has() {
69+
resp.Header().Set("Content-Length", strconv.FormatInt(h.ContentLength.Value(), 10))
6970
}
7071
if h.UploadUUID != "" {
7172
resp.Header().Set("Docker-Upload-Uuid", h.UploadUUID)
@@ -505,7 +506,7 @@ func HeadBlob(ctx *context.Context) {
505506

506507
setResponseHeaders(ctx.Resp, &containerHeaders{
507508
ContentDigest: blob.Properties.GetByName(container_module.PropertyDigest),
508-
ContentLength: blob.Blob.Size,
509+
ContentLength: optional.Some(blob.Blob.Size),
509510
Status: http.StatusOK,
510511
})
511512
}
@@ -644,7 +645,7 @@ func HeadManifest(ctx *context.Context) {
644645
setResponseHeaders(ctx.Resp, &containerHeaders{
645646
ContentDigest: manifest.Properties.GetByName(container_module.PropertyDigest),
646647
ContentType: manifest.Properties.GetByName(container_module.PropertyMediaType),
647-
ContentLength: manifest.Blob.Size,
648+
ContentLength: optional.Some(manifest.Blob.Size),
648649
Status: http.StatusOK,
649650
})
650651
}
@@ -708,14 +709,14 @@ func serveBlob(ctx *context.Context, pfd *packages_model.PackageFileDescriptor)
708709
headers := &containerHeaders{
709710
ContentDigest: pfd.Properties.GetByName(container_module.PropertyDigest),
710711
ContentType: pfd.Properties.GetByName(container_module.PropertyMediaType),
711-
ContentLength: pfd.Blob.Size,
712+
ContentLength: optional.Some(pfd.Blob.Size),
712713
Status: http.StatusOK,
713714
}
714715

715716
if u != nil {
716717
headers.Status = http.StatusTemporaryRedirect
717718
headers.Location = u.String()
718-
headers.ContentLength = 0 // do not set Content-Length for redirect responses
719+
headers.ContentLength = optional.None[int64]() // do not set Content-Length for redirect responses
719720
setResponseHeaders(ctx.Resp, headers)
720721
return
721722
}

tests/integration/api_packages_container_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"bytes"
88
"crypto/sha256"
99
"encoding/base64"
10+
"encoding/hex"
1011
"fmt"
1112
"net/http"
1213
"strconv"
@@ -623,6 +624,22 @@ func TestPackageContainer(t *testing.T) {
623624
assert.Equal(t, blobContent, resp.Body.Bytes())
624625
})
625626

627+
t.Run("GetBlob/Empty", func(t *testing.T) {
628+
defer tests.PrintCurrentTest(t)()
629+
emptyDigestBuf := sha256.Sum256(nil)
630+
emptyDigest := "sha256:" + hex.EncodeToString(emptyDigestBuf[:])
631+
req := NewRequestWithBody(t, "POST", fmt.Sprintf("%s/blobs/uploads?digest=%s", url, emptyDigest), strings.NewReader("")).AddTokenAuth(userToken)
632+
MakeRequest(t, req, http.StatusCreated)
633+
634+
req = NewRequest(t, "HEAD", fmt.Sprintf("%s/blobs/%s", url, emptyDigest)).AddTokenAuth(userToken)
635+
resp := MakeRequest(t, req, http.StatusOK)
636+
assert.Equal(t, "0", resp.Header().Get("Content-Length"))
637+
638+
req = NewRequest(t, "GET", fmt.Sprintf("%s/blobs/%s", url, emptyDigest)).AddTokenAuth(userToken)
639+
resp = MakeRequest(t, req, http.StatusOK)
640+
assert.Equal(t, "0", resp.Header().Get("Content-Length"))
641+
})
642+
626643
t.Run("GetTagList", func(t *testing.T) {
627644
defer tests.PrintCurrentTest(t)()
628645

0 commit comments

Comments
 (0)