From: Michael Tremer Date: Thu, 14 Jul 2022 16:07:14 +0000 (+0000) Subject: hub: Move upload handlers into their own file X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a097e88a213ece68e6555a22d3f1dbba9be688f6;p=pbs.git hub: Move upload handlers into their own file Signed-off-by: Michael Tremer --- diff --git a/Makefile.am b/Makefile.am index 79a53a21..73d4ef0c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -120,7 +120,8 @@ hub_PYTHON = \ src/hub/builds.py \ src/hub/handlers.py \ src/hub/jobs.py \ - src/hub/queue.py + src/hub/queue.py \ + src/hub/uploads.py hubdir = $(buildservicedir)/hub diff --git a/src/hub/__init__.py b/src/hub/__init__.py index 952d461a..4bc3a609 100644 --- a/src/hub/__init__.py +++ b/src/hub/__init__.py @@ -10,6 +10,7 @@ from . import builds from . import handlers from . import jobs from . import queue +from . import uploads class Application(tornado.web.Application): def __init__(self, **settings): @@ -46,7 +47,7 @@ class Application(tornado.web.Application): (r"/queue", queue.QueueHandler), # Uploads - (r"/upload", handlers.UploadHandler), + (r"/uploads", uploads.CreateHandler), ], **settings) # Launch backend diff --git a/src/hub/handlers.py b/src/hub/handlers.py index f8009fd7..6ffa91f2 100644 --- a/src/hub/handlers.py +++ b/src/hub/handlers.py @@ -1,11 +1,8 @@ #!/usr/bin/python import base64 -import hashlib -import hmac import json import logging -import tempfile import tornado.web from .. import builds @@ -137,108 +134,6 @@ class ErrorTestHandler(BaseHandler): raise tornado.web.HTTPError(error_code) -# Uploads - -@tornado.web.stream_request_body -class UploadHandler(BaseHandler): - @tornado.web.authenticated - def initialize(self): - # Fetch the filename - self.filename = self.get_argument("filename") - - # Fetch file size - self.filesize = self.get_argument_int("size") - - # Check quota - if isinstance(self.current_user, users.User): - try: - self.current_user.check_quota(self.filesize) - except users.QuotaExceededError as e: - raise tornado.web.HTTPError(400, - "Quota exceeded for %s" % self.current_user) from e - - # Count how many bytes have been received - self.bytes_read = 0 - - # Allocate a temporary file - self.f = self.backend.uploads.allocate_file() - - self.h, self.hexdigest = self._setup_digest() - - def data_received(self, data): - """ - Called when some data is being received - """ - self.bytes_read += len(data) - - # Abort if we have received more data than expected - if self.bytes_read > self.filesize: - # 422 - Unprocessable Entity - raise tornado.web.HTTPError(422) - - # Update the digest - self.h.update(data) - - # Write payload - self.f.write(data) - - async def put(self): - """ - Called after the entire file has been received - """ - log.debug("Finished receiving data") - - # Finish computing the hexdigest - computed_hexdigest = self.h.hexdigest() - - # Check if the hexdigest matches - # If not, we will raise an error - if not hmac.compare_digest(self.hexdigest, computed_hexdigest): - # 422 - Unprocessable Entity - raise tornado.web.HTTPError(422) - - # Create a new upload object - with self.db.transaction(): - upload = self.backend.uploads.create( - self.filename, - self.f.name, - builder=self.builder, - user=self.user, - ) - - # Free the temporary file (to prevent cleanup) - self.f = None - - # Send the ID of the upload back to the client - self.finish({ - "id" : upload.uuid, - "expires_at" : upload.expires_at.isoformat(), - }) - - def _setup_digest(self): - # Fetch the digest argument - digest = self.get_argument("digest") - - # Find the algorithm - algo, delim, hexdigest = digest.partition(":") - - try: - h = hashlib.new(algo) - except ValueError as e: - raise tornado.web.HTTPError(415) from e - - return h, hexdigest - - def on_connection_close(self): - """ - Called when a connection was unexpectedly closed - """ - # Try deleting the file - if self.f: - log.debug("Deleting temporary file %s" % self.f.name) - os.unlink(self.f.name) - - # Builds class BuildsGetHandler(BaseHandler): diff --git a/src/hub/uploads.py b/src/hub/uploads.py new file mode 100644 index 00000000..b653e321 --- /dev/null +++ b/src/hub/uploads.py @@ -0,0 +1,131 @@ +#!/usr/bin/python3 +############################################################################### +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2011 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +############################################################################### + +import hashlib +import hmac +import logging +import os +import tornado.web + +from .handlers import BaseHandler +from .. import users + +# Setup logging +log = logging.getLogger("pakfire.hub.uploads") + +@tornado.web.stream_request_body +class CreateHandler(BaseHandler): + @tornado.web.authenticated + def initialize(self): + # Fetch the filename + self.filename = self.get_argument("filename") + + # Fetch file size + self.filesize = self.get_argument_int("size") + + # Check quota + if isinstance(self.current_user, users.User): + try: + self.current_user.check_quota(self.filesize) + except users.QuotaExceededError as e: + raise tornado.web.HTTPError(400, + "Quota exceeded for %s" % self.current_user) from e + + # Count how many bytes have been received + self.bytes_read = 0 + + # Allocate a temporary file + self.f = self.backend.uploads.allocate_file() + + self.h, self.hexdigest = self._setup_digest() + + def data_received(self, data): + """ + Called when some data is being received + """ + self.bytes_read += len(data) + + # Abort if we have received more data than expected + if self.bytes_read > self.filesize: + # 422 - Unprocessable Entity + raise tornado.web.HTTPError(422) + + # Update the digest + self.h.update(data) + + # Write payload + self.f.write(data) + + async def put(self): + """ + Called after the entire file has been received + """ + log.debug("Finished receiving data") + + # Finish computing the hexdigest + computed_hexdigest = self.h.hexdigest() + + # Check if the hexdigest matches + # If not, we will raise an error + if not hmac.compare_digest(self.hexdigest, computed_hexdigest): + # 422 - Unprocessable Entity + raise tornado.web.HTTPError(422) + + # Create a new upload object + with self.db.transaction(): + upload = self.backend.uploads.create( + self.filename, + self.f.name, + builder=self.builder, + user=self.user, + ) + + # Free the temporary file (to prevent cleanup) + self.f = None + + # Send the ID of the upload back to the client + self.finish({ + "id" : upload.uuid, + "expires_at" : upload.expires_at.isoformat(), + }) + + def _setup_digest(self): + # Fetch the digest argument + digest = self.get_argument("digest") + + # Find the algorithm + algo, delim, hexdigest = digest.partition(":") + + try: + h = hashlib.new(algo) + except ValueError as e: + raise tornado.web.HTTPError(415) from e + + return h, hexdigest + + def on_connection_close(self): + """ + Called when a connection was unexpectedly closed + """ + # Try deleting the file + if self.f: + log.debug("Deleting temporary file %s" % self.f.name) + os.unlink(self.f.name)