Files
dvc/dvc/utils/http.py
T
b13aec0f2b [6478] Fix 401 unauthorized for directories in basic auth protected http remote (#6479)
* added auth to iter_url and created custom open for http fs

* added default value to auth

* Update dvc/utils/http.py

Co-authored-by: Ruslan Kuprieiev <[email protected]>

* Update dvc/fs/http.py

Co-authored-by: Ruslan Kuprieiev <[email protected]>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* pr fixes

Co-authored-by: Ruslan Kuprieiev <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2021-08-24 18:39:29 +03:00

68 lines
1.9 KiB
Python

import io
from contextlib import contextmanager
from dvc.utils.stream import IterStream
@contextmanager
def open_url(url, mode="r", encoding=None, **iter_opts):
"""Opens an url as a readable stream.
Resumes on connection error.
Url could be a string or a callable returning a string.
"""
assert mode in {"r", "rt", "rb"}
with iter_url(url, **iter_opts) as (response, it):
bytes_stream = IterStream(it)
if mode == "rb":
yield bytes_stream
else:
encoding = encoding or response.encoding
yield io.TextIOWrapper(bytes_stream, encoding=encoding)
@contextmanager
def iter_url(url, chunk_size=io.DEFAULT_BUFFER_SIZE, auth=None):
"""Iterate over chunks requested from url."""
import requests
def request(headers=None):
the_url = url() if callable(url) else url
response = requests.get(
the_url, stream=True, headers=headers, auth=auth
)
if response.status_code == 404:
raise FileNotFoundError(f"Can't open {the_url}")
response.raise_for_status()
return response
def gen(response):
try:
pos = 0
while True:
try:
for chunk in response.iter_content(chunk_size):
pos += len(chunk)
yield chunk
break
except requests.ConnectionError:
response.close()
if response.headers.get("Accept-Ranges") != "bytes":
raise
# Reopen request from where we stopped
headers = {"Range": f"bytes={pos}-"}
response = request(headers)
finally:
response.close()
response = request()
it = gen(response)
try:
yield response, it
finally:
# Ensure connection is closed
it.close()