Add an additional short circuit to avoid parsing the manifest when not necessary for older Docker clients

We also add tests for this case
This commit is contained in:
Joseph Schorr 2019-01-11 16:37:23 -05:00
parent 7f068c3fc3
commit e78b5c5516
3 changed files with 36 additions and 4 deletions

View file

@ -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, from endpoints.v2.errors import (ManifestInvalid, ManifestUnknown, NameInvalid, TagExpired,
NameUnknown) NameUnknown)
from image.docker import ManifestException 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.schema2 import DOCKER_SCHEMA2_CONTENT_TYPES, OCI_CONTENT_TYPES
from image.docker.schemas import parse_manifest_from_bytes from image.docker.schemas import parse_manifest_from_bytes
from notifications import spawn_notification 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: if manifest.media_type in mimetypes:
return manifest.internal_manifest_bytes, manifest.digest, manifest.media_type 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, logger.debug('Manifest `%s` not compatible against %s; checking for conversion', manifest.digest,
request.accept_mimetypes) request.accept_mimetypes)
converted = registry_model.convert_manifest(manifest, namespace_name, repo_name, tag_name, converted = registry_model.convert_manifest(manifest, namespace_name, repo_name, tag_name,

View file

@ -208,7 +208,7 @@ class V2Protocol(RegistryProtocol):
headers = { headers = {
'Authorization': 'Bearer ' + token, '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. # Push all blobs.
@ -340,7 +340,7 @@ class V2Protocol(RegistryProtocol):
headers = { headers = {
'Authorization': 'Bearer ' + token, '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. # Build fake manifests.
@ -530,7 +530,9 @@ class V2Protocol(RegistryProtocol):
} }
if self.schema2: 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 = {} manifests = {}
image_ids = {} image_ids = {}

View file

@ -1854,3 +1854,27 @@ def test_push_pull_emoji_unicode_direct(pusher, puller, unicode_emoji_images, li
# Pull the repository to verify. # Pull the repository to verify.
puller.pull(liveserver_session, 'devtable', 'newrepo', 'latest', unicode_emoji_images, puller.pull(liveserver_session, 'devtable', 'newrepo', 'latest', unicode_emoji_images,
credentials=credentials, options=options) 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)