diff --git a/endpoints/v2/manifest.py b/endpoints/v2/manifest.py index 4ed8331fd..37ea12953 100644 --- a/endpoints/v2/manifest.py +++ b/endpoints/v2/manifest.py @@ -15,7 +15,7 @@ from endpoints.v2 import v2_bp, require_repo_read, require_repo_write from endpoints.v2.errors import (ManifestInvalid, ManifestUnknown, NameInvalid, TagExpired, NameUnknown) from image.docker import ManifestException -from image.docker.schema1 import DOCKER_SCHEMA1_MANIFEST_CONTENT_TYPE +from image.docker.schema1 import DOCKER_SCHEMA1_MANIFEST_CONTENT_TYPE, DOCKER_SCHEMA1_CONTENT_TYPES from image.docker.schema2 import DOCKER_SCHEMA2_CONTENT_TYPES, OCI_CONTENT_TYPES from image.docker.schemas import parse_manifest_from_bytes from notifications import spawn_notification @@ -113,6 +113,12 @@ def _rewrite_schema_if_necessary(namespace_name, repo_name, tag_name, manifest): if manifest.media_type in mimetypes: return manifest.internal_manifest_bytes, manifest.digest, manifest.media_type + # Short-circuit check: If the mimetypes is empty or just `application/json`, verify we have + # a schema 1 manifest and return it. + if not mimetypes or mimetypes == ['application/json']: + if manifest.media_type in DOCKER_SCHEMA1_CONTENT_TYPES: + return manifest.internal_manifest_bytes, manifest.digest, manifest.media_type + logger.debug('Manifest `%s` not compatible against %s; checking for conversion', manifest.digest, request.accept_mimetypes) converted = registry_model.convert_manifest(manifest, namespace_name, repo_name, tag_name, diff --git a/test/registry/protocol_v2.py b/test/registry/protocol_v2.py index 1e2580202..01e8f12c6 100644 --- a/test/registry/protocol_v2.py +++ b/test/registry/protocol_v2.py @@ -208,7 +208,7 @@ class V2Protocol(RegistryProtocol): headers = { 'Authorization': 'Bearer ' + token, - 'Accept': ','.join(options.accept_mimetypes) if options.accept_mimetypes else '*/*', + 'Accept': ','.join(options.accept_mimetypes) if options.accept_mimetypes is not None else '*/*', } # Push all blobs. @@ -340,7 +340,7 @@ class V2Protocol(RegistryProtocol): headers = { 'Authorization': 'Bearer ' + token, - 'Accept': ','.join(options.accept_mimetypes) if options.accept_mimetypes else '*/*', + 'Accept': ','.join(options.accept_mimetypes) if options.accept_mimetypes is not None else '*/*', } # Build fake manifests. @@ -530,7 +530,9 @@ class V2Protocol(RegistryProtocol): } if self.schema2: - headers['Accept'] = ','.join(options.accept_mimetypes or DOCKER_SCHEMA2_CONTENT_TYPES) + headers['Accept'] = ','.join(options.accept_mimetypes + if options.accept_mimetypes is not None + else DOCKER_SCHEMA2_CONTENT_TYPES) manifests = {} image_ids = {} diff --git a/test/registry/registry_tests.py b/test/registry/registry_tests.py index ea5b0ffad..70980f6f1 100644 --- a/test/registry/registry_tests.py +++ b/test/registry/registry_tests.py @@ -1854,3 +1854,27 @@ def test_push_pull_emoji_unicode_direct(pusher, puller, unicode_emoji_images, li # Pull the repository to verify. puller.pull(liveserver_session, 'devtable', 'newrepo', 'latest', unicode_emoji_images, credentials=credentials, options=options) + + +@pytest.mark.parametrize('accepted_mimetypes', [ + [], + ['application/json'], +]) +def test_push_pull_older_mimetype(pusher, puller, basic_images, liveserver_session, app_reloader, + accepted_mimetypes): + """ Test: Push and pull an image, but override the accepted mimetypes to that sent by older + Docker clients. + """ + credentials = ('devtable', 'password') + + # Push a new repository. + pusher.push(liveserver_session, 'devtable', 'newrepo', 'latest', basic_images, + credentials=credentials) + + # Turn off automatic unicode encoding when building the manifests. + options = ProtocolOptions() + options.accept_mimetypes = accepted_mimetypes + + # Pull the repository to verify. + puller.pull(liveserver_session, 'devtable', 'newrepo', 'latest', basic_images, + credentials=credentials, options=options)