Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: handle parameters in Content-Type header #2055

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/api/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,7 @@ func (rh *RouteHandler) UpdateManifest(response http.ResponseWriter, request *ht
return
}

mediaType := request.Header.Get("Content-Type")
mediaType := zcommon.GetContentType(request)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two places in pkg/api/routes.go?
666: mediaType := request.Header.Get("Content-Type")
1219: if contentType := request.Header.Get("Content-Type"); contentType != constants.BinaryMediaType {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't sure about L1219. In spec it is specified for /v2/{name}/manifests/{reference} [put] (L666) that the parameters on the Content-Type header should be ignore , but for /v2/{name}/blobs/uploads [post] (L1219) there is no info about that. Do you think I should make the change also for L1219?

if !storageCommon.IsSupportedMediaType(mediaType) {
err := apiErr.NewError(apiErr.MANIFEST_INVALID).AddDetail(map[string]string{"mediaType": mediaType})
zcommon.WriteJSON(response, http.StatusUnsupportedMediaType, apiErr.NewErrorList(err))
Expand Down
30 changes: 27 additions & 3 deletions pkg/api/routes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"net/http/httptest"
Expand Down Expand Up @@ -211,12 +212,12 @@ func TestRoutes(t *testing.T) {
})

Convey("UpdateManifest ", func() {
testUpdateManifest := func(urlVars map[string]string, ism *mocks.MockedImageStore) int {
testUpdateManifest := func(urlVars map[string]string, contentType string, ism *mocks.MockedImageStore) int {
ctlr.StoreController.DefaultStore = ism
str := []byte("test")
request, _ := http.NewRequestWithContext(context.TODO(), http.MethodPut, baseURL, bytes.NewBuffer(str))
request = mux.SetURLVars(request, urlVars)
request.Header.Add("Content-Type", ispec.MediaTypeImageManifest)
request.Header.Add("Content-Type", contentType)
response := httptest.NewRecorder()

rthdlr.UpdateManifest(response, request)
Expand All @@ -226,12 +227,14 @@ func TestRoutes(t *testing.T) {

return resp.StatusCode
}
contentType := ispec.MediaTypeImageManifest
// repo not found
statusCode := testUpdateManifest(
map[string]string{
"name": "test",
"reference": "reference",
},
contentType,
&mocks.MockedImageStore{
PutImageManifestFn: func(repo, reference, mediaType string, body []byte) (godigest.Digest,
godigest.Digest, error,
Expand All @@ -246,7 +249,7 @@ func TestRoutes(t *testing.T) {
"name": "test",
"reference": "reference",
},

contentType,
&mocks.MockedImageStore{
PutImageManifestFn: func(repo, reference, mediaType string, body []byte) (godigest.Digest,
godigest.Digest, error,
Expand All @@ -261,6 +264,7 @@ func TestRoutes(t *testing.T) {
"name": "test",
"reference": "reference",
},
contentType,
&mocks.MockedImageStore{
PutImageManifestFn: func(repo, reference, mediaType string, body []byte) (godigest.Digest,
godigest.Digest, error,
Expand All @@ -275,6 +279,7 @@ func TestRoutes(t *testing.T) {
"name": "test",
"reference": "reference",
},
contentType,
&mocks.MockedImageStore{
PutImageManifestFn: func(repo, reference, mediaType string, body []byte) (godigest.Digest,
godigest.Digest, error,
Expand All @@ -290,6 +295,7 @@ func TestRoutes(t *testing.T) {
"name": "test",
"reference": "reference",
},
contentType,
&mocks.MockedImageStore{
PutImageManifestFn: func(repo, reference, mediaType string, body []byte) (godigest.Digest,
godigest.Digest, error,
Expand All @@ -298,6 +304,24 @@ func TestRoutes(t *testing.T) {
},
})
So(statusCode, ShouldEqual, http.StatusInternalServerError)

// multiple parameters in "Content-Type" header
contentType = fmt.Sprintf("%s; %s", ispec.MediaTypeImageManifest, "chartset=utf-8")
statusCode = testUpdateManifest(
map[string]string{
"name": "test",
"reference": "reference",
},
contentType,
&mocks.MockedImageStore{
PutImageManifestFn: func(repo, reference, mediaType string, body []byte) (godigest.Digest,
godigest.Digest, error,
) {
return "", "", nil
},
})
So(statusCode, ShouldNotEqual, http.StatusUnsupportedMediaType)
So(statusCode, ShouldEqual, http.StatusInternalServerError)
})

Convey("DeleteManifest", func() {
Expand Down
7 changes: 7 additions & 0 deletions pkg/common/http_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,3 +148,10 @@ func QueryHasParams(values url.Values, params []string) bool {

return true
}

func GetContentType(r *http.Request) string {
contentType := r.Header.Get("Content-Type")
contentTypeParams := strings.Split(contentType, ";")

return contentTypeParams[0]
}
Loading