From b87b3ca2937fa4b24f8fc1627bdacad6194dcd59 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Thu, 5 Mar 2020 11:36:44 +0100 Subject: dash_server: handle DELETE requests --- README | 16 +++++++++------- dash_server.py | 37 +++++++++++++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/README b/README index b05130b..83e986f 100644 --- a/README +++ b/README @@ -7,13 +7,15 @@ interpreter. No dependencies beyond the standard library are neded. The executable takes one mandatory parameter, which is the path to the directory to which the DASH media files shall be written. -The server processes incoming HTTP GET, PUT and POST requests. PUT and POST are -treated identically - request body is written into a file inside the media -directory, with the name equal to decoded request target. For requests using -chunked transfer encoding, the body shall also be temporarily cached in memory -and will be available to incoming GET requests while it is being received. -To GET requests the server will serve either the accordingly-named file from the -media directory or the aforementioned cache entry. +The server processes incoming HTTP GET, PUT, POST and DELETE requests. PUT and +POST are treated identically - request body is written into a file inside the +media directory, with the name equal to decoded request target. For requests +using chunked transfer encoding, the body shall also be temporarily cached in +memory and will be available to incoming GET requests while it is being +received. To GET requests the server will serve either the accordingly-named +file from the media directory or the aforementioned cache entry. +DELETE requests make the server remove accordingly-named files in the media +directory if they are not currently being uploaded. The server is written to be as simple as possible and is intended to be deployed as a backend behind a gateway HTTP server such as nginx (sample config is diff --git a/dash_server.py b/dash_server.py index 9e79c68..17a4ec8 100755 --- a/dash_server.py +++ b/dash_server.py @@ -159,14 +159,17 @@ class StreamCache: def __getitem__(self, key): self._logger.debug('reading from cache: %s', key) with self._lock: - return self._streams[key] + ret = self._streams[key] + if ret is None: + raise KeyError(key) + return ret @contextlib.contextmanager def add_entry(self, key, val): self._logger.debug('cache add: %s', key) with self._lock: if key in self._streams: - raise ValueError('Duplicate cache entry: %s' % key) + raise FileExistsError('Duplicate cache entry: %s' % key) self._streams[key] = val try: yield val @@ -295,6 +298,36 @@ class DashRequestHandler(hs.BaseHTTPRequestHandler): def do_PUT(self): return self.do_POST() + def do_DELETE(self): + self._log_request() + + local_path = self._process_path(self.path) + + # add a temporary None cache entry to make sure + # - it is not being uploaded right now + # - nobody starts uploading it until we are done with the deletion + with contextlib.ExitStack() as stack: + try: + stack.enter_context(self.server._streams.add_entry(local_path, None)) + except FileExistsError: + self._logger.error('DELETE request for open stream: %s' % + local_path.decode('utf-8', errors = 'backslashreplace')) + self.send_error(HTTPStatus.CONFLICT) + return + + targetpath = b'/'.join((self.server.serve_dir, local_path)) + try: + os.remove(targetpath) + except FileNotFoundError: + self._logger.error('DELETE request for non-existing file: %s' % + local_path.decode('utf-8', errors = 'backslashreplace')) + self.send_error(HTTPStatus.NOT_FOUND) + return + + self.send_response(HTTPStatus.NO_CONTENT) + self.send_header('Content-Length', '0') + self.end_headers() + class DashServer(hs.ThreadingHTTPServer): serve_dir = None -- cgit v1.2.3