|
35 | 35 | import warnings
|
36 | 36 |
|
37 | 37 | import httplib2
|
| 38 | +from six.moves.urllib.parse import parse_qsl |
38 | 39 | from six.moves.urllib.parse import quote
|
| 40 | +from six.moves.urllib.parse import urlencode |
| 41 | +from six.moves.urllib.parse import urlsplit |
| 42 | +from six.moves.urllib.parse import urlunsplit |
39 | 43 |
|
40 | 44 | import google.auth.transport.requests
|
41 | 45 | from google import resumable_media
|
@@ -403,15 +407,19 @@ def _get_download_url(self):
|
403 | 407 | :rtype: str
|
404 | 408 | :returns: The download URL for the current blob.
|
405 | 409 | """
|
| 410 | + name_value_pairs = [] |
406 | 411 | if self.media_link is None:
|
407 |
| - download_url = _DOWNLOAD_URL_TEMPLATE.format(path=self.path) |
| 412 | + base_url = _DOWNLOAD_URL_TEMPLATE.format(path=self.path) |
408 | 413 | if self.generation is not None:
|
409 |
| - download_url += u'&generation={:d}'.format(self.generation) |
410 |
| - if self.user_project is not None: |
411 |
| - download_url += u'&userProject={}'.format(self.user_project) |
412 |
| - return download_url |
| 414 | + name_value_pairs.append( |
| 415 | + ('generation', '{:d}'.format(self.generation))) |
413 | 416 | else:
|
414 |
| - return self.media_link |
| 417 | + base_url = self.media_link |
| 418 | + |
| 419 | + if self.user_project is not None: |
| 420 | + name_value_pairs.append(('userProject', self.user_project)) |
| 421 | + |
| 422 | + return _add_query_parameters(base_url, name_value_pairs) |
415 | 423 |
|
416 | 424 | def _do_download(self, transport, file_obj, download_url, headers):
|
417 | 425 | """Perform a download without any error handling.
|
@@ -658,12 +666,14 @@ def _do_multipart_upload(self, client, stream, content_type,
|
658 | 666 | info = self._get_upload_arguments(content_type)
|
659 | 667 | headers, object_metadata, content_type = info
|
660 | 668 |
|
661 |
| - upload_url = _MULTIPART_URL_TEMPLATE.format( |
| 669 | + base_url = _MULTIPART_URL_TEMPLATE.format( |
662 | 670 | bucket_path=self.bucket.path)
|
| 671 | + name_value_pairs = [] |
663 | 672 |
|
664 | 673 | if self.user_project is not None:
|
665 |
| - upload_url += '&userProject={}'.format(self.user_project) |
| 674 | + name_value_pairs.append(('userProject', self.user_project)) |
666 | 675 |
|
| 676 | + upload_url = _add_query_parameters(base_url, name_value_pairs) |
667 | 677 | upload = MultipartUpload(upload_url, headers=headers)
|
668 | 678 |
|
669 | 679 | if num_retries is not None:
|
@@ -734,12 +744,14 @@ def _initiate_resumable_upload(self, client, stream, content_type,
|
734 | 744 | if extra_headers is not None:
|
735 | 745 | headers.update(extra_headers)
|
736 | 746 |
|
737 |
| - upload_url = _RESUMABLE_URL_TEMPLATE.format( |
| 747 | + base_url = _RESUMABLE_URL_TEMPLATE.format( |
738 | 748 | bucket_path=self.bucket.path)
|
| 749 | + name_value_pairs = [] |
739 | 750 |
|
740 | 751 | if self.user_project is not None:
|
741 |
| - upload_url += '&userProject={}'.format(self.user_project) |
| 752 | + name_value_pairs.append(('userProject', self.user_project)) |
742 | 753 |
|
| 754 | + upload_url = _add_query_parameters(base_url, name_value_pairs) |
743 | 755 | upload = ResumableUpload(upload_url, chunk_size, headers=headers)
|
744 | 756 |
|
745 | 757 | if num_retries is not None:
|
@@ -1676,3 +1688,24 @@ def _raise_from_invalid_response(error, error_info=None):
|
1676 | 1688 | faux_response = httplib2.Response({'status': response.status_code})
|
1677 | 1689 | raise make_exception(faux_response, response.content,
|
1678 | 1690 | error_info=error_info, use_json=False)
|
| 1691 | + |
| 1692 | + |
| 1693 | +def _add_query_parameters(base_url, name_value_pairs): |
| 1694 | + """Add one query parameter to a base URL. |
| 1695 | +
|
| 1696 | + :type base_url: string |
| 1697 | + :param base_url: Base URL (may already contain query parameters) |
| 1698 | +
|
| 1699 | + :type name_value_pairs: list of (string, string) tuples. |
| 1700 | + :param name_value_pairs: Names and values of the query parameters to add |
| 1701 | +
|
| 1702 | + :rtype: string |
| 1703 | + :returns: URL with additional query strings appended. |
| 1704 | + """ |
| 1705 | + if len(name_value_pairs) == 0: |
| 1706 | + return base_url |
| 1707 | + |
| 1708 | + scheme, netloc, path, query, frag = urlsplit(base_url) |
| 1709 | + query = parse_qsl(query) |
| 1710 | + query.extend(name_value_pairs) |
| 1711 | + return urlunsplit((scheme, netloc, path, urlencode(query), frag)) |
0 commit comments