Have blob uploads be checked against configurable max layer size

This commit is contained in:
Joseph Schorr 2017-02-27 13:32:09 -05:00
parent dd35677712
commit dd7f254f96
4 changed files with 32 additions and 1 deletions

View file

@ -4,6 +4,7 @@ import time
from flask import url_for, request, redirect, Response, abort as flask_abort from flask import url_for, request, redirect, Response, abort as flask_abort
import bitmath
import resumablehashlib import resumablehashlib
from app import storage, app, get_app_url, metric_queue from app import storage, app, get_app_url, metric_queue
@ -14,7 +15,7 @@ from digest import digest_tools
from endpoints.common import parse_repository_name from endpoints.common import parse_repository_name
from endpoints.v2 import v2_bp, require_repo_read, require_repo_write, get_input_stream from endpoints.v2 import v2_bp, require_repo_read, require_repo_write, get_input_stream
from endpoints.v2.errors import (BlobUnknown, BlobUploadInvalid, BlobUploadUnknown, Unsupported, from endpoints.v2.errors import (BlobUnknown, BlobUploadInvalid, BlobUploadUnknown, Unsupported,
NameUnknown) NameUnknown, LayerTooLarge)
from endpoints.decorators import anon_protect from endpoints.decorators import anon_protect
from util.cache import cache_control from util.cache import cache_control
from util.registry.filelike import wrap_with_handler, StreamSlice from util.registry.filelike import wrap_with_handler, StreamSlice
@ -346,6 +347,8 @@ def _upload_chunk(blob_upload, range_header):
Returns a BlobUpload object or None if there was a failure. Returns a BlobUpload object or None if there was a failure.
""" """
max_layer_size = bitmath.parse_string_unsafe(app.config['MAXIMUM_LAYER_SIZE'])
# Get the offset and length of the current chunk. # Get the offset and length of the current chunk.
start_offset, length = _start_offset_and_length(range_header) start_offset, length = _start_offset_and_length(range_header)
if blob_upload is None or None in {start_offset, length}: if blob_upload is None or None in {start_offset, length}:
@ -356,6 +359,16 @@ def _upload_chunk(blob_upload, range_header):
logger.error('start_offset provided to _upload_chunk greater than blob.upload.byte_count') logger.error('start_offset provided to _upload_chunk greater than blob.upload.byte_count')
return None return None
# Check if we should raise 413 before accepting the data.
uploaded = bitmath.Byte(length + start_offset)
if length > -1 and uploaded > max_layer_size:
detail = {
'reason': '%s is greater than maximum allowed size %s' % (uploaded, max_layer_size),
'max_allowed': max_layer_size.bytes,
'uploaded': uploaded.bytes,
}
raise LayerTooLarge(detail=detail)
location_set = {blob_upload.location_name} location_set = {blob_upload.location_name}
upload_error = None upload_error = None
@ -435,6 +448,16 @@ def _upload_chunk(blob_upload, range_header):
blob_upload.byte_count += length_written blob_upload.byte_count += length_written
blob_upload.chunk_count += 1 blob_upload.chunk_count += 1
# Ensure we have not gone beyond the max layer size.
upload_size = bitmath.Byte(blob_upload.byte_count)
if upload_size > max_layer_size:
detail = {
'reason': '%s is greater than maximum allowed size %s' % (upload_size, max_layer_size),
'max_allowed': max_layer_size.bytes,
'uploaded': upload_size.bytes,
}
raise LayerTooLarge(detail=detail)
return blob_upload return blob_upload

View file

@ -112,6 +112,12 @@ class TagInvalid(V2RegistryException):
'manifest tag did not match URI', 'manifest tag did not match URI',
detail) detail)
class LayerTooLarge(V2RegistryException):
def __init__(self, detail=None):
super(LayerTooLarge, self).__init__('BLOB_UPLOAD_INVALID',
'Uploaded layer is larger than allowed by this registry',
detail)
class Unauthorized(V2RegistryException): class Unauthorized(V2RegistryException):
def __init__(self, detail=None, repository=None, scopes=None): def __init__(self, detail=None, repository=None, scopes=None):

View file

@ -20,6 +20,7 @@ autobahn==0.9.3-3
beautifulsoup4 beautifulsoup4
bencode bencode
bintrees bintrees
bitmath
boto boto
cachetools==1.1.6 cachetools==1.1.6
cryptography cryptography

View file

@ -8,6 +8,7 @@ Babel==2.3.4
beautifulsoup4==4.5.1 beautifulsoup4==4.5.1
bencode==1.0 bencode==1.0
bintrees==2.0.4 bintrees==2.0.4
bitmath==1.3.1.2
blinker==1.4 blinker==1.4
boto==2.43.0 boto==2.43.0
cachetools==1.1.6 cachetools==1.1.6