Files
dvc/tests/utils/httpd.py
T
Alexander Schepanovski e5e29065c8 api: make .open() stream data for Azure
This employs generating temporary signed public url and then streaming
from it. The bulk of the code might be reused for other remotes.

Url streaming does resume on connection error using "Range" header and
regenerates public url too.

If remote class doesn't provide .open() then this falls back to pulling
a file and opening it locally.
2019-08-09 21:51:43 +07:00

60 lines
1.7 KiB
Python

import hashlib
import os
import threading
from RangeHTTPServer import RangeRequestHandler
from dvc.utils.compat import HTTPServer
class TestRequestHandler(RangeRequestHandler):
checksum_header = None
def end_headers(self):
# RangeRequestHandler only sends Accept-Ranges header if Range header
# is present, see https://github.com/danvk/RangeHTTPServer/issues/23
if not self.headers.get("Range"):
self.send_header("Accept-Ranges", "bytes")
# Add a checksum header
if self.checksum_header:
file = self.translate_path(self.path)
if not os.path.isdir(file) and os.path.exists(file):
with open(file, "r") as fd:
encoded_text = fd.read().encode("utf8")
checksum = hashlib.md5(encoded_text).hexdigest()
self.send_header(self.checksum_header, checksum)
RangeRequestHandler.end_headers(self)
class ETagHandler(TestRequestHandler):
checksum_header = "ETag"
class ContentMD5Handler(TestRequestHandler):
checksum_header = "Content-MD5"
class StaticFileServer:
_lock = threading.Lock()
def __init__(self, handler="etag"):
self._lock.acquire()
handler_class = ETagHandler if handler == "etag" else ContentMD5Handler
self._httpd = HTTPServer(("localhost", 0), handler_class)
self._thread = None
def __enter__(self):
self._thread = threading.Thread(target=self._httpd.serve_forever)
self._thread.daemon = True
self._thread.start()
return self._httpd
def __exit__(self, *args):
self._httpd.socket.close()
self._httpd.shutdown()
self._httpd.server_close()
self._lock.release()