1# -------------------------------------------------------------------------
2# Copyright (c) Microsoft Corporation. All rights reserved.
3# Licensed under the MIT License. See License.txt in the project root for
4# license information.
5# --------------------------------------------------------------------------
6import sys
7from os import path
8
9from azure.storage.common._common_conversion import (
10    _int_to_str,
11    _to_str,
12    _datetime_to_utc_string,
13    _get_content_md5,
14)
15from azure.storage.common._constants import (
16    SERVICE_HOST_BASE,
17    DEFAULT_PROTOCOL,
18)
19from azure.storage.common._error import (
20    _validate_not_none,
21    _validate_type_bytes,
22    _validate_encryption_required,
23    _validate_encryption_unsupported,
24    _ERROR_VALUE_NEGATIVE,
25)
26from azure.storage.common._http import HTTPRequest
27from azure.storage.common._serialization import (
28    _get_data_bytes_only,
29    _add_metadata_headers,
30)
31from ._deserialization import (
32    _convert_xml_to_page_ranges,
33    _parse_page_properties,
34    _parse_base_properties,
35)
36from ._encryption import _generate_blob_encryption_data
37from ._error import (
38    _ERROR_PAGE_BLOB_SIZE_ALIGNMENT,
39)
40from ._serialization import (
41    _get_path,
42    _validate_and_format_range_headers,
43    _validate_and_add_cpk_headers,
44)
45from ._upload_chunking import (
46    _PageBlobChunkUploader,
47    _upload_blob_chunks,
48)
49from .baseblobservice import BaseBlobService
50from .models import (
51    _BlobTypes,
52    ResourceProperties)
53
54if sys.version_info >= (3,):
55    from io import BytesIO
56else:
57    from cStringIO import StringIO as BytesIO
58
59# Keep this value sync with _ERROR_PAGE_BLOB_SIZE_ALIGNMENT
60_PAGE_ALIGNMENT = 512
61
62
63class PageBlobService(BaseBlobService):
64    '''
65    Page blobs are a collection of 512-byte pages optimized for random read and
66    write operations. To create a page blob, you initialize the page blob and
67    specify the maximum size the page blob will grow. To add or update the
68    contents of a page blob, you write a page or pages by specifying an offset
69    and a range that align to 512-byte page boundaries. A write to a page blob
70    can overwrite just one page, some pages, or up to 4 MB of the page blob.
71    Writes to page blobs happen in-place and are immediately committed to the
72    blob. The maximum size for a page blob is 8 TB.
73
74    :ivar int MAX_PAGE_SIZE:
75        The size of the pages put by create_blob_from_* methods. Smaller pages
76        may be put if there is less data provided. The maximum page size the service
77        supports is 4MB. When using the create_blob_from_* methods, empty pages are skipped.
78    '''
79
80    MAX_PAGE_SIZE = 4 * 1024 * 1024
81
82    def __init__(self, account_name=None, account_key=None, sas_token=None, is_emulated=False,
83                 protocol=DEFAULT_PROTOCOL, endpoint_suffix=SERVICE_HOST_BASE, custom_domain=None,
84                 request_session=None, connection_string=None, socket_timeout=None, token_credential=None):
85        '''
86        :param str account_name:
87            The storage account name. This is used to authenticate requests
88            signed with an account key and to construct the storage endpoint. It
89            is required unless a connection string is given, or if a custom
90            domain is used with anonymous authentication.
91        :param str account_key:
92            The storage account key. This is used for shared key authentication.
93            If neither account key or sas token is specified, anonymous access
94            will be used.
95        :param str sas_token:
96             A shared access signature token to use to authenticate requests
97             instead of the account key. If account key and sas token are both
98             specified, account key will be used to sign. If neither are
99             specified, anonymous access will be used.
100        :param bool is_emulated:
101            Whether to use the emulator. Defaults to False. If specified, will
102            override all other parameters besides connection string and request
103            session.
104        :param str protocol:
105            The protocol to use for requests. Defaults to https.
106        :param str endpoint_suffix:
107            The host base component of the url, minus the account name. Defaults
108            to Azure (core.windows.net). Override this to use the China cloud
109            (core.chinacloudapi.cn).
110        :param str custom_domain:
111            The custom domain to use. This can be set in the Azure Portal. For
112            example, 'www.mydomain.com'.
113        :param requests.Session request_session:
114            The session object to use for http requests.
115        :param str connection_string:
116            If specified, this will override all other parameters besides
117            request session. See
118            http://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/
119            for the connection string format.
120        :param int socket_timeout:
121            If specified, this will override the default socket timeout. The timeout specified is in seconds.
122            See DEFAULT_SOCKET_TIMEOUT in _constants.py for the default value.
123        :param token_credential:
124            A token credential used to authenticate HTTPS requests. The token value
125            should be updated before its expiration.
126        :type `~azure.storage.common.TokenCredential`
127        '''
128        self.blob_type = _BlobTypes.PageBlob
129        super(PageBlobService, self).__init__(
130            account_name, account_key, sas_token, is_emulated, protocol, endpoint_suffix,
131            custom_domain, request_session, connection_string, socket_timeout, token_credential)
132
133    def create_blob(
134            self, container_name, blob_name, content_length, content_settings=None,
135            sequence_number=None, metadata=None, lease_id=None, if_modified_since=None,
136            if_unmodified_since=None, if_match=None, if_none_match=None, timeout=None,
137            premium_page_blob_tier=None, cpk=None):
138        '''
139        Creates a new Page Blob.
140
141        See create_blob_from_* for high level functions that handle the
142        creation and upload of large blobs with automatic chunking and
143        progress notifications.
144
145        :param str container_name:
146            Name of existing container.
147        :param str blob_name:
148            Name of blob to create or update.
149        :param int content_length:
150            Required. This header specifies the maximum size
151            for the page blob, up to 1 TB. The page blob size must be aligned
152            to a 512-byte boundary.
153        :param ~azure.storage.blob.models.ContentSettings content_settings:
154            ContentSettings object used to set properties on the blob.
155        :param int sequence_number:
156            The sequence number is a user-controlled value that you can use to
157            track requests. The value of the sequence number must be between 0
158            and 2^63 - 1.The default value is 0.
159        :param metadata:
160            Name-value pairs associated with the blob as metadata.
161        :type metadata: dict(str, str)
162        :param str lease_id:
163            Required if the blob has an active lease.
164        :param datetime if_modified_since:
165            A DateTime value. Azure expects the date value passed in to be UTC.
166            If timezone is included, any non-UTC datetimes will be converted to UTC.
167            If a date is passed in without timezone info, it is assumed to be UTC.
168            Specify this header to perform the operation only
169            if the resource has been modified since the specified time.
170        :param datetime if_unmodified_since:
171            A DateTime value. Azure expects the date value passed in to be UTC.
172            If timezone is included, any non-UTC datetimes will be converted to UTC.
173            If a date is passed in without timezone info, it is assumed to be UTC.
174            Specify this header to perform the operation only if
175            the resource has not been modified since the specified date/time.
176        :param str if_match:
177            An ETag value, or the wildcard character (*). Specify this header to perform
178            the operation only if the resource's ETag matches the value specified.
179        :param str if_none_match:
180            An ETag value, or the wildcard character (*). Specify this header
181            to perform the operation only if the resource's ETag does not match
182            the value specified. Specify the wildcard character (*) to perform
183            the operation only if the resource does not exist, and fail the
184            operation if it does exist.
185        :param int timeout:
186            The timeout parameter is expressed in seconds.
187        :param PremiumPageBlobTier premium_page_blob_tier:
188            A page blob tier value to set the blob to. The tier correlates to the size of the
189            blob and number of allowed IOPS. This is only applicable to page blobs on
190            premium storage accounts.
191        :param ~azure.storage.blob.models.CustomerProvidedEncryptionKey cpk:
192            Encrypts the data on the service-side with the given key.
193            Use of customer-provided keys must be done over HTTPS.
194            As the encryption key itself is provided in the request,
195            a secure connection must be established to transfer the key.
196        :return: ETag and last modified properties for the new Page Blob
197        :rtype: :class:`~azure.storage.blob.models.ResourceProperties`
198        '''
199        _validate_encryption_unsupported(self.require_encryption, self.key_encryption_key)
200
201        return self._create_blob(
202            container_name,
203            blob_name,
204            content_length,
205            content_settings=content_settings,
206            sequence_number=sequence_number,
207            metadata=metadata,
208            lease_id=lease_id,
209            premium_page_blob_tier=premium_page_blob_tier,
210            if_modified_since=if_modified_since,
211            if_unmodified_since=if_unmodified_since,
212            if_match=if_match,
213            if_none_match=if_none_match,
214            timeout=timeout,
215            cpk=cpk,
216        )
217
218    def incremental_copy_blob(self, container_name, blob_name, copy_source,
219                              metadata=None, destination_if_modified_since=None, destination_if_unmodified_since=None,
220                              destination_if_match=None, destination_if_none_match=None, destination_lease_id=None,
221                              source_lease_id=None, timeout=None):
222        '''
223        Copies an incremental copy of a blob asynchronously. This operation returns a copy operation
224        properties object, including a copy ID you can use to check or abort the
225        copy operation. The Blob service copies blobs on a best-effort basis.
226
227        The source blob for an incremental copy operation must be a page blob.
228        Call get_blob_properties on the destination blob to check the status of the copy operation.
229        The final blob will be committed when the copy completes.
230
231        :param str container_name:
232            Name of the destination container. The container must exist.
233        :param str blob_name:
234            Name of the destination blob. If the destination blob exists, it will
235            be overwritten. Otherwise, it will be created.
236        :param str copy_source:
237            A URL of up to 2 KB in length that specifies an Azure page blob.
238            The value should be URL-encoded as it would appear in a request URI.
239            The copy source must be a snapshot and include a valid SAS token or be public.
240            Example:
241            https://myaccount.blob.core.windows.net/mycontainer/myblob?snapshot=<DateTime>&sastoken
242        :param metadata:
243            Name-value pairs associated with the blob as metadata. If no name-value
244            pairs are specified, the operation will copy the metadata from the
245            source blob or file to the destination blob. If one or more name-value
246            pairs are specified, the destination blob is created with the specified
247            metadata, and metadata is not copied from the source blob or file.
248        :type metadata: dict(str, str).
249        :param datetime destination_if_modified_since:
250            A DateTime value. Azure expects the date value passed in to be UTC.
251            If timezone is included, any non-UTC datetimes will be converted to UTC.
252            If a date is passed in without timezone info, it is assumed to be UTC.
253            Specify this conditional header to copy the blob only
254            if the destination blob has been modified since the specified date/time.
255            If the destination blob has not been modified, the Blob service returns
256            status code 412 (Precondition Failed).
257        :param datetime destination_if_unmodified_since:
258            A DateTime value. Azure expects the date value passed in to be UTC.
259            If timezone is included, any non-UTC datetimes will be converted to UTC.
260            If a date is passed in without timezone info, it is assumed to be UTC.
261            Specify this conditional header to copy the blob only if the destination blob
262            has not been modified since the specified ate/time. If the destination blob
263            has been modified, the Blob service returns status code 412 (Precondition Failed).
264        :param ETag destination_if_match:
265            An ETag value, or the wildcard character (*). Specify an ETag value for
266            this conditional header to copy the blob only if the specified ETag value
267            matches the ETag value for an existing destination blob. If the ETag for
268            the destination blob does not match the ETag specified for If-Match, the
269            Blob service returns status code 412 (Precondition Failed).
270        :param ETag destination_if_none_match:
271            An ETag value, or the wildcard character (*). Specify an ETag value for
272            this conditional header to copy the blob only if the specified ETag value
273            does not match the ETag value for the destination blob. Specify the wildcard
274            character (*) to perform the operation only if the destination blob does not
275            exist. If the specified condition isn't met, the Blob service returns status
276            code 412 (Precondition Failed).
277        :param str destination_lease_id:
278            The lease ID specified for this header must match the lease ID of the
279            destination blob. If the request does not include the lease ID or it is not
280            valid, the operation fails with status code 412 (Precondition Failed).
281        :param str source_lease_id:
282            Specify this to perform the Copy Blob operation only if
283            the lease ID given matches the active lease ID of the source blob.
284        :param int timeout:
285            The timeout parameter is expressed in seconds.
286        :return: Copy operation properties such as status, source, and ID.
287        :rtype: :class:`~azure.storage.blob.models.CopyProperties`
288        '''
289        return self._copy_blob(container_name, blob_name, copy_source,
290                               metadata,
291                               source_if_modified_since=None, source_if_unmodified_since=None,
292                               source_if_match=None, source_if_none_match=None,
293                               destination_if_modified_since=destination_if_modified_since,
294                               destination_if_unmodified_since=destination_if_unmodified_since,
295                               destination_if_match=destination_if_match,
296                               destination_if_none_match=destination_if_none_match,
297                               destination_lease_id=destination_lease_id,
298                               source_lease_id=source_lease_id, timeout=timeout,
299                               incremental_copy=True)
300
301    def update_page(
302            self, container_name, blob_name, page, start_range, end_range,
303            validate_content=False, lease_id=None, if_sequence_number_lte=None,
304            if_sequence_number_lt=None, if_sequence_number_eq=None,
305            if_modified_since=None, if_unmodified_since=None,
306            if_match=None, if_none_match=None, cpk=None, timeout=None):
307        '''
308        Updates a range of pages.
309
310        :param str container_name:
311            Name of existing container.
312        :param str blob_name:
313            Name of existing blob.
314        :param bytes page:
315            Content of the page.
316        :param int start_range:
317            Start of byte range to use for writing to a section of the blob.
318            Pages must be aligned with 512-byte boundaries, the start offset
319            must be a modulus of 512 and the end offset must be a modulus of
320            512-1. Examples of valid byte ranges are 0-511, 512-1023, etc.
321        :param int end_range:
322            End of byte range to use for writing to a section of the blob.
323            Pages must be aligned with 512-byte boundaries, the start offset
324            must be a modulus of 512 and the end offset must be a modulus of
325            512-1. Examples of valid byte ranges are 0-511, 512-1023, etc.
326        :param bool validate_content:
327            If true, calculates an MD5 hash of the page content. The storage
328            service checks the hash of the content that has arrived
329            with the hash that was sent. This is primarily valuable for detecting
330            bitflips on the wire if using http instead of https as https (the default)
331            will already validate. Note that this MD5 hash is not stored with the
332            blob.
333        :param str lease_id:
334            Required if the blob has an active lease.
335        :param int if_sequence_number_lte:
336            If the blob's sequence number is less than or equal to
337            the specified value, the request proceeds; otherwise it fails.
338        :param int if_sequence_number_lt:
339            If the blob's sequence number is less than the specified
340            value, the request proceeds; otherwise it fails.
341        :param int if_sequence_number_eq:
342            If the blob's sequence number is equal to the specified
343            value, the request proceeds; otherwise it fails.
344        :param datetime if_modified_since:
345            A DateTime value. Azure expects the date value passed in to be UTC.
346            If timezone is included, any non-UTC datetimes will be converted to UTC.
347            If a date is passed in without timezone info, it is assumed to be UTC.
348            Specify this header to perform the operation only
349            if the resource has been modified since the specified time.
350        :param datetime if_unmodified_since:
351            A DateTime value. Azure expects the date value passed in to be UTC.
352            If timezone is included, any non-UTC datetimes will be converted to UTC.
353            If a date is passed in without timezone info, it is assumed to be UTC.
354            Specify this header to perform the operation only if
355            the resource has not been modified since the specified date/time.
356        :param str if_match:
357            An ETag value, or the wildcard character (*). Specify an ETag value for this conditional
358            header to write the page only if the blob's ETag value matches the
359            value specified. If the values do not match, the Blob service fails.
360        :param str if_none_match:
361            An ETag value, or the wildcard character (*). Specify an ETag value for this conditional
362            header to write the page only if the blob's ETag value does not
363            match the value specified. If the values are identical, the Blob
364            service fails.
365        :param ~azure.storage.blob.models.CustomerProvidedEncryptionKey cpk:
366            Encrypts the data on the service-side with the given key.
367            Use of customer-provided keys must be done over HTTPS.
368            As the encryption key itself is provided in the request,
369            a secure connection must be established to transfer the key.
370        :param int timeout:
371            The timeout parameter is expressed in seconds.
372        :return: ETag and last modified properties for the updated Page Blob
373        :rtype: :class:`~azure.storage.blob.models.ResourceProperties`
374        '''
375
376        _validate_encryption_unsupported(self.require_encryption, self.key_encryption_key)
377
378        return self._update_page(
379            container_name,
380            blob_name,
381            page,
382            start_range,
383            end_range,
384            validate_content=validate_content,
385            lease_id=lease_id,
386            if_sequence_number_lte=if_sequence_number_lte,
387            if_sequence_number_lt=if_sequence_number_lt,
388            if_sequence_number_eq=if_sequence_number_eq,
389            if_modified_since=if_modified_since,
390            if_unmodified_since=if_unmodified_since,
391            if_match=if_match,
392            if_none_match=if_none_match,
393            cpk=cpk,
394            timeout=timeout
395        )
396
397    def update_page_from_url(self, container_name, blob_name, start_range, end_range, copy_source_url,
398                             source_range_start, source_content_md5=None, source_if_modified_since=None,
399                             source_if_unmodified_since=None, source_if_match=None, source_if_none_match=None,
400                             lease_id=None, if_sequence_number_lte=None, if_sequence_number_lt=None,
401                             if_sequence_number_eq=None, if_modified_since=None, if_unmodified_since=None,
402                             if_match=None, if_none_match=None, cpk=None, timeout=None):
403        """
404        Updates a range of pages to a page blob where the contents are read from a URL.
405
406        :param str container_name:
407            Name of existing container.
408        :param str blob_name:
409            Name of blob.
410        :param int start_range:
411            Start of byte range to use for writing to a section of the blob.
412            Pages must be aligned with 512-byte boundaries, the start offset
413            must be a modulus of 512 and the end offset must be a modulus of
414            512-1. Examples of valid byte ranges are 0-511, 512-1023, etc.
415        :param int end_range:
416            End of byte range to use for writing to a section of the blob.
417            Pages must be aligned with 512-byte boundaries, the start offset
418            must be a modulus of 512 and the end offset must be a modulus of
419            512-1. Examples of valid byte ranges are 0-511, 512-1023, etc.
420        :param str copy_source_url:
421            The URL of the source data. It can point to any Azure Blob or File, that is either public or has a
422            shared access signature attached.
423        :param int source_range_start:
424            This indicates the start of the range of bytes(inclusive) that has to be taken from the copy source.
425            The service will read the same number of bytes as the destination range (end_range-start_range).
426        :param str source_content_md5:
427            If given, the service will calculate the MD5 hash of the block content and compare against this value.
428        :param datetime source_if_modified_since:
429            A DateTime value. Azure expects the date value passed in to be UTC.
430            If timezone is included, any non-UTC datetimes will be converted to UTC.
431            If a date is passed in without timezone info, it is assumed to be UTC.
432            Specify this header to perform the operation only
433            if the source resource has been modified since the specified time.
434        :param datetime source_if_unmodified_since:
435            A DateTime value. Azure expects the date value passed in to be UTC.
436            If timezone is included, any non-UTC datetimes will be converted to UTC.
437            If a date is passed in without timezone info, it is assumed to be UTC.
438            Specify this header to perform the operation only if
439            the source resource has not been modified since the specified date/time.
440        :param str source_if_match:
441            An ETag value, or the wildcard character (*). Specify this header to perform
442            the operation only if the source resource's ETag matches the value specified.
443        :param str source_if_none_match:
444            An ETag value, or the wildcard character (*). Specify this header
445            to perform the operation only if the source resource's ETag does not match
446            the value specified. Specify the wildcard character (*) to perform
447            the operation only if the source resource does not exist, and fail the
448            operation if it does exist.
449        :param str lease_id:
450            Required if the blob has an active lease.
451        :param int if_sequence_number_lte:
452            If the blob's sequence number is less than or equal to
453            the specified value, the request proceeds; otherwise it fails.
454        :param int if_sequence_number_lt:
455            If the blob's sequence number is less than the specified
456            value, the request proceeds; otherwise it fails.
457        :param int if_sequence_number_eq:
458            If the blob's sequence number is equal to the specified
459            value, the request proceeds; otherwise it fails.
460        :param datetime if_modified_since:
461            A DateTime value. Azure expects the date value passed in to be UTC.
462            If timezone is included, any non-UTC datetimes will be converted to UTC.
463            If a date is passed in without timezone info, it is assumed to be UTC.
464            Specify this header to perform the operation only
465            if the resource has been modified since the specified time.
466        :param datetime if_unmodified_since:
467            A DateTime value. Azure expects the date value passed in to be UTC.
468            If timezone is included, any non-UTC datetimes will be converted to UTC.
469            If a date is passed in without timezone info, it is assumed to be UTC.
470            Specify this header to perform the operation only if
471            the resource has not been modified since the specified date/time.
472        :param str if_match:
473            An ETag value, or the wildcard character (*). Specify this header to perform
474            the operation only if the resource's ETag matches the value specified.
475        :param str if_none_match:
476            An ETag value, or the wildcard character (*). Specify this header
477            to perform the operation only if the resource's ETag does not match
478            the value specified. Specify the wildcard character (*) to perform
479            the operation only if the resource does not exist, and fail the
480            operation if it does exist.
481        :param ~azure.storage.blob.models.CustomerProvidedEncryptionKey cpk:
482            Encrypts the data on the service-side with the given key.
483            Use of customer-provided keys must be done over HTTPS.
484            As the encryption key itself is provided in the request,
485            a secure connection must be established to transfer the key.
486        :param int timeout:
487            The timeout parameter is expressed in seconds.
488        """
489        _validate_encryption_unsupported(self.require_encryption, self.key_encryption_key)
490        _validate_not_none('container_name', container_name)
491        _validate_not_none('blob_name', blob_name)
492        _validate_not_none('copy_source_url', copy_source_url)
493
494        request = HTTPRequest()
495        request.method = 'PUT'
496        request.host_locations = self._get_host_locations()
497        request.path = _get_path(container_name, blob_name)
498        request.query = {
499            'comp': 'page',
500            'timeout': _int_to_str(timeout),
501        }
502        request.headers = {
503            'x-ms-page-write': 'update',
504            'x-ms-copy-source': copy_source_url,
505            'x-ms-source-content-md5': source_content_md5,
506            'x-ms-source-if-Modified-Since': _datetime_to_utc_string(source_if_modified_since),
507            'x-ms-source-if-Unmodified-Since': _datetime_to_utc_string(source_if_unmodified_since),
508            'x-ms-source-if-Match': _to_str(source_if_match),
509            'x-ms-source-if-None-Match': _to_str(source_if_none_match),
510            'x-ms-lease-id': _to_str(lease_id),
511            'x-ms-if-sequence-number-le': _to_str(if_sequence_number_lte),
512            'x-ms-if-sequence-number-lt': _to_str(if_sequence_number_lt),
513            'x-ms-if-sequence-number-eq': _to_str(if_sequence_number_eq),
514            'If-Modified-Since': _datetime_to_utc_string(if_modified_since),
515            'If-Unmodified-Since': _datetime_to_utc_string(if_unmodified_since),
516            'If-Match': _to_str(if_match),
517            'If-None-Match': _to_str(if_none_match)
518        }
519        _validate_and_add_cpk_headers(request, encryption_key=cpk, protocol=self.protocol)
520        _validate_and_format_range_headers(
521            request,
522            start_range,
523            end_range,
524            align_to_page=True)
525        _validate_and_format_range_headers(
526            request,
527            source_range_start,
528            source_range_start+(end_range-start_range),
529            range_header_name="x-ms-source-range")
530
531        return self._perform_request(request, _parse_page_properties)
532
533    def clear_page(
534            self, container_name, blob_name, start_range, end_range,
535            lease_id=None, if_sequence_number_lte=None,
536            if_sequence_number_lt=None, if_sequence_number_eq=None,
537            if_modified_since=None, if_unmodified_since=None,
538            if_match=None, if_none_match=None, timeout=None):
539        '''
540        Clears a range of pages.
541
542        :param str container_name:
543            Name of existing container.
544        :param str blob_name:
545            Name of existing blob.
546        :param int start_range:
547            Start of byte range to use for writing to a section of the blob.
548            Pages must be aligned with 512-byte boundaries, the start offset
549            must be a modulus of 512 and the end offset must be a modulus of
550            512-1. Examples of valid byte ranges are 0-511, 512-1023, etc.
551        :param int end_range:
552            End of byte range to use for writing to a section of the blob.
553            Pages must be aligned with 512-byte boundaries, the start offset
554            must be a modulus of 512 and the end offset must be a modulus of
555            512-1. Examples of valid byte ranges are 0-511, 512-1023, etc.
556        :param str lease_id:
557            Required if the blob has an active lease.
558        :param int if_sequence_number_lte:
559            If the blob's sequence number is less than or equal to
560            the specified value, the request proceeds; otherwise it fails.
561        :param int if_sequence_number_lt:
562            If the blob's sequence number is less than the specified
563            value, the request proceeds; otherwise it fails.
564        :param int if_sequence_number_eq:
565            If the blob's sequence number is equal to the specified
566            value, the request proceeds; otherwise it fails.
567        :param datetime if_modified_since:
568            A DateTime value. Azure expects the date value passed in to be UTC.
569            If timezone is included, any non-UTC datetimes will be converted to UTC.
570            If a date is passed in without timezone info, it is assumed to be UTC.
571            Specify this header to perform the operation only
572            if the resource has been modified since the specified time.
573        :param datetime if_unmodified_since:
574            A DateTime value. Azure expects the date value passed in to be UTC.
575            If timezone is included, any non-UTC datetimes will be converted to UTC.
576            If a date is passed in without timezone info, it is assumed to be UTC.
577            Specify this header to perform the operation only if
578            the resource has not been modified since the specified date/time.
579        :param str if_match:
580            An ETag value, or the wildcard character (*). Specify an ETag value for this conditional
581            header to write the page only if the blob's ETag value matches the
582            value specified. If the values do not match, the Blob service fails.
583        :param str if_none_match:
584            An ETag value, or the wildcard character (*). Specify an ETag value for this conditional
585            header to write the page only if the blob's ETag value does not
586            match the value specified. If the values are identical, the Blob
587            service fails.
588        :param int timeout:
589            The timeout parameter is expressed in seconds.
590        :return: ETag and last modified properties for the updated Page Blob
591        :rtype: :class:`~azure.storage.blob.models.ResourceProperties`
592        '''
593        _validate_not_none('container_name', container_name)
594        _validate_not_none('blob_name', blob_name)
595
596        request = HTTPRequest()
597        request.method = 'PUT'
598        request.host_locations = self._get_host_locations()
599        request.path = _get_path(container_name, blob_name)
600        request.query = {
601            'comp': 'page',
602            'timeout': _int_to_str(timeout),
603        }
604        request.headers = {
605            'x-ms-page-write': 'clear',
606            'x-ms-lease-id': _to_str(lease_id),
607            'x-ms-if-sequence-number-le': _to_str(if_sequence_number_lte),
608            'x-ms-if-sequence-number-lt': _to_str(if_sequence_number_lt),
609            'x-ms-if-sequence-number-eq': _to_str(if_sequence_number_eq),
610            'If-Modified-Since': _datetime_to_utc_string(if_modified_since),
611            'If-Unmodified-Since': _datetime_to_utc_string(if_unmodified_since),
612            'If-Match': _to_str(if_match),
613            'If-None-Match': _to_str(if_none_match)
614        }
615        _validate_and_format_range_headers(
616            request,
617            start_range,
618            end_range,
619            align_to_page=True)
620
621        return self._perform_request(request, _parse_page_properties)
622
623    def get_page_ranges(
624            self, container_name, blob_name, snapshot=None, start_range=None,
625            end_range=None, lease_id=None, if_modified_since=None,
626            if_unmodified_since=None, if_match=None, if_none_match=None, timeout=None):
627        '''
628        Returns the list of valid page ranges for a Page Blob or snapshot
629        of a page blob.
630
631        :param str container_name:
632            Name of existing container.
633        :param str blob_name:
634            Name of existing blob.
635        :param str snapshot:
636            The snapshot parameter is an opaque DateTime value that,
637            when present, specifies the blob snapshot to retrieve information
638            from.
639        :param int start_range:
640            Start of byte range to use for getting valid page ranges.
641            If no end_range is given, all bytes after the start_range will be searched.
642            Pages must be aligned with 512-byte boundaries, the start offset
643            must be a modulus of 512 and the end offset must be a modulus of
644            512-1. Examples of valid byte ranges are 0-511, 512-, etc.
645        :param int end_range:
646            End of byte range to use for getting valid page ranges.
647            If end_range is given, start_range must be provided.
648            This range will return valid page ranges for from the offset start up to
649            offset end.
650            Pages must be aligned with 512-byte boundaries, the start offset
651            must be a modulus of 512 and the end offset must be a modulus of
652            512-1. Examples of valid byte ranges are 0-511, 512-, etc.
653        :param str lease_id:
654            Required if the blob has an active lease.
655        :param datetime if_modified_since:
656            A DateTime value. Azure expects the date value passed in to be UTC.
657            If timezone is included, any non-UTC datetimes will be converted to UTC.
658            If a date is passed in without timezone info, it is assumed to be UTC.
659            Specify this header to perform the operation only
660            if the resource has been modified since the specified time.
661        :param datetime if_unmodified_since:
662            A DateTime value. Azure expects the date value passed in to be UTC.
663            If timezone is included, any non-UTC datetimes will be converted to UTC.
664            If a date is passed in without timezone info, it is assumed to be UTC.
665            Specify this header to perform the operation only if
666            the resource has not been modified since the specified date/time.
667        :param str if_match:
668            An ETag value, or the wildcard character (*). Specify this header to perform
669            the operation only if the resource's ETag matches the value specified.
670        :param str if_none_match:
671            An ETag value, or the wildcard character (*). Specify this header
672            to perform the operation only if the resource's ETag does not match
673            the value specified. Specify the wildcard character (*) to perform
674            the operation only if the resource does not exist, and fail the
675            operation if it does exist.
676        :param int timeout:
677            The timeout parameter is expressed in seconds.
678        :return: A list of valid Page Ranges for the Page Blob.
679        :rtype: list(:class:`~azure.storage.blob.models.PageRange`)
680        '''
681        _validate_not_none('container_name', container_name)
682        _validate_not_none('blob_name', blob_name)
683        request = HTTPRequest()
684        request.method = 'GET'
685        request.host_locations = self._get_host_locations(secondary=True)
686        request.path = _get_path(container_name, blob_name)
687        request.query = {
688            'comp': 'pagelist',
689            'snapshot': _to_str(snapshot),
690            'timeout': _int_to_str(timeout),
691        }
692        request.headers = {
693            'x-ms-lease-id': _to_str(lease_id),
694            'If-Modified-Since': _datetime_to_utc_string(if_modified_since),
695            'If-Unmodified-Since': _datetime_to_utc_string(if_unmodified_since),
696            'If-Match': _to_str(if_match),
697            'If-None-Match': _to_str(if_none_match),
698        }
699        if start_range is not None:
700            _validate_and_format_range_headers(
701                request,
702                start_range,
703                end_range,
704                start_range_required=False,
705                end_range_required=False,
706                align_to_page=True)
707
708        return self._perform_request(request, _convert_xml_to_page_ranges)
709
710    def get_page_ranges_diff(
711            self, container_name, blob_name, previous_snapshot, snapshot=None,
712            start_range=None, end_range=None, lease_id=None, if_modified_since=None,
713            if_unmodified_since=None, if_match=None, if_none_match=None, timeout=None):
714        '''
715        The response will include only the pages that are different between either a
716        recent snapshot or the current blob and a previous snapshot, including pages
717        that were cleared.
718
719        :param str container_name:
720            Name of existing container.
721        :param str blob_name:
722            Name of existing blob.
723        :param str previous_snapshot:
724            The snapshot parameter is an opaque DateTime value that
725            specifies a previous blob snapshot to be compared
726            against a more recent snapshot or the current blob.
727        :param str snapshot:
728            The snapshot parameter is an opaque DateTime value that
729            specifies a more recent blob snapshot to be compared
730            against a previous snapshot (previous_snapshot).
731        :param int start_range:
732            Start of byte range to use for getting different page ranges.
733            If no end_range is given, all bytes after the start_range will be searched.
734            Pages must be aligned with 512-byte boundaries, the start offset
735            must be a modulus of 512 and the end offset must be a modulus of
736            512-1. Examples of valid byte ranges are 0-511, 512-, etc.
737        :param int end_range:
738            End of byte range to use for getting different page ranges.
739            If end_range is given, start_range must be provided.
740            This range will return valid page ranges for from the offset start up to
741            offset end.
742            Pages must be aligned with 512-byte boundaries, the start offset
743            must be a modulus of 512 and the end offset must be a modulus of
744            512-1. Examples of valid byte ranges are 0-511, 512-, etc.
745        :param str lease_id:
746            Required if the blob has an active lease.
747        :param datetime if_modified_since:
748            A DateTime value. Azure expects the date value passed in to be UTC.
749            If timezone is included, any non-UTC datetimes will be converted to UTC.
750            If a date is passed in without timezone info, it is assumed to be UTC.
751            Specify this header to perform the operation only
752            if the resource has been modified since the specified time.
753        :param datetime if_unmodified_since:
754            A DateTime value. Azure expects the date value passed in to be UTC.
755            If timezone is included, any non-UTC datetimes will be converted to UTC.
756            If a date is passed in without timezone info, it is assumed to be UTC.
757            Specify this header to perform the operation only if
758            the resource has not been modified since the specified date/time.
759        :param str if_match:
760            An ETag value, or the wildcard character (*). Specify this header to perform
761            the operation only if the resource's ETag matches the value specified.
762        :param str if_none_match:
763            An ETag value, or the wildcard character (*). Specify this header
764            to perform the operation only if the resource's ETag does not match
765            the value specified. Specify the wildcard character (*) to perform
766            the operation only if the resource does not exist, and fail the
767            operation if it does exist.
768        :param int timeout:
769            The timeout parameter is expressed in seconds.
770        :return: A list of different Page Ranges for the Page Blob.
771        :rtype: list(:class:`~azure.storage.blob.models.PageRange`)
772        '''
773        _validate_not_none('container_name', container_name)
774        _validate_not_none('blob_name', blob_name)
775        _validate_not_none('previous_snapshot', previous_snapshot)
776        request = HTTPRequest()
777        request.method = 'GET'
778        request.host_locations = self._get_host_locations(secondary=True)
779        request.path = _get_path(container_name, blob_name)
780        request.query = {
781            'comp': 'pagelist',
782            'snapshot': _to_str(snapshot),
783            'prevsnapshot': _to_str(previous_snapshot),
784            'timeout': _int_to_str(timeout),
785        }
786        request.headers = {
787            'x-ms-lease-id': _to_str(lease_id),
788            'If-Modified-Since': _datetime_to_utc_string(if_modified_since),
789            'If-Unmodified-Since': _datetime_to_utc_string(if_unmodified_since),
790            'If-Match': _to_str(if_match),
791            'If-None-Match': _to_str(if_none_match),
792        }
793        if start_range is not None:
794            _validate_and_format_range_headers(
795                request,
796                start_range,
797                end_range,
798                start_range_required=False,
799                end_range_required=False,
800                align_to_page=True)
801
802        return self._perform_request(request, _convert_xml_to_page_ranges)
803
804    def set_sequence_number(
805            self, container_name, blob_name, sequence_number_action, sequence_number=None,
806            lease_id=None, if_modified_since=None, if_unmodified_since=None,
807            if_match=None, if_none_match=None, timeout=None):
808
809        '''
810        Sets the blob sequence number.
811
812        :param str container_name:
813            Name of existing container.
814        :param str blob_name:
815            Name of existing blob.
816        :param str sequence_number_action:
817            This property indicates how the service should modify the blob's sequence
818            number. See :class:`~azure.storage.blob.models.SequenceNumberAction` for more information.
819        :param str sequence_number:
820            This property sets the blob's sequence number. The sequence number is a
821            user-controlled property that you can use to track requests and manage
822            concurrency issues.
823        :param str lease_id:
824            Required if the blob has an active lease.
825        :param datetime if_modified_since:
826            A DateTime value. Azure expects the date value passed in to be UTC.
827            If timezone is included, any non-UTC datetimes will be converted to UTC.
828            If a date is passed in without timezone info, it is assumed to be UTC.
829            Specify this header to perform the operation only
830            if the resource has been modified since the specified time.
831        :param datetime if_unmodified_since:
832            A DateTime value. Azure expects the date value passed in to be UTC.
833            If timezone is included, any non-UTC datetimes will be converted to UTC.
834            If a date is passed in without timezone info, it is assumed to be UTC.
835            Specify this header to perform the operation only if
836            the resource has not been modified since the specified date/time.
837        :param str if_match:
838            An ETag value, or the wildcard character (*). Specify this header to perform
839            the operation only if the resource's ETag matches the value specified.
840        :param str if_none_match:
841            An ETag value, or the wildcard character (*). Specify this header
842            to perform the operation only if the resource's ETag does not match
843            the value specified. Specify the wildcard character (*) to perform
844            the operation only if the resource does not exist, and fail the
845            operation if it does exist.
846        :param int timeout:
847            The timeout parameter is expressed in seconds.
848        :return: ETag and last modified properties for the updated Page Blob
849        :rtype: :class:`~azure.storage.blob.models.ResourceProperties`
850        '''
851        _validate_not_none('container_name', container_name)
852        _validate_not_none('blob_name', blob_name)
853        _validate_not_none('sequence_number_action', sequence_number_action)
854        request = HTTPRequest()
855        request.method = 'PUT'
856        request.host_locations = self._get_host_locations()
857        request.path = _get_path(container_name, blob_name)
858        request.query = {
859            'comp': 'properties',
860            'timeout': _int_to_str(timeout),
861        }
862        request.headers = {
863            'x-ms-blob-sequence-number': _to_str(sequence_number),
864            'x-ms-sequence-number-action': _to_str(sequence_number_action),
865            'x-ms-lease-id': _to_str(lease_id),
866            'If-Modified-Since': _datetime_to_utc_string(if_modified_since),
867            'If-Unmodified-Since': _datetime_to_utc_string(if_unmodified_since),
868            'If-Match': _to_str(if_match),
869            'If-None-Match': _to_str(if_none_match),
870        }
871
872        return self._perform_request(request, _parse_page_properties)
873
874    def resize_blob(
875            self, container_name, blob_name, content_length,
876            lease_id=None, if_modified_since=None, if_unmodified_since=None,
877            if_match=None, if_none_match=None, timeout=None):
878
879        '''
880        Resizes a page blob to the specified size. If the specified value is less
881        than the current size of the blob, then all pages above the specified value
882        are cleared.
883
884        :param str container_name:
885            Name of existing container.
886        :param str blob_name:
887            Name of existing blob.
888        :param int content_length:
889            Size to resize blob to.
890        :param str lease_id:
891            Required if the blob has an active lease.
892        :param datetime if_modified_since:
893            A DateTime value. Azure expects the date value passed in to be UTC.
894            If timezone is included, any non-UTC datetimes will be converted to UTC.
895            If a date is passed in without timezone info, it is assumed to be UTC.
896            Specify this header to perform the operation only
897            if the resource has been modified since the specified time.
898        :param datetime if_unmodified_since:
899            A DateTime value. Azure expects the date value passed in to be UTC.
900            If timezone is included, any non-UTC datetimes will be converted to UTC.
901            If a date is passed in without timezone info, it is assumed to be UTC.
902            Specify this header to perform the operation only if
903            the resource has not been modified since the specified date/time.
904        :param str if_match:
905            An ETag value, or the wildcard character (*). Specify this header to perform
906            the operation only if the resource's ETag matches the value specified.
907        :param str if_none_match:
908            An ETag value, or the wildcard character (*). Specify this header
909            to perform the operation only if the resource's ETag does not match
910            the value specified. Specify the wildcard character (*) to perform
911            the operation only if the resource does not exist, and fail the
912            operation if it does exist.
913        :param int timeout:
914            The timeout parameter is expressed in seconds.
915        :return: ETag and last modified properties for the updated Page Blob
916        :rtype: :class:`~azure.storage.blob.models.ResourceProperties`
917        '''
918        _validate_not_none('container_name', container_name)
919        _validate_not_none('blob_name', blob_name)
920        _validate_not_none('content_length', content_length)
921        request = HTTPRequest()
922        request.method = 'PUT'
923        request.host_locations = self._get_host_locations()
924        request.path = _get_path(container_name, blob_name)
925        request.query = {
926            'comp': 'properties',
927            'timeout': _int_to_str(timeout),
928        }
929        request.headers = {
930            'x-ms-blob-content-length': _to_str(content_length),
931            'x-ms-lease-id': _to_str(lease_id),
932            'If-Modified-Since': _datetime_to_utc_string(if_modified_since),
933            'If-Unmodified-Since': _datetime_to_utc_string(if_unmodified_since),
934            'If-Match': _to_str(if_match),
935            'If-None-Match': _to_str(if_none_match),
936        }
937
938        return self._perform_request(request, _parse_page_properties)
939
940    # ----Convenience APIs-----------------------------------------------------
941
942    def create_blob_from_path(
943            self, container_name, blob_name, file_path, content_settings=None,
944            metadata=None, validate_content=False, progress_callback=None, max_connections=2,
945            lease_id=None, if_modified_since=None, if_unmodified_since=None,
946            if_match=None, if_none_match=None, timeout=None, premium_page_blob_tier=None, cpk=None):
947        '''
948        Creates a new blob from a file path, or updates the content of an
949        existing blob, with automatic chunking and progress notifications.
950        Empty chunks are skipped, while non-emtpy ones(even if only partly filled) are uploaded.
951
952        :param str container_name:
953            Name of existing container.
954        :param str blob_name:
955            Name of blob to create or update.
956        :param str file_path:
957            Path of the file to upload as the blob content.
958        :param ~azure.storage.blob.models.ContentSettings content_settings:
959            ContentSettings object used to set blob properties.
960        :param metadata:
961            Name-value pairs associated with the blob as metadata.
962        :type metadata: dict(str, str)
963        :param bool validate_content:
964            If true, calculates an MD5 hash for each page of the blob. The storage
965            service checks the hash of the content that has arrived with the hash
966            that was sent. This is primarily valuable for detecting bitflips on
967            the wire if using http instead of https as https (the default) will
968            already validate. Note that this MD5 hash is not stored with the
969            blob.
970        :param progress_callback:
971            Callback for progress with signature function(current, total) where
972            current is the number of bytes transfered so far, and total is the
973            size of the blob, or None if the total size is unknown.
974        :type progress_callback: func(current, total)
975        :param int max_connections:
976            Maximum number of parallel connections to use.
977        :param str lease_id:
978            Required if the blob has an active lease.
979        :param datetime if_modified_since:
980            A DateTime value. Azure expects the date value passed in to be UTC.
981            If timezone is included, any non-UTC datetimes will be converted to UTC.
982            If a date is passed in without timezone info, it is assumed to be UTC.
983            Specify this header to perform the operation only
984            if the resource has been modified since the specified time.
985        :param datetime if_unmodified_since:
986            A DateTime value. Azure expects the date value passed in to be UTC.
987            If timezone is included, any non-UTC datetimes will be converted to UTC.
988            If a date is passed in without timezone info, it is assumed to be UTC.
989            Specify this header to perform the operation only if
990            the resource has not been modified since the specified date/time.
991        :param str if_match:
992            An ETag value, or the wildcard character (*). Specify this header to perform
993            the operation only if the resource's ETag matches the value specified.
994        :param str if_none_match:
995            An ETag value, or the wildcard character (*). Specify this header
996            to perform the operation only if the resource's ETag does not match
997            the value specified. Specify the wildcard character (*) to perform
998            the operation only if the resource does not exist, and fail the
999            operation if it does exist.
1000        :param int timeout:
1001            The timeout parameter is expressed in seconds. This method may make
1002            multiple calls to the Azure service and the timeout will apply to
1003            each call individually.
1004        :param premium_page_blob_tier:
1005            A page blob tier value to set the blob to. The tier correlates to the size of the
1006            blob and number of allowed IOPS. This is only applicable to page blobs on
1007            premium storage accounts.
1008        :param ~azure.storage.blob.models.CustomerProvidedEncryptionKey cpk:
1009            Encrypts the data on the service-side with the given key.
1010            Use of customer-provided keys must be done over HTTPS.
1011            As the encryption key itself is provided in the request,
1012            a secure connection must be established to transfer the key.
1013        :return: ETag and last modified properties for the Page Blob
1014        :rtype: :class:`~azure.storage.blob.models.ResourceProperties`
1015        '''
1016        _validate_not_none('container_name', container_name)
1017        _validate_not_none('blob_name', blob_name)
1018        _validate_not_none('file_path', file_path)
1019
1020        count = path.getsize(file_path)
1021        with open(file_path, 'rb') as stream:
1022            return self.create_blob_from_stream(
1023                container_name=container_name,
1024                blob_name=blob_name,
1025                stream=stream,
1026                count=count,
1027                content_settings=content_settings,
1028                metadata=metadata,
1029                validate_content=validate_content,
1030                progress_callback=progress_callback,
1031                max_connections=max_connections,
1032                lease_id=lease_id,
1033                if_modified_since=if_modified_since,
1034                if_unmodified_since=if_unmodified_since,
1035                if_match=if_match,
1036                if_none_match=if_none_match,
1037                timeout=timeout,
1038                premium_page_blob_tier=premium_page_blob_tier,
1039                cpk=cpk)
1040
1041    def create_blob_from_stream(
1042            self, container_name, blob_name, stream, count, content_settings=None,
1043            metadata=None, validate_content=False, progress_callback=None,
1044            max_connections=2, lease_id=None, if_modified_since=None,
1045            if_unmodified_since=None, if_match=None, if_none_match=None, timeout=None,
1046            premium_page_blob_tier=None, cpk=None):
1047        '''
1048        Creates a new blob from a file/stream, or updates the content of an
1049        existing blob, with automatic chunking and progress notifications.
1050        Empty chunks are skipped, while non-emtpy ones(even if only partly filled) are uploaded.
1051
1052        :param str container_name:
1053            Name of existing container.
1054        :param str blob_name:
1055            Name of blob to create or update.
1056        :param io.IOBase stream:
1057            Opened file/stream to upload as the blob content.
1058        :param int count:
1059            Number of bytes to read from the stream. This is required, a page
1060            blob cannot be created if the count is unknown.
1061        :param ~azure.storage.blob.models.ContentSettings content_settings:
1062            ContentSettings object used to set the blob properties.
1063        :param metadata:
1064            Name-value pairs associated with the blob as metadata.
1065        :type metadata: dict(str, str)
1066        :param bool validate_content:
1067            If true, calculates an MD5 hash for each page of the blob. The storage
1068            service checks the hash of the content that has arrived with the hash
1069            that was sent. This is primarily valuable for detecting bitflips on
1070            the wire if using http instead of https as https (the default) will
1071            already validate. Note that this MD5 hash is not stored with the
1072            blob.
1073        :param progress_callback:
1074            Callback for progress with signature function(current, total) where
1075            current is the number of bytes transfered so far, and total is the
1076            size of the blob, or None if the total size is unknown.
1077        :type progress_callback: func(current, total)
1078        :param int max_connections:
1079            Maximum number of parallel connections to use. Note that parallel upload
1080            requires the stream to be seekable.
1081        :param str lease_id:
1082            Required if the blob has an active lease.
1083        :param datetime if_modified_since:
1084            A DateTime value. Azure expects the date value passed in to be UTC.
1085            If timezone is included, any non-UTC datetimes will be converted to UTC.
1086            If a date is passed in without timezone info, it is assumed to be UTC.
1087            Specify this header to perform the operation only
1088            if the resource has been modified since the specified time.
1089        :param datetime if_unmodified_since:
1090            A DateTime value. Azure expects the date value passed in to be UTC.
1091            If timezone is included, any non-UTC datetimes will be converted to UTC.
1092            If a date is passed in without timezone info, it is assumed to be UTC.
1093            Specify this header to perform the operation only if
1094            the resource has not been modified since the specified date/time.
1095        :param str if_match:
1096            An ETag value, or the wildcard character (*). Specify this header to perform
1097            the operation only if the resource's ETag matches the value specified.
1098        :param str if_none_match:
1099            An ETag value, or the wildcard character (*). Specify this header
1100            to perform the operation only if the resource's ETag does not match
1101            the value specified. Specify the wildcard character (*) to perform
1102            the operation only if the resource does not exist, and fail the
1103            operation if it does exist.
1104        :param int timeout:
1105            The timeout parameter is expressed in seconds. This method may make
1106            multiple calls to the Azure service and the timeout will apply to
1107            each call individually.
1108        :param premium_page_blob_tier:
1109            A page blob tier value to set the blob to. The tier correlates to the size of the
1110            blob and number of allowed IOPS. This is only applicable to page blobs on
1111            premium storage accounts.
1112        :param ~azure.storage.blob.models.CustomerProvidedEncryptionKey cpk:
1113            Encrypts the data on the service-side with the given key.
1114            Use of customer-provided keys must be done over HTTPS.
1115            As the encryption key itself is provided in the request,
1116            a secure connection must be established to transfer the key.
1117        :return: ETag and last modified properties for the Page Blob
1118        :rtype: :class:`~azure.storage.blob.models.ResourceProperties`
1119        '''
1120        _validate_not_none('container_name', container_name)
1121        _validate_not_none('blob_name', blob_name)
1122        _validate_not_none('stream', stream)
1123        _validate_not_none('count', count)
1124        _validate_encryption_required(self.require_encryption, self.key_encryption_key)
1125
1126        if count < 0:
1127            raise ValueError(_ERROR_VALUE_NEGATIVE.format('count'))
1128
1129        if count % _PAGE_ALIGNMENT != 0:
1130            raise ValueError(_ERROR_PAGE_BLOB_SIZE_ALIGNMENT.format(count))
1131
1132        cek, iv, encryption_data = None, None, None
1133        if self.key_encryption_key is not None:
1134            cek, iv, encryption_data = _generate_blob_encryption_data(self.key_encryption_key)
1135
1136        response = self._create_blob(
1137            container_name=container_name,
1138            blob_name=blob_name,
1139            content_length=count,
1140            content_settings=content_settings,
1141            metadata=metadata,
1142            lease_id=lease_id,
1143            premium_page_blob_tier=premium_page_blob_tier,
1144            if_modified_since=if_modified_since,
1145            if_unmodified_since=if_unmodified_since,
1146            if_match=if_match,
1147            if_none_match=if_none_match,
1148            timeout=timeout,
1149            encryption_data=encryption_data,
1150            cpk=cpk,
1151        )
1152
1153        if count == 0:
1154            return response
1155
1156        # _upload_blob_chunks returns the block ids for block blobs so resource_properties
1157        # is passed as a parameter to get the last_modified and etag for page and append blobs.
1158        # this info is not needed for block_blobs since _put_block_list is called after which gets this info
1159        resource_properties = ResourceProperties()
1160        _upload_blob_chunks(
1161            blob_service=self,
1162            container_name=container_name,
1163            blob_name=blob_name,
1164            blob_size=count,
1165            block_size=self.MAX_PAGE_SIZE,
1166            stream=stream,
1167            max_connections=max_connections,
1168            progress_callback=progress_callback,
1169            validate_content=validate_content,
1170            lease_id=lease_id,
1171            uploader_class=_PageBlobChunkUploader,
1172            if_match=response.etag,
1173            timeout=timeout,
1174            content_encryption_key=cek,
1175            initialization_vector=iv,
1176            resource_properties=resource_properties,
1177            cpk=cpk,
1178        )
1179
1180        return resource_properties
1181
1182    def create_blob_from_bytes(
1183            self, container_name, blob_name, blob, index=0, count=None,
1184            content_settings=None, metadata=None, validate_content=False,
1185            progress_callback=None, max_connections=2, lease_id=None,
1186            if_modified_since=None, if_unmodified_since=None, if_match=None,
1187            if_none_match=None, timeout=None, premium_page_blob_tier=None, cpk=None):
1188        '''
1189        Creates a new blob from an array of bytes, or updates the content
1190        of an existing blob, with automatic chunking and progress
1191        notifications. Empty chunks are skipped, while non-emtpy ones(even if only partly filled) are uploaded.
1192
1193        :param str container_name:
1194            Name of existing container.
1195        :param str blob_name:
1196            Name of blob to create or update.
1197        :param bytes blob:
1198            Content of blob as an array of bytes.
1199        :param int index:
1200            Start index in the byte array.
1201        :param int count:
1202            Number of bytes to upload. Set to None or negative value to upload
1203            all bytes starting from index.
1204        :param ~azure.storage.blob.models.ContentSettings content_settings:
1205            ContentSettings object used to set blob properties.
1206        :param metadata:
1207            Name-value pairs associated with the blob as metadata.
1208        :type metadata: dict(str, str)
1209        :param bool validate_content:
1210            If true, calculates an MD5 hash for each page of the blob. The storage
1211            service checks the hash of the content that has arrived with the hash
1212            that was sent. This is primarily valuable for detecting bitflips on
1213            the wire if using http instead of https as https (the default) will
1214            already validate. Note that this MD5 hash is not stored with the
1215            blob.
1216        :param progress_callback:
1217            Callback for progress with signature function(current, total) where
1218            current is the number of bytes transfered so far, and total is the
1219            size of the blob, or None if the total size is unknown.
1220        :type progress_callback: func(current, total)
1221        :param int max_connections:
1222            Maximum number of parallel connections to use.
1223        :param str lease_id:
1224            Required if the blob has an active lease.
1225        :param datetime if_modified_since:
1226            A DateTime value. Azure expects the date value passed in to be UTC.
1227            If timezone is included, any non-UTC datetimes will be converted to UTC.
1228            If a date is passed in without timezone info, it is assumed to be UTC.
1229            Specify this header to perform the operation only
1230            if the resource has been modified since the specified time.
1231        :param datetime if_unmodified_since:
1232            A DateTime value. Azure expects the date value passed in to be UTC.
1233            If timezone is included, any non-UTC datetimes will be converted to UTC.
1234            If a date is passed in without timezone info, it is assumed to be UTC.
1235            Specify this header to perform the operation only if
1236            the resource has not been modified since the specified date/time.
1237        :param str if_match:
1238            An ETag value, or the wildcard character (*). Specify this header to perform
1239            the operation only if the resource's ETag matches the value specified.
1240        :param str if_none_match:
1241            An ETag value, or the wildcard character (*). Specify this header
1242            to perform the operation only if the resource's ETag does not match
1243            the value specified. Specify the wildcard character (*) to perform
1244            the operation only if the resource does not exist, and fail the
1245            operation if it does exist.
1246        :param int timeout:
1247            The timeout parameter is expressed in seconds. This method may make
1248            multiple calls to the Azure service and the timeout will apply to
1249            each call individually.
1250        :param premium_page_blob_tier:
1251            A page blob tier value to set the blob to. The tier correlates to the size of the
1252            blob and number of allowed IOPS. This is only applicable to page blobs on
1253            premium storage accounts.
1254        :param ~azure.storage.blob.models.CustomerProvidedEncryptionKey cpk:
1255            Encrypts the data on the service-side with the given key.
1256            Use of customer-provided keys must be done over HTTPS.
1257            As the encryption key itself is provided in the request,
1258            a secure connection must be established to transfer the key.
1259        :return: ETag and last modified properties for the Page Blob
1260        :rtype: :class:`~azure.storage.blob.models.ResourceProperties`
1261        '''
1262        _validate_not_none('container_name', container_name)
1263        _validate_not_none('blob_name', blob_name)
1264        _validate_not_none('blob', blob)
1265        _validate_type_bytes('blob', blob)
1266
1267        if index < 0:
1268            raise IndexError(_ERROR_VALUE_NEGATIVE.format('index'))
1269
1270        if count is None or count < 0:
1271            count = len(blob) - index
1272
1273        stream = BytesIO(blob)
1274        stream.seek(index)
1275
1276        return self.create_blob_from_stream(
1277            container_name=container_name,
1278            blob_name=blob_name,
1279            stream=stream,
1280            count=count,
1281            content_settings=content_settings,
1282            metadata=metadata,
1283            validate_content=validate_content,
1284            lease_id=lease_id,
1285            progress_callback=progress_callback,
1286            max_connections=max_connections,
1287            if_modified_since=if_modified_since,
1288            if_unmodified_since=if_unmodified_since,
1289            if_match=if_match,
1290            if_none_match=if_none_match,
1291            timeout=timeout,
1292            premium_page_blob_tier=premium_page_blob_tier,
1293            cpk=cpk)
1294
1295    def set_premium_page_blob_tier(
1296            self, container_name, blob_name, premium_page_blob_tier,
1297            timeout=None):
1298        '''
1299        Sets the page blob tiers on the blob. This API is only supported for page blobs on premium accounts.
1300
1301        :param str container_name:
1302            Name of existing container.
1303        :param str blob_name:
1304            Name of blob to update.
1305        :param PremiumPageBlobTier premium_page_blob_tier:
1306            A page blob tier value to set the blob to. The tier correlates to the size of the
1307            blob and number of allowed IOPS. This is only applicable to page blobs on
1308            premium storage accounts.
1309        :param int timeout:
1310            The timeout parameter is expressed in seconds. This method may make
1311            multiple calls to the Azure service and the timeout will apply to
1312            each call individually.
1313        '''
1314        _validate_not_none('container_name', container_name)
1315        _validate_not_none('blob_name', blob_name)
1316        _validate_not_none('premium_page_blob_tier', premium_page_blob_tier)
1317
1318        request = HTTPRequest()
1319        request.method = 'PUT'
1320        request.host_locations = self._get_host_locations()
1321        request.path = _get_path(container_name, blob_name)
1322        request.query = {
1323            'comp': 'tier',
1324            'timeout': _int_to_str(timeout),
1325        }
1326        request.headers = {
1327            'x-ms-access-tier': _to_str(premium_page_blob_tier)
1328        }
1329
1330        self._perform_request(request)
1331
1332    def copy_blob(self, container_name, blob_name, copy_source,
1333                  metadata=None,
1334                  source_if_modified_since=None,
1335                  source_if_unmodified_since=None,
1336                  source_if_match=None, source_if_none_match=None,
1337                  destination_if_modified_since=None,
1338                  destination_if_unmodified_since=None,
1339                  destination_if_match=None,
1340                  destination_if_none_match=None,
1341                  destination_lease_id=None,
1342                  source_lease_id=None, timeout=None,
1343                  premium_page_blob_tier=None):
1344        '''
1345        Copies a blob asynchronously. This operation returns a copy operation
1346        properties object, including a copy ID you can use to check or abort the
1347        copy operation. The Blob service copies blobs on a best-effort basis.
1348
1349        The source blob for a copy operation must be a page blob. If the destination
1350        blob already exists, it must be of the same blob type as the source blob.
1351        Any existing destination blob will be overwritten.
1352        The destination blob cannot be modified while a copy operation is in progress.
1353
1354        When copying from a page blob, the Blob service creates a destination page
1355        blob of the source blob's length, initially containing all zeroes. Then
1356        the source page ranges are enumerated, and non-empty ranges are copied.
1357
1358        If the tier on the source blob is larger than the tier being passed to this
1359        copy operation or if the size of the blob exceeds the tier being passed to
1360        this copy operation then the operation will fail.
1361
1362        You can call get_blob_properties on the destination
1363        blob to check the status of the copy operation. The final blob will be
1364        committed when the copy completes.
1365
1366        :param str container_name:
1367            Name of the destination container. The container must exist.
1368        :param str blob_name:
1369            Name of the destination blob. If the destination blob exists, it will
1370            be overwritten. Otherwise, it will be created.
1371        :param str copy_source:
1372            A URL of up to 2 KB in length that specifies an Azure file or blob.
1373            The value should be URL-encoded as it would appear in a request URI.
1374            If the source is in another account, the source must either be public
1375            or must be authenticated via a shared access signature. If the source
1376            is public, no authentication is required.
1377            Examples:
1378            https://myaccount.blob.core.windows.net/mycontainer/myblob
1379            https://myaccount.blob.core.windows.net/mycontainer/myblob?snapshot=<DateTime>
1380            https://otheraccount.blob.core.windows.net/mycontainer/myblob?sastoken
1381        :param metadata:
1382            Name-value pairs associated with the blob as metadata. If no name-value
1383            pairs are specified, the operation will copy the metadata from the
1384            source blob or file to the destination blob. If one or more name-value
1385            pairs are specified, the destination blob is created with the specified
1386            metadata, and metadata is not copied from the source blob or file.
1387        :type metadata: dict(str, str).
1388        :param datetime source_if_modified_since:
1389            A DateTime value. Azure expects the date value passed in to be UTC.
1390            If timezone is included, any non-UTC datetimes will be converted to UTC.
1391            If a date is passed in without timezone info, it is assumed to be UTC.
1392            Specify this conditional header to copy the blob only if the source
1393            blob has been modified since the specified date/time.
1394        :param datetime source_if_unmodified_since:
1395            A DateTime value. Azure expects the date value passed in to be UTC.
1396            If timezone is included, any non-UTC datetimes will be converted to UTC.
1397            If a date is passed in without timezone info, it is assumed to be UTC.
1398            Specify this conditional header to copy the blob only if the source blob
1399            has not been modified since the specified date/time.
1400        :param ETag source_if_match:
1401            An ETag value, or the wildcard character (*). Specify this conditional
1402            header to copy the source blob only if its ETag matches the value
1403            specified. If the ETag values do not match, the Blob service returns
1404            status code 412 (Precondition Failed). This header cannot be specified
1405            if the source is an Azure File.
1406        :param ETag source_if_none_match:
1407            An ETag value, or the wildcard character (*). Specify this conditional
1408            header to copy the blob only if its ETag does not match the value
1409            specified. If the values are identical, the Blob service returns status
1410            code 412 (Precondition Failed). This header cannot be specified if the
1411            source is an Azure File.
1412        :param datetime destination_if_modified_since:
1413            A DateTime value. Azure expects the date value passed in to be UTC.
1414            If timezone is included, any non-UTC datetimes will be converted to UTC.
1415            If a date is passed in without timezone info, it is assumed to be UTC.
1416            Specify this conditional header to copy the blob only
1417            if the destination blob has been modified since the specified date/time.
1418            If the destination blob has not been modified, the Blob service returns
1419            status code 412 (Precondition Failed).
1420        :param datetime destination_if_unmodified_since:
1421            A DateTime value. Azure expects the date value passed in to be UTC.
1422            If timezone is included, any non-UTC datetimes will be converted to UTC.
1423            If a date is passed in without timezone info, it is assumed to be UTC.
1424            Specify this conditional header to copy the blob only
1425            if the destination blob has not been modified since the specified
1426            date/time. If the destination blob has been modified, the Blob service
1427            returns status code 412 (Precondition Failed).
1428        :param ETag destination_if_match:
1429            An ETag value, or the wildcard character (*). Specify an ETag value for
1430            this conditional header to copy the blob only if the specified ETag value
1431            matches the ETag value for an existing destination blob. If the ETag for
1432            the destination blob does not match the ETag specified for If-Match, the
1433            Blob service returns status code 412 (Precondition Failed).
1434        :param ETag destination_if_none_match:
1435            An ETag value, or the wildcard character (*). Specify an ETag value for
1436            this conditional header to copy the blob only if the specified ETag value
1437            does not match the ETag value for the destination blob. Specify the wildcard
1438            character (*) to perform the operation only if the destination blob does not
1439            exist. If the specified condition isn't met, the Blob service returns status
1440            code 412 (Precondition Failed).
1441        :param str destination_lease_id:
1442            The lease ID specified for this header must match the lease ID of the
1443            destination blob. If the request does not include the lease ID or it is not
1444            valid, the operation fails with status code 412 (Precondition Failed).
1445        :param str source_lease_id:
1446            Specify this to perform the Copy Blob operation only if
1447            the lease ID given matches the active lease ID of the source blob.
1448        :param int timeout:
1449            The timeout parameter is expressed in seconds.
1450        :param PageBlobTier premium_page_blob_tier:
1451            A page blob tier value to set on the destination blob. The tier correlates to
1452            the size of the blob and number of allowed IOPS. This is only applicable to
1453            page blobs on premium storage accounts.
1454            If the tier on the source blob is larger than the tier being passed to this
1455            copy operation or if the size of the blob exceeds the tier being passed to
1456            this copy operation then the operation will fail.
1457        :return: Copy operation properties such as status, source, and ID.
1458        :rtype: :class:`~azure.storage.blob.models.CopyProperties`
1459        '''
1460        return self._copy_blob(container_name, blob_name, copy_source,
1461                               metadata, premium_page_blob_tier,
1462                               source_if_modified_since, source_if_unmodified_since,
1463                               source_if_match, source_if_none_match,
1464                               destination_if_modified_since,
1465                               destination_if_unmodified_since,
1466                               destination_if_match,
1467                               destination_if_none_match,
1468                               destination_lease_id,
1469                               source_lease_id, timeout,
1470                               False)
1471
1472    # -----Helper methods-----------------------------------------------------
1473
1474    def _create_blob(
1475            self, container_name, blob_name, content_length, content_settings=None,
1476            sequence_number=None, metadata=None, lease_id=None, premium_page_blob_tier=None, if_modified_since=None,
1477            if_unmodified_since=None, if_match=None, if_none_match=None, timeout=None,
1478            encryption_data=None, cpk=None):
1479        '''
1480        See create_blob for more details. This helper method
1481        allows for encryption or other such special behavior because
1482        it is safely handled by the library. These behaviors are
1483        prohibited in the public version of this function.
1484        :param str encryption_data:
1485            The JSON formatted encryption metadata to upload as a part of the blob.
1486            This should only be passed internally from other methods and only applied
1487            when uploading entire blob contents immediately follows creation of the blob.
1488        :param ~azure.storage.blob.models.CustomerProvidedEncryptionKey cpk:
1489            Encrypts the data on the service-side with the given key.
1490            Use of customer-provided keys must be done over HTTPS.
1491            As the encryption key itself is provided in the request,
1492            a secure connection must be established to transfer the key.
1493        '''
1494
1495        _validate_not_none('container_name', container_name)
1496        _validate_not_none('blob_name', blob_name)
1497        _validate_not_none('content_length', content_length)
1498        request = HTTPRequest()
1499        request.method = 'PUT'
1500        request.host_locations = self._get_host_locations()
1501        request.path = _get_path(container_name, blob_name)
1502        request.query = {'timeout': _int_to_str(timeout)}
1503        request.headers = {
1504            'x-ms-blob-type': _to_str(self.blob_type),
1505            'x-ms-blob-content-length': _to_str(content_length),
1506            'x-ms-lease-id': _to_str(lease_id),
1507            'x-ms-blob-sequence-number': _to_str(sequence_number),
1508            'x-ms-access-tier': _to_str(premium_page_blob_tier),
1509            'If-Modified-Since': _datetime_to_utc_string(if_modified_since),
1510            'If-Unmodified-Since': _datetime_to_utc_string(if_unmodified_since),
1511            'If-Match': _to_str(if_match),
1512            'If-None-Match': _to_str(if_none_match)
1513        }
1514        _validate_and_add_cpk_headers(request, encryption_key=cpk, protocol=self.protocol)
1515        _add_metadata_headers(metadata, request)
1516        if content_settings is not None:
1517            request.headers.update(content_settings._to_headers())
1518
1519        if encryption_data is not None:
1520            request.headers['x-ms-meta-encryptiondata'] = encryption_data
1521
1522        return self._perform_request(request, _parse_base_properties)
1523
1524    def _update_page(
1525            self, container_name, blob_name, page, start_range, end_range,
1526            validate_content=False, lease_id=None, if_sequence_number_lte=None,
1527            if_sequence_number_lt=None, if_sequence_number_eq=None,
1528            if_modified_since=None, if_unmodified_since=None,
1529            if_match=None, if_none_match=None, cpk=None, timeout=None):
1530        '''
1531        See update_page for more details. This helper method
1532        allows for encryption or other such special behavior because
1533        it is safely handled by the library. These behaviors are
1534        prohibited in the public version of this function.
1535        '''
1536
1537        request = HTTPRequest()
1538        request.method = 'PUT'
1539        request.host_locations = self._get_host_locations()
1540        request.path = _get_path(container_name, blob_name)
1541        request.query = {
1542            'comp': 'page',
1543            'timeout': _int_to_str(timeout),
1544        }
1545        request.headers = {
1546            'x-ms-page-write': 'update',
1547            'x-ms-lease-id': _to_str(lease_id),
1548            'x-ms-if-sequence-number-le': _to_str(if_sequence_number_lte),
1549            'x-ms-if-sequence-number-lt': _to_str(if_sequence_number_lt),
1550            'x-ms-if-sequence-number-eq': _to_str(if_sequence_number_eq),
1551            'If-Modified-Since': _datetime_to_utc_string(if_modified_since),
1552            'If-Unmodified-Since': _datetime_to_utc_string(if_unmodified_since),
1553            'If-Match': _to_str(if_match),
1554            'If-None-Match': _to_str(if_none_match)
1555        }
1556        _validate_and_add_cpk_headers(request, encryption_key=cpk, protocol=self.protocol)
1557        _validate_and_format_range_headers(
1558            request,
1559            start_range,
1560            end_range,
1561            align_to_page=True)
1562        request.body = _get_data_bytes_only('page', page)
1563
1564        if validate_content:
1565            computed_md5 = _get_content_md5(request.body)
1566            request.headers['Content-MD5'] = _to_str(computed_md5)
1567
1568        return self._perform_request(request, _parse_page_properties)
1569