Skip to content

Commit 0dc81bf

Browse files
authored
Respect custom headers set on the request supplied to MediaIoBaseDownload within each call to next_chunk (#546)
Closes #207
1 parent 3cf5e60 commit 0dc81bf

File tree

2 files changed

+46
-3
lines changed

2 files changed

+46
-3
lines changed

googleapiclient/http.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,14 @@ def __init__(self, fd, request, chunksize=DEFAULT_CHUNK_SIZE):
647647
self._sleep = time.sleep
648648
self._rand = random.random
649649

650+
self._headers = {}
651+
for k, v in six.iteritems(request.headers):
652+
# allow users to supply custom headers by setting them on the request
653+
# but strip out the ones that are set by default on requests generated by
654+
# API methods like Drive's files().get(fileId=...)
655+
if not k.lower() in ('accept', 'accept-encoding', 'user-agent'):
656+
self._headers[k] = v
657+
650658
@util.positional(1)
651659
def next_chunk(self, num_retries=0):
652660
"""Get the next chunk of the download.
@@ -666,10 +674,9 @@ def next_chunk(self, num_retries=0):
666674
googleapiclient.errors.HttpError if the response was not a 2xx.
667675
httplib2.HttpLib2Error if a transport error has occured.
668676
"""
669-
headers = {
670-
'range': 'bytes=%d-%d' % (
677+
headers = self._headers.copy()
678+
headers['range'] = 'bytes=%d-%d' % (
671679
self._progress, self._progress + self._chunksize)
672-
}
673680
http = self._request.http
674681

675682
resp, content = _retry_request(

tests/test_http.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
from six.moves.urllib.parse import urlencode
3030

3131
# Do not remove the httplib2 import
32+
import json
3233
import httplib2
3334
import logging
3435
import mock
@@ -456,6 +457,41 @@ def test_media_io_base_download(self):
456457
self.assertEqual(5, download._progress)
457458
self.assertEqual(5, download._total_size)
458459

460+
def test_media_io_base_download_custom_request_headers(self):
461+
self.request.http = HttpMockSequence([
462+
({'status': '200',
463+
'content-range': '0-2/5'}, 'echo_request_headers_as_json'),
464+
({'status': '200',
465+
'content-range': '3-4/5'}, 'echo_request_headers_as_json'),
466+
])
467+
self.assertEqual(True, self.request.http.follow_redirects)
468+
469+
self.request.headers['Cache-Control'] = 'no-store'
470+
471+
download = MediaIoBaseDownload(
472+
fd=self.fd, request=self.request, chunksize=3)
473+
474+
self.assertEqual(download._headers, {'Cache-Control':'no-store'})
475+
476+
status, done = download.next_chunk()
477+
478+
result = self.fd.getvalue().decode('utf-8')
479+
480+
# we abuse the internals of the object we're testing, pay no attention
481+
# to the actual bytes= values here; we are just asserting that the
482+
# header we added to the original request is sent up to the server
483+
# on each call to next_chunk
484+
485+
self.assertEqual(json.loads(result),
486+
{"Cache-Control": "no-store", "range": "bytes=0-3"})
487+
488+
download._fd = self.fd = BytesIO()
489+
status, done = download.next_chunk()
490+
491+
result = self.fd.getvalue().decode('utf-8')
492+
self.assertEqual(json.loads(result),
493+
{"Cache-Control": "no-store", "range": "bytes=51-54"})
494+
459495
def test_media_io_base_download_handle_redirects(self):
460496
self.request.http = HttpMockSequence([
461497
({'status': '200',

0 commit comments

Comments
 (0)