24
from __future__ import absolute_import
25
from io import BytesIO
28
import http.client as http_client
29
except ImportError: # python < 3
30
import httplib as http_client
32
import email.utils as email_utils
33
except ImportError: # python < 3
34
import rfc822 as email_utils
27
import http.client as http_client
28
import email.utils as email_utils
40
from ...sixish import (
46
36
class ResponseFile(object):
219
212
Parse the headers including the empty line following them so that we
220
213
are ready to read the data itself.
223
self._headers = http_client.parse_headers(self._file)
225
self._headers = http_client.HTTPMessage(self._file, seekable=0)
215
self._headers = http_client.parse_headers(self._file)
226
216
# Extract the range definition
227
217
content_range = self._headers.get('content-range', None)
228
218
if content_range is None:
372
def handle_response(url, code, msg, data):
362
def handle_response(url, code, getheader, data):
373
363
"""Interpret the code & headers and wrap the provided data in a RangeFile.
375
365
This is a factory method which returns an appropriate RangeFile based on
378
368
:param url: The url being processed. Mostly for error reporting
379
369
:param code: The integer HTTP response code
380
:param msg: An HTTPMessage containing the headers for the response
370
:param getheader: Function for retrieving header
381
371
:param data: A file-like object that can be read() to get the
383
373
:return: A file-like object that can seek()+read() the
388
378
rfile = ResponseFile(url, data)
389
379
elif code == 206:
390
380
rfile = RangeFile(url, data)
391
content_type = msg.get('content-type', None)
392
if content_type is None:
393
# When there is no content-type header we treat the response as
394
# being of type 'application/octet-stream' as per RFC2616 section
396
# Therefore it is obviously not multipart
397
content_type = 'application/octet-stream'
401
is_multipart = (msg.get_content_maintype() == 'multipart'
402
and msg.get_content_subtype() == 'byteranges')
404
is_multipart = (msg.getmaintype() == 'multipart'
405
and msg.getsubtype() == 'byteranges')
408
# Full fledged multipart response
410
boundary = msg.get_param('boundary')
412
boundary = msg.getparam('boundary')
413
rfile.set_boundary(boundary.encode('ascii'))
381
# When there is no content-type header we treat the response as
382
# being of type 'application/octet-stream' as per RFC2616 section
384
# Therefore it is obviously not multipart
385
content_type = getheader('content-type', 'application/octet-stream')
386
mimetype, options = cgi.parse_header(content_type)
387
if mimetype == 'multipart/byteranges':
388
rfile.set_boundary(options['boundary'].encode('ascii'))
415
390
# A response to a range request, but not multipart
416
content_range = msg.get('content-range', None)
391
content_range = getheader('content-range', None)
417
392
if content_range is None:
418
raise errors.InvalidHttpResponse(url,
419
'Missing the Content-Range header in a 206 range response')
393
raise errors.InvalidHttpResponse(
394
url, 'Missing the Content-Range header in a 206 range response')
420
395
rfile.set_range_from_header(content_range)
422
raise errors.InvalidHttpResponse(url,
423
'Unknown response code %s' % code)
397
raise errors.UnexpectedHttpStatus(url, code)