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