@@ -428,15 +428,20 @@ def _stream_response(self, start: int, end: int) -> Response:
428428 headers ["Range" ] = f"bytes={ start } -{ end } "
429429 logger .debug ("streamed bytes request: %s" , headers ["Range" ])
430430 self ._request_count += 1
431+
431432 response = self ._session .get (self ._url , headers = headers , stream = True )
432- response .raise_for_status ()
433- if int (response .headers ["Content-Length" ]) != (end - start + 1 ):
434- raise HTTPRangeRequestNotRespectedError (
435- f"server did not respect byte range request: "
436- f"requested { end - start + 1 } bytes, got "
437- f"{ response .headers ['Content-Length' ]} bytes"
438- )
439- return response
433+ try :
434+ response .raise_for_status ()
435+ if int (response .headers ["Content-Length" ]) != (end - start + 1 ):
436+ raise HTTPRangeRequestNotRespectedError (
437+ f"server did not respect byte range request: "
438+ f"requested { end - start + 1 } bytes, got "
439+ f"{ response .headers ['Content-Length' ]} bytes"
440+ )
441+ return response
442+ except BaseException :
443+ response .close ()
444+ raise
440445
441446 def _fetch_content_range (self , start : int , end : int ) -> Iterator [bytes ]:
442447 """Perform a series of HTTP range requests to cover the specified byte range.
@@ -445,7 +450,8 @@ def _fetch_content_range(self, start: int, end: int) -> Iterator[bytes]:
445450 method must *include* the byte indexed at argument ``end`` (so e.g. ``0-1`` is 2
446451 bytes long, and the range can never be empty).
447452 """
448- yield from self ._stream_response (start , end ).iter_content (CONTENT_CHUNK_SIZE )
453+ with self ._stream_response (start , end ) as response :
454+ yield from response .iter_content (CONTENT_CHUNK_SIZE )
449455
450456 @contextmanager
451457 def _stay (self ) -> Iterator [None ]:
@@ -549,7 +555,7 @@ def _fetch_content_length(self) -> int:
549555 else :
550556 # If we *could* download some file contents, then write them to the end of
551557 # the file and set up our bisect boundaries by hand.
552- with self ._stay ():
558+ with self ._stay (), tail :
553559 response_length = int (tail .headers ["Content-Length" ])
554560 assert response_length == min (initial_chunk_size , ret_length )
555561 self .seek (- response_length , io .SEEK_END )
@@ -600,36 +606,43 @@ def _try_initial_chunk_request(
600606
601607 self ._request_count += 1
602608 tail = self ._session .get (self ._url , headers = headers , stream = True )
603- tail .raise_for_status ()
604-
605- code = tail .status_code
606- if code != codes .partial_content :
607- # According to
608- # https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests,
609- # a 200 OK implies that range requests are not supported,
610- # regardless of the requested size.
611- # However, some servers that support negative range requests also return a
612- # 200 OK if the requested range from the end was larger than the file size.
613- if code == codes .ok :
614- accept_ranges = tail .headers .get ("Accept-Ranges" , None )
615- content_length = int (tail .headers ["Content-Length" ])
616- if accept_ranges == "bytes" and content_length <= initial_chunk_size :
617- return content_length , tail
609+ try :
610+ tail .raise_for_status ()
611+
612+ code = tail .status_code
613+ if code != codes .partial_content :
614+ # According to
615+ # https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests,
616+ # a 200 OK implies that range requests are not supported,
617+ # regardless of the requested size.
618+ # However, some servers that support negative range requests also return a
619+ # 200 OK if the requested range from the end was larger than the file size.
620+ if code == codes .ok :
621+ accept_ranges = tail .headers .get ("Accept-Ranges" , None )
622+ content_length = int (tail .headers ["Content-Length" ])
623+ if (
624+ accept_ranges == "bytes"
625+ and content_length <= initial_chunk_size
626+ ):
627+ return content_length , tail
628+
629+ raise HTTPRangeRequestUnsupportedError (
630+ f"did not receive partial content: got code { code } "
631+ )
618632
619- raise HTTPRangeRequestUnsupportedError (
620- f"did not receive partial content: got code { code } "
621- )
633+ if "Content-Range" not in tail .headers :
634+ raise LazyWheelUnsupportedError (
635+ f"file length cannot be determined for { self ._url } , "
636+ f"did not receive content range header from server"
637+ )
622638
623- if "Content-Range" not in tail .headers :
624- raise LazyWheelUnsupportedError (
625- f"file length cannot be determined for { self ._url } , "
626- f"did not receive content range header from server"
639+ file_length = self ._parse_full_length_from_content_range (
640+ tail .headers ["Content-Range" ]
627641 )
628-
629- file_length = self ._parse_full_length_from_content_range (
630- tail .headers ["Content-Range" ]
631- )
632- return (file_length , tail )
642+ return (file_length , tail )
643+ except BaseException :
644+ tail .close ()
645+ raise
633646
634647 def _extract_content_length (
635648 self , initial_chunk_size : int
@@ -683,6 +696,7 @@ def _extract_content_length(
683696 if int (tail .headers ["Content-Length" ]) > initial_chunk_size or tail .headers .get (
684697 "Content-Range" , ""
685698 ).startswith ("bytes -" ):
699+ tail .close ()
686700 tail = None
687701 self ._domains_without_negative_range .add (domain )
688702 return file_length , tail
0 commit comments