def _finalize_blob_storage(self, app_config): """ When an upload is successful, this ends the uploading process from the storage's perspective. Returns True if the blob already existed. """ computed_digest = digest_tools.sha256_digest_from_hashlib( self.blob_upload.sha_state) final_blob_location = digest_tools.content_path(computed_digest) # Close the database connection before we perform this operation, as it can take a while # and we shouldn't hold the connection during that time. with CloseForLongOperation(app_config): # Move the storage into place, or if this was a re-upload, cancel it already_existed = self.storage.exists( {self.blob_upload.location_name}, final_blob_location) if already_existed: # It already existed, clean up our upload which served as proof that the # uploader had the blob. self.storage.cancel_chunked_upload( {self.blob_upload.location_name}, self.blob_upload.upload_id, self.blob_upload.storage_metadata, ) else: # We were the first ones to upload this image (at least to this location) # Let's copy it into place self.storage.complete_chunked_upload( {self.blob_upload.location_name}, self.blob_upload.upload_id, final_blob_location, self.blob_upload.storage_metadata, ) return already_existed
def commit_to_blob(self, app_config, expected_digest=None): """ Commits the blob upload to a blob under the repository. The resulting blob will be marked to not be GCed for some period of time (as configured by `committed_blob_expiration`). If expected_digest is specified, the content digest of the data uploaded for the blob is compared to that given and, if it does not match, a BlobDigestMismatchException is raised. The digest given must be of type `Digest` and not a string. """ # Compare the content digest. if expected_digest is not None: self._validate_digest(expected_digest) # Finalize the storage. storage_already_existed = self._finalize_blob_storage(app_config) # Convert the upload to a blob. computed_digest_str = digest_tools.sha256_digest_from_hashlib( self.blob_upload.sha_state) with db_transaction(): blob = registry_model.commit_blob_upload( self.blob_upload, computed_digest_str, self.settings.committed_blob_expiration) if blob is None: return None self.committed_blob = blob return blob
def _validate_digest(self, expected_digest): """ Verifies that the digest's SHA matches that of the uploaded data. """ computed_digest = digest_tools.sha256_digest_from_hashlib( self.blob_upload.sha_state) if not digest_tools.digests_equal(computed_digest, expected_digest): logger.error( 'Digest mismatch for upload %s: Expected digest %s, found digest %s', self.blob_upload.upload_id, expected_digest, computed_digest) raise BlobDigestMismatchException()