From 5a2664e0b1e4f638f32687c7a9779f414b449583 Mon Sep 17 00:00:00 2001 From: Aaron Lehmann Date: Mon, 18 Jan 2016 09:59:50 -0800 Subject: [PATCH] Do not require "charset=utf-8" for a schema1 with content type application/json For compatibility with other registries that don't use this exact variant of the Content-Type header, we need to be more flexible about what we accept. Any form of "application/json" should be allowed. The charset should not be included in the comparison. See docker/docker#19400. Signed-off-by: Aaron Lehmann --- manifest/schema1/manifest.go | 2 +- manifests.go | 13 ++++++++++++- registry/handlers/api_test.go | 9 ++++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/manifest/schema1/manifest.go b/manifest/schema1/manifest.go index 98a7d817..4850d940 100644 --- a/manifest/schema1/manifest.go +++ b/manifest/schema1/manifest.go @@ -51,7 +51,7 @@ func init() { if err != nil { panic(fmt.Sprintf("Unable to register manifest: %s", err)) } - err = distribution.RegisterManifestSchema("application/json; charset=utf-8", schema1Func) + err = distribution.RegisterManifestSchema("application/json", schema1Func) if err != nil { panic(fmt.Sprintf("Unable to register manifest: %s", err)) } diff --git a/manifests.go b/manifests.go index 1f93812d..aec28e97 100644 --- a/manifests.go +++ b/manifests.go @@ -2,6 +2,7 @@ package distribution import ( "fmt" + "strings" "github.com/docker/distribution/context" "github.com/docker/distribution/digest" @@ -80,7 +81,17 @@ var mappings = make(map[string]UnmarshalFunc, 0) // UnmarshalManifest looks up manifest unmarshall functions based on // MediaType -func UnmarshalManifest(mediatype string, p []byte) (Manifest, Descriptor, error) { +func UnmarshalManifest(ctHeader string, p []byte) (Manifest, Descriptor, error) { + // Need to look up by the actual content type, not the raw contents of + // the header. Strip semicolons and anything following them. + var mediatype string + semicolonIndex := strings.Index(ctHeader, ";") + if semicolonIndex != -1 { + mediatype = ctHeader[:semicolonIndex] + } else { + mediatype = ctHeader + } + unmarshalFunc, ok := mappings[mediatype] if !ok { return nil, Descriptor{}, fmt.Errorf("unsupported manifest mediatype: %s", mediatype) diff --git a/registry/handlers/api_test.go b/registry/handlers/api_test.go index a1aac3cd..f3f5a4fb 100644 --- a/registry/handlers/api_test.go +++ b/registry/handlers/api_test.go @@ -954,7 +954,14 @@ func testManifestAPISchema1(t *testing.T, env *testEnv, imageName string) manife } - resp = putManifest(t, "re-putting signed manifest", manifestDigestURL, "", sm2) + // Re-push with a few different Content-Types. The official schema1 + // content type should work, as should application/json with/without a + // charset. + resp = putManifest(t, "re-putting signed manifest", manifestDigestURL, schema1.MediaTypeManifest, sm2) + checkResponse(t, "re-putting signed manifest", resp, http.StatusCreated) + resp = putManifest(t, "re-putting signed manifest", manifestDigestURL, "application/json; charset=utf-8", sm2) + checkResponse(t, "re-putting signed manifest", resp, http.StatusCreated) + resp = putManifest(t, "re-putting signed manifest", manifestDigestURL, "application/json", sm2) checkResponse(t, "re-putting signed manifest", resp, http.StatusCreated) resp, err = http.Get(manifestDigestURL)