Changeset View
Changeset View
Standalone View
Standalone View
woof
| Show All 11 Lines | |||||
| import readline | import readline | ||||
| import configparser | import configparser | ||||
| import shutil, tarfile, zipfile | import shutil, tarfile, zipfile | ||||
| import struct | import struct | ||||
| from io import BytesIO, StringIO | from io import BytesIO, StringIO | ||||
| maxdownloads = 1 | maxdownloads = 1 | ||||
| cpid = -1 | cpid = -1 | ||||
| compressed = 'gz' | compressed = "gz" | ||||
| upload = False | upload = False | ||||
| # Utility function to guess the IP (as a string) where the server can be | # Utility function to guess the IP (as a string) where the server can be | ||||
| # reached from the outside. Quite nasty problem actually. | # reached from the outside. Quite nasty problem actually. | ||||
| def find_ip (): | def find_ip(): | ||||
| # we get a UDP-socket for the TEST-networks reserved by IANA. | # we get a UDP-socket for the TEST-networks reserved by IANA. | ||||
| # It is highly unlikely, that there is special routing used | # It is highly unlikely, that there is special routing used | ||||
| # for these networks, hence the socket later should give us | # for these networks, hence the socket later should give us | ||||
| # the ip address of the default route. | # the ip address of the default route. | ||||
| # We're doing multiple tests, to guard against the computer being | # We're doing multiple tests, to guard against the computer being | ||||
| # part of a test installation. | # part of a test installation. | ||||
| candidates = [] | candidates = [] | ||||
| for test_ip in ["192.0.2.0", "198.51.100.0", "203.0.113.0"]: | for test_ip in ["192.0.2.0", "198.51.100.0", "203.0.113.0"]: | ||||
| s = socket.socket (socket.AF_INET, socket.SOCK_DGRAM) | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | ||||
| s.connect ((test_ip, 80)) | s.connect((test_ip, 80)) | ||||
| ip_addr = s.getsockname ()[0] | ip_addr = s.getsockname()[0] | ||||
| s.close () | s.close() | ||||
| if ip_addr in candidates: | if ip_addr in candidates: | ||||
| return ip_addr | return ip_addr | ||||
| candidates.append (ip_addr) | candidates.append(ip_addr) | ||||
| return candidates[0] | return candidates[0] | ||||
| def decode_multipart_form_data( | def decode_multipart_form_data( | ||||
| multipart_data: BinaryIO, headers: email.message.Message | multipart_data: BinaryIO, headers: email.message.Message | ||||
| ) -> list[tuple[dict[str, str], bytes]]: | ) -> list[tuple[dict[str, str], bytes]]: | ||||
| """Decode multipart form data""" | """Decode multipart form data""" | ||||
| content_type = headers["Content-Type"].encode("ascii") | content_type = headers["Content-Type"].encode("ascii") | ||||
| content_len = int(headers["Content-Length"]) | content_len = int(headers["Content-Length"]) | ||||
| data = multipart_data.read(content_len) | data = multipart_data.read(content_len) | ||||
| content = b"Content-Type: %b\r\n%b" % (content_type, data) | content = b"Content-Type: %b\r\n%b" % (content_type, data) | ||||
| parsed = email.parser.BytesParser().parsebytes(content) | parsed = email.parser.BytesParser().parsebytes(content) | ||||
| results = [] | results = [] | ||||
| for part in parsed.get_payload(): | for part in parsed.get_payload(): | ||||
| params = part.get_params(header="content-disposition") | params = part.get_params(header="content-disposition") | ||||
| payload: bytes = part.get_payload(decode=True) | payload: bytes = part.get_payload(decode=True) | ||||
| result = dict(params), payload | result = dict(params), payload | ||||
| results.append(result) | results.append(result) | ||||
| return results | return results | ||||
| # our own HTTP server class, fixing up a change in python 2.7 | # our own HTTP server class, fixing up a change in python 2.7 | ||||
| # since we do our fork() in the request handler | # since we do our fork() in the request handler | ||||
| # the server must not shutdown() the socket. | # the server must not shutdown() the socket. | ||||
| class ForkingHTTPServer (http.server.HTTPServer): | class ForkingHTTPServer(http.server.HTTPServer): | ||||
| def process_request (self, request, client_address): | def process_request(self, request, client_address): | ||||
| self.finish_request (request, client_address) | self.finish_request(request, client_address) | ||||
| self.close_request (request) | self.close_request(request) | ||||
| # Main class implementing an HTTP-Requesthandler, that serves just a single | # Main class implementing an HTTP-Requesthandler, that serves just a single | ||||
| # file and redirects all other requests to this file (this passes the actual | # file and redirects all other requests to this file (this passes the actual | ||||
| # filename to the client). | # filename to the client). | ||||
| # Currently it is impossible to serve different files with different | # Currently it is impossible to serve different files with different | ||||
| # instances of this class. | # instances of this class. | ||||
| class FileServHTTPRequestHandler (http.server.BaseHTTPRequestHandler): | class FileServHTTPRequestHandler(http.server.BaseHTTPRequestHandler): | ||||
| server_version = "Simons FileServer" | server_version = "Simons FileServer" | ||||
| protocol_version = "HTTP/1.0" | protocol_version = "HTTP/1.0" | ||||
| filename = "." | filename = "." | ||||
| def log_request (self, code='-', size='-'): | def log_request(self, code="-", size="-"): | ||||
| if code == 200: | if code == 200: | ||||
| super().log_request (code, size) | super().log_request(code, size) | ||||
| def do_POST (self): | def do_POST(self): | ||||
| global maxdownloads, upload | global maxdownloads, upload | ||||
| if not upload: | if not upload: | ||||
| self.send_error (501, "Unsupported method (POST)") | self.send_error(501, "Unsupported method (POST)") | ||||
| return | return | ||||
| multi_form = decode_multipart_form_data(self.rfile, self.headers) | multi_form = decode_multipart_form_data(self.rfile, self.headers) | ||||
| for form_dict, content in multi_form: | for form_dict, content in multi_form: | ||||
| if form_dict.get("name") == "upfile": | if form_dict.get("name") == "upfile": | ||||
| break | break | ||||
| else: | else: | ||||
| # Went through without break, did not find | # Went through without break, did not find | ||||
| self.send_error(403, "No upload provided") | self.send_error(403, "No upload provided") | ||||
| return | return | ||||
| if not content or not form_dict.get("filename"): | if not content or not form_dict.get("filename"): | ||||
| self.send_error (403, "No upload provided") | self.send_error(403, "No upload provided") | ||||
| return | return | ||||
| upfilename = form_dict["filename"] | upfilename = form_dict["filename"] | ||||
| if "\\" in upfilename: | if "\\" in upfilename: | ||||
| upfilename = upfilename.rsplit ("\\", 1)[-1] | upfilename = upfilename.rsplit("\\", 1)[-1] | ||||
| upfilename = os.path.basename (upfilename) | upfilename = os.path.basename(upfilename) | ||||
| destfile = None | destfile = None | ||||
| for suffix in ["", ".1", ".2", ".3", ".4", ".5", ".6", ".7", ".8", ".9"]: | for suffix in ["", ".1", ".2", ".3", ".4", ".5", ".6", ".7", ".8", ".9"]: | ||||
| destfilename = os.path.join (".", upfilename + suffix) | destfilename = os.path.join(".", upfilename + suffix) | ||||
| try: | try: | ||||
| destfile = os.open (destfilename, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644) | destfile = os.open( | ||||
| destfilename, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644 | |||||
| ) | |||||
| break | break | ||||
| except OSError as ex: | except OSError as ex: | ||||
| if ex.errno == errno.EEXIST: | if ex.errno == errno.EEXIST: | ||||
| continue | continue | ||||
| raise | raise | ||||
| if not destfile: | if not destfile: | ||||
| upfilename += "." | upfilename += "." | ||||
| destfile, destfilename = tempfile.mkstemp (prefix = upfilename, dir = ".") | destfile, destfilename = tempfile.mkstemp(prefix=upfilename, dir=".") | ||||
| print ("Accepting uploaded file: %s -> %s" % (upfilename, destfilename), file=sys.stderr) | print( | ||||
| "Accepting uploaded file: %s -> %s" % (upfilename, destfilename), | |||||
| file=sys.stderr, | |||||
| ) | |||||
| with BytesIO(content) as readfile: | with BytesIO(content) as readfile: | ||||
| with open(destfile, "wb") as writefile: | with open(destfile, "wb") as writefile: | ||||
| shutil.copyfileobj (readfile, writefile) | shutil.copyfileobj(readfile, writefile) | ||||
| # if upfile.done == -1: | # if upfile.done == -1: | ||||
| # self.send_error (408, "upload interrupted") | # self.send_error (408, "upload interrupted") | ||||
| txt = b"""\ | txt = b"""\ | ||||
| <!DOCTYPE html> | <!DOCTYPE html> | ||||
| <html> | <html> | ||||
| <head><title>Woof Upload</title></head> | <head><title>Woof Upload</title></head> | ||||
| <body> | <body> | ||||
| <h1>Woof Upload complete</title></h1> | <h1>Woof Upload complete</title></h1> | ||||
| <p>Thanks a lot!</p> | <p>Thanks a lot!</p> | ||||
| </body> | </body> | ||||
| </html> | </html> | ||||
| """ | """ | ||||
| self.send_response (200) | self.send_response(200) | ||||
| self.send_header ("Content-Type", "text/html") | self.send_header("Content-Type", "text/html") | ||||
| self.send_header ("Content-Length", str (len (txt))) | self.send_header("Content-Length", str(len(txt))) | ||||
| self.end_headers () | self.end_headers() | ||||
| self.wfile.write (txt) | self.wfile.write(txt) | ||||
| maxdownloads -= 1 | maxdownloads -= 1 | ||||
| return | return | ||||
| def do_GET (self): | def do_GET(self): | ||||
| global maxdownloads, cpid, compressed, upload | global maxdownloads, cpid, compressed, upload | ||||
| # Form for uploading a file | # Form for uploading a file | ||||
| if upload: | if upload: | ||||
| txt = b"""\ | txt = b"""\ | ||||
| <!DOCTYPE html> | <!DOCTYPE html> | ||||
| <html> | <html> | ||||
| <head><title>Woof Upload</title></head> | <head><title>Woof Upload</title></head> | ||||
| <body> | <body> | ||||
| <h1>Woof Upload</title></h1> | <h1>Woof Upload</title></h1> | ||||
| <form name="upload" method="POST" enctype="multipart/form-data"> | <form name="upload" method="POST" enctype="multipart/form-data"> | ||||
| <p><input type="file" name="upfile" /></p> | <p><input type="file" name="upfile" /></p> | ||||
| <p><input type="submit" value="Upload!" /></p> | <p><input type="submit" value="Upload!" /></p> | ||||
| </form> | </form> | ||||
| </body> | </body> | ||||
| </html> | </html> | ||||
| """ | """ | ||||
| self.send_response (200) | self.send_response(200) | ||||
| self.send_header ("Content-Type", "text/html") | self.send_header("Content-Type", "text/html") | ||||
| self.send_header ("Content-Length", str (len (txt))) | self.send_header("Content-Length", str(len(txt))) | ||||
| self.end_headers () | self.end_headers() | ||||
| self.wfile.write (txt) | self.wfile.write(txt) | ||||
| return | return | ||||
| # Redirect any request to the filename of the file to serve. | # Redirect any request to the filename of the file to serve. | ||||
| # This hands over the filename to the client. | # This hands over the filename to the client. | ||||
| self.path = urllib.parse.quote (urllib.parse.unquote (self.path)) | self.path = urllib.parse.quote(urllib.parse.unquote(self.path)) | ||||
| location = "/" + urllib.parse.quote (os.path.basename (self.filename)) | location = "/" + urllib.parse.quote(os.path.basename(self.filename)) | ||||
| if os.path.isdir (self.filename): | if os.path.isdir(self.filename): | ||||
| if compressed == 'gz': | if compressed == "gz": | ||||
| location += ".tar.gz" | location += ".tar.gz" | ||||
| elif compressed == 'bz2': | elif compressed == "bz2": | ||||
| location += ".tar.bz2" | location += ".tar.bz2" | ||||
| elif compressed == 'zip': | elif compressed == "zip": | ||||
| location += ".zip" | location += ".zip" | ||||
| else: | else: | ||||
| location += ".tar" | location += ".tar" | ||||
| if self.path != location: | if self.path != location: | ||||
| txt = """\ | txt = ( | ||||
| """\ | |||||
| <!DOCTYPE html> | <!DOCTYPE html> | ||||
| <html> | <html> | ||||
| <head><title>302 Found</title></head> | <head><title>302 Found</title></head> | ||||
| <body>302 Found <a href="%s">here</a>.</body> | <body>302 Found <a href="%s">here</a>.</body> | ||||
| </html>\n""" % location | </html>\n""" | ||||
| txt = txt.encode ('ascii') | % location | ||||
| ) | |||||
| txt = txt.encode("ascii") | |||||
| self.send_response (302) | self.send_response(302) | ||||
| self.send_header ("Location", location) | self.send_header("Location", location) | ||||
| self.send_header ("Content-Type", "text/html") | self.send_header("Content-Type", "text/html") | ||||
| self.send_header ("Content-Length", str (len (txt))) | self.send_header("Content-Length", str(len(txt))) | ||||
| self.end_headers () | self.end_headers() | ||||
| self.wfile.write (txt) | self.wfile.write(txt) | ||||
| return | return | ||||
| maxdownloads -= 1 | maxdownloads -= 1 | ||||
| # let a separate process handle the actual download, so that | # let a separate process handle the actual download, so that | ||||
| # multiple downloads can happen simultaneously. | # multiple downloads can happen simultaneously. | ||||
| cpid = os.fork () | cpid = os.fork() | ||||
| if cpid == 0: | if cpid == 0: | ||||
| # Child process | # Child process | ||||
| type = None | type = None | ||||
| if os.path.isfile (self.filename): | if os.path.isfile(self.filename): | ||||
| type = "file" | type = "file" | ||||
| elif os.path.isdir (self.filename): | elif os.path.isdir(self.filename): | ||||
| type = "dir" | type = "dir" | ||||
| if not type: | if not type: | ||||
| print ("can only serve files or directories. Aborting.", file=sys.stderr) | print("can only serve files or directories. Aborting.", file=sys.stderr) | ||||
| sys.exit (1) | sys.exit(1) | ||||
| self.send_response (200) | self.send_response(200) | ||||
| self.send_header ("Content-Type", "application/octet-stream") | self.send_header("Content-Type", "application/octet-stream") | ||||
| self.send_header ("Content-Disposition", "attachment;filename=%s" % urllib.parse.quote (os.path.basename (self.filename + self.archive_ext))) | self.send_header( | ||||
| "Content-Disposition", | |||||
| "attachment;filename=%s" | |||||
| % urllib.parse.quote( | |||||
| os.path.basename(self.filename + self.archive_ext) | |||||
| ), | |||||
| ) | |||||
| if os.path.isfile (self.filename): | if os.path.isfile(self.filename): | ||||
| self.send_header ("Content-Length", | self.send_header("Content-Length", str(os.path.getsize(self.filename))) | ||||
| str(os.path.getsize (self.filename))) | |||||
| self.end_headers () | self.end_headers() | ||||
| try: | try: | ||||
| if type == "file": | if type == "file": | ||||
| with open (self.filename, "rb") as datafile: | with open(self.filename, "rb") as datafile: | ||||
| shutil.copyfileobj (datafile, self.wfile) | shutil.copyfileobj(datafile, self.wfile) | ||||
| elif type == "dir": | elif type == "dir": | ||||
| if compressed == 'zip': | if compressed == "zip": | ||||
| with zipfile.ZipFile( | with zipfile.ZipFile( | ||||
| self.wfile, "w", zipfile.ZIP_DEFLATED | self.wfile, "w", zipfile.ZIP_DEFLATED | ||||
| ) as zfile: | ) as zfile: | ||||
| stripoff = os.path.dirname (self.filename) + os.sep | stripoff = os.path.dirname(self.filename) + os.sep | ||||
| for root, dirs, files in os.walk (self.filename): | for root, dirs, files in os.walk(self.filename): | ||||
| for f in files: | for f in files: | ||||
| filename = os.path.join (root, f) | filename = os.path.join(root, f) | ||||
| if filename[:len (stripoff)] != stripoff: | if filename[: len(stripoff)] != stripoff: | ||||
| raise RuntimeError ("invalid filename assumptions, please report!") | raise RuntimeError( | ||||
| "invalid filename assumptions, please report!" | |||||
| ) | |||||
| zfile.write (filename, filename[len (stripoff):]) | zfile.write(filename, filename[len(stripoff) :]) | ||||
| else: | else: | ||||
| with tarfile.open( | with tarfile.open( | ||||
| mode=("w|" + compressed), fileobj=self.wfile | mode=("w|" + compressed), fileobj=self.wfile | ||||
| ) as tfile: | ) as tfile: | ||||
| tfile.add (self.filename, | tfile.add( | ||||
| arcname=os.path.basename (self.filename)) | self.filename, arcname=os.path.basename(self.filename) | ||||
| ) | |||||
| except Exception as ex: | except Exception as ex: | ||||
| print (ex) | print(ex) | ||||
| print ("Connection broke. Aborting", file=sys.stderr) | print("Connection broke. Aborting", file=sys.stderr) | ||||
| def serve_files (filename, maxdown = 1, ip_addr = '', port = 8080): | def serve_files(filename, maxdown=1, ip_addr="", port=8080): | ||||
| global maxdownloads | global maxdownloads | ||||
| maxdownloads = maxdown | maxdownloads = maxdown | ||||
| archive_ext = "" | archive_ext = "" | ||||
| if filename and os.path.isdir (filename): | if filename and os.path.isdir(filename): | ||||
| if compressed == 'gz': | if compressed == "gz": | ||||
| archive_ext = ".tar.gz" | archive_ext = ".tar.gz" | ||||
| elif compressed == 'bz2': | elif compressed == "bz2": | ||||
| archive_ext = ".tar.bz2" | archive_ext = ".tar.bz2" | ||||
| elif compressed == 'zip': | elif compressed == "zip": | ||||
| archive_ext = ".zip" | archive_ext = ".zip" | ||||
| else: | else: | ||||
| archive_ext = ".tar" | archive_ext = ".tar" | ||||
| # We have to somehow push the filename of the file to serve to the | # We have to somehow push the filename of the file to serve to the | ||||
| # class handling the requests. This is an evil way to do this... | # class handling the requests. This is an evil way to do this... | ||||
| FileServHTTPRequestHandler.filename = filename | FileServHTTPRequestHandler.filename = filename | ||||
| FileServHTTPRequestHandler.archive_ext = archive_ext | FileServHTTPRequestHandler.archive_ext = archive_ext | ||||
| try: | try: | ||||
| httpd = ForkingHTTPServer ((ip_addr, port), FileServHTTPRequestHandler) | httpd = ForkingHTTPServer((ip_addr, port), FileServHTTPRequestHandler) | ||||
| except socket.error: | except socket.error: | ||||
| print ("cannot bind to IP address '%s' port %d" % (ip_addr, port), file=sys.stderr) | print( | ||||
| "cannot bind to IP address '%s' port %d" % (ip_addr, port), file=sys.stderr | |||||
| ) | |||||
| sys.exit (1) | sys.exit(1) | ||||
| if not ip_addr: | if not ip_addr: | ||||
| ip_addr = find_ip () | ip_addr = find_ip() | ||||
| if ip_addr: | if ip_addr: | ||||
| if filename: | if filename: | ||||
| location = (f"http://{ip_addr}:{httpd.server_port}/" + | location = f"http://{ip_addr}:{httpd.server_port}/" + urllib.parse.quote( | ||||
| urllib.parse.quote (os.path.basename (filename + archive_ext))) | os.path.basename(filename + archive_ext) | ||||
| ) | |||||
| else: | else: | ||||
| location = "http://%s:%s/" % (ip_addr, httpd.server_port) | location = "http://%s:%s/" % (ip_addr, httpd.server_port) | ||||
| print ("Now serving on %s" % location) | print("Now serving on %s" % location) | ||||
| while cpid != 0 and maxdownloads > 0: | while cpid != 0 and maxdownloads > 0: | ||||
| httpd.handle_request () | httpd.handle_request() | ||||
| def usage (defport, defmaxdown, errmsg = None): | def usage(defport, defmaxdown, errmsg=None): | ||||
| name = os.path.basename (sys.argv[0]) | name = os.path.basename(sys.argv[0]) | ||||
| print (""" | print( | ||||
| """ | |||||
| Usage: %s [-i <ip_addr>] [-p <port>] [-c <count>] <file> | Usage: %s [-i <ip_addr>] [-p <port>] [-c <count>] <file> | ||||
| %s [-i <ip_addr>] [-p <port>] [-c <count>] [-z|-j|-Z|-u] <dir> | %s [-i <ip_addr>] [-p <port>] [-c <count>] [-z|-j|-Z|-u] <dir> | ||||
| %s [-i <ip_addr>] [-p <port>] [-c <count>] -s | %s [-i <ip_addr>] [-p <port>] [-c <count>] -s | ||||
| %s [-i <ip_addr>] [-p <port>] [-c <count>] -U | %s [-i <ip_addr>] [-p <port>] [-c <count>] -U | ||||
| %s <url> | %s <url> | ||||
| Serves a single file <count> times via http on port <port> on IP | Serves a single file <count> times via http on port <port> on IP | ||||
| Show All 20 Lines | def usage(defport, defmaxdown, errmsg=None): | ||||
| Sample file: | Sample file: | ||||
| [main] | [main] | ||||
| port = 8008 | port = 8008 | ||||
| count = 2 | count = 2 | ||||
| ip = 127.0.0.1 | ip = 127.0.0.1 | ||||
| compressed = gz | compressed = gz | ||||
| """ % (name, name, name, name, name, name, defmaxdown, defport), file=sys.stderr) | """ | ||||
| % (name, name, name, name, name, name, defmaxdown, defport), | |||||
| file=sys.stderr, | |||||
| ) | |||||
| if errmsg: | if errmsg: | ||||
| print (errmsg, file=sys.stderr) | print(errmsg, file=sys.stderr) | ||||
| print (file=sys.stderr) | print(file=sys.stderr) | ||||
| sys.exit (1) | sys.exit(1) | ||||
| def woof_client (url): | def woof_client(url): | ||||
| urlparts = urllib.parse.urlparse (url, "http") | urlparts = urllib.parse.urlparse(url, "http") | ||||
| if urlparts[0] not in [ "http", "https" ] or urlparts[1] == '': | if urlparts[0] not in ["http", "https"] or urlparts[1] == "": | ||||
| return None | return None | ||||
| fname = None | fname = None | ||||
| f = urllib.request.urlopen (url) | f = urllib.request.urlopen(url) | ||||
| f_meta = f.info () | f_meta = f.info() | ||||
| disp = f_meta["Content-Disposition"] | disp = f_meta["Content-Disposition"] | ||||
| if disp: | if disp: | ||||
| disp = disp.split (";") | disp = disp.split(";") | ||||
| if disp and disp[0].lower () == 'attachment': | if disp and disp[0].lower() == "attachment": | ||||
| fname = [x[9:] for x in disp[1:] if x[:9].lower () == "filename="] | fname = [x[9:] for x in disp[1:] if x[:9].lower() == "filename="] | ||||
| if len (fname): | if len(fname): | ||||
| fname = fname[0] | fname = fname[0] | ||||
| else: | else: | ||||
| fname = None | fname = None | ||||
| if fname == None: | if fname == None: | ||||
| url = f.geturl () | url = f.geturl() | ||||
| urlparts = urllib.parse.urlparse (url) | urlparts = urllib.parse.urlparse(url) | ||||
| fname = urlparts[2] | fname = urlparts[2] | ||||
| if not fname: | if not fname: | ||||
| fname = "woof-out.bin" | fname = "woof-out.bin" | ||||
| if fname: | if fname: | ||||
| fname = urllib.parse.unquote (fname) | fname = urllib.parse.unquote(fname) | ||||
| fname = os.path.basename (fname) | fname = os.path.basename(fname) | ||||
| readline.set_startup_hook (lambda: readline.insert_text (fname)) | readline.set_startup_hook(lambda: readline.insert_text(fname)) | ||||
| fname = input ("Enter target filename: ") | fname = input("Enter target filename: ") | ||||
| readline.set_startup_hook (None) | readline.set_startup_hook(None) | ||||
| override = False | override = False | ||||
| destfile = None | destfile = None | ||||
| destfilename = os.path.join (".", fname) | destfilename = os.path.join(".", fname) | ||||
| try: | try: | ||||
| destfile = os.open (destfilename, | destfile = os.open(destfilename, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644) | ||||
| os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644) | |||||
| except OSError as e: | except OSError as e: | ||||
| if e.errno == errno.EEXIST: | if e.errno == errno.EEXIST: | ||||
| override = input ("File exists. Overwrite (y/n)? ") | override = input("File exists. Overwrite (y/n)? ") | ||||
| override = override.lower () in [ "y", "yes" ] | override = override.lower() in ["y", "yes"] | ||||
| else: | else: | ||||
| raise | raise | ||||
| if destfile == None: | if destfile == None: | ||||
| if override == True: | if override == True: | ||||
| destfile = os.open (destfilename, os.O_WRONLY | os.O_CREAT, 0o644) | destfile = os.open(destfilename, os.O_WRONLY | os.O_CREAT, 0o644) | ||||
| else: | else: | ||||
| for suffix in [".1", ".2", ".3", ".4", ".5", ".6", ".7", ".8", ".9"]: | for suffix in [".1", ".2", ".3", ".4", ".5", ".6", ".7", ".8", ".9"]: | ||||
| destfilename = os.path.join (".", fname + suffix) | destfilename = os.path.join(".", fname + suffix) | ||||
| try: | try: | ||||
| destfile = os.open (destfilename, | destfile = os.open( | ||||
| os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644) | destfilename, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644 | ||||
| ) | |||||
| break | break | ||||
| except OSError as e: | except OSError as e: | ||||
| if e.errno == errno.EEXIST: | if e.errno == errno.EEXIST: | ||||
| continue | continue | ||||
| raise | raise | ||||
| if not destfile: | if not destfile: | ||||
| destfile, destfilename = tempfile.mkstemp (prefix = fname + ".", | destfile, destfilename = tempfile.mkstemp(prefix=fname + ".", dir=".") | ||||
| dir = ".") | |||||
| print ("alternate filename is:", destfilename) | print("alternate filename is:", destfilename) | ||||
| print ("downloading file: %s -> %s" % (fname, destfilename)) | print("downloading file: %s -> %s" % (fname, destfilename)) | ||||
| shutil.copyfileobj (f, os.fdopen (destfile, "wb")) | shutil.copyfileobj(f, os.fdopen(destfile, "wb")) | ||||
| return 1; | return 1 | ||||
| def main (): | def main(): | ||||
| global cpid, upload, compressed | global cpid, upload, compressed | ||||
| maxdown = 1 | maxdown = 1 | ||||
| port = 8080 | port = 8080 | ||||
| ip_addr = '' | ip_addr = "" | ||||
| config = configparser.ConfigParser () | config = configparser.ConfigParser() | ||||
| config.read (['/etc/woofrc', os.path.expanduser ('~/.woofrc')]) | config.read(["/etc/woofrc", os.path.expanduser("~/.woofrc")]) | ||||
| if config.has_option ('main', 'port'): | if config.has_option("main", "port"): | ||||
| port = config.getint ('main', 'port') | port = config.getint("main", "port") | ||||
| if config.has_option ('main', 'count'): | if config.has_option("main", "count"): | ||||
| maxdown = config.getint ('main', 'count') | maxdown = config.getint("main", "count") | ||||
| if config.has_option ('main', 'ip'): | if config.has_option("main", "ip"): | ||||
| ip_addr = config.get ('main', 'ip') | ip_addr = config.get("main", "ip") | ||||
| if config.has_option ('main', 'compressed'): | if config.has_option("main", "compressed"): | ||||
| formats = { 'gz' : 'gz', | formats = { | ||||
| 'true' : 'gz', | "gz": "gz", | ||||
| 'bz' : 'bz2', | "true": "gz", | ||||
| 'bz2' : 'bz2', | "bz": "bz2", | ||||
| 'zip' : 'zip', | "bz2": "bz2", | ||||
| 'off' : '', | "zip": "zip", | ||||
| 'false' : '' } | "off": "", | ||||
| compressed = config.get ('main', 'compressed') | "false": "", | ||||
| compressed = formats.get (compressed, 'gz') | } | ||||
| compressed = config.get("main", "compressed") | |||||
| compressed = formats.get(compressed, "gz") | |||||
| defaultport = port | defaultport = port | ||||
| defaultmaxdown = maxdown | defaultmaxdown = maxdown | ||||
| try: | try: | ||||
| options, filenames = getopt.gnu_getopt (sys.argv[1:], "hUszjZui:c:p:") | options, filenames = getopt.gnu_getopt(sys.argv[1:], "hUszjZui:c:p:") | ||||
| except getopt.GetoptError as desc: | except getopt.GetoptError as desc: | ||||
| usage (defaultport, defaultmaxdown, desc) | usage(defaultport, defaultmaxdown, desc) | ||||
| for option, val in options: | for option, val in options: | ||||
| if option == '-c': | if option == "-c": | ||||
| try: | try: | ||||
| maxdown = int (val) | maxdown = int(val) | ||||
| if maxdown <= 0: | if maxdown <= 0: | ||||
| raise ValueError | raise ValueError | ||||
| except ValueError: | except ValueError: | ||||
| usage (defaultport, defaultmaxdown, | usage( | ||||
| defaultport, | |||||
| defaultmaxdown, | |||||
| "invalid download count: %r. " | "invalid download count: %r. " | ||||
| "Please specify an integer >= 0." % val) | "Please specify an integer >= 0." % val, | ||||
| ) | |||||
| elif option == '-i': | elif option == "-i": | ||||
| ip_addr = val | ip_addr = val | ||||
| elif option == '-p': | elif option == "-p": | ||||
| try: | try: | ||||
| port = int (val) | port = int(val) | ||||
| except ValueError: | except ValueError: | ||||
| usage (defaultport, defaultmaxdown, | usage( | ||||
| "invalid port number: %r. Please specify an integer" % val) | defaultport, | ||||
| defaultmaxdown, | |||||
| "invalid port number: %r. Please specify an integer" % val, | |||||
| ) | |||||
| elif option == '-s': | elif option == "-s": | ||||
| filenames.append (__file__) | filenames.append(__file__) | ||||
| elif option == '-h': | elif option == "-h": | ||||
| usage (defaultport, defaultmaxdown) | usage(defaultport, defaultmaxdown) | ||||
| elif option == '-U': | elif option == "-U": | ||||
| upload = True | upload = True | ||||
| elif option == '-z': | elif option == "-z": | ||||
| compressed = 'gz' | compressed = "gz" | ||||
| elif option == '-j': | elif option == "-j": | ||||
| compressed = 'bz2' | compressed = "bz2" | ||||
| elif option == '-Z': | elif option == "-Z": | ||||
| compressed = 'zip' | compressed = "zip" | ||||
| elif option == '-u': | elif option == "-u": | ||||
| compressed = '' | compressed = "" | ||||
| else: | else: | ||||
| usage (defaultport, defaultmaxdown, "Unknown option: %r" % option) | usage(defaultport, defaultmaxdown, "Unknown option: %r" % option) | ||||
| if upload: | if upload: | ||||
| if len (filenames) > 0: | if len(filenames) > 0: | ||||
| usage (defaultport, defaultmaxdown, | usage( | ||||
| "Conflicting usage: simultaneous up- and download not supported.") | defaultport, | ||||
| defaultmaxdown, | |||||
| "Conflicting usage: simultaneous up- and download not supported.", | |||||
| ) | |||||
| filename = None | filename = None | ||||
| else: | else: | ||||
| if len (filenames) == 1: | if len(filenames) == 1: | ||||
| if woof_client (filenames[0]) != None: | if woof_client(filenames[0]) != None: | ||||
| sys.exit (0) | sys.exit(0) | ||||
| filename = os.path.abspath (filenames[0]) | filename = os.path.abspath(filenames[0]) | ||||
| else: | else: | ||||
| usage (defaultport, defaultmaxdown, | usage( | ||||
| "Can only serve single files/directories.") | defaultport, defaultmaxdown, "Can only serve single files/directories." | ||||
| ) | |||||
| if not os.path.exists (filename): | if not os.path.exists(filename): | ||||
| usage (defaultport, defaultmaxdown, | usage( | ||||
| "%s: No such file or directory" % filenames[0]) | defaultport, | ||||
| defaultmaxdown, | |||||
| "%s: No such file or directory" % filenames[0], | |||||
| ) | |||||
| if not (os.path.isfile (filename) or os.path.isdir (filename)): | if not (os.path.isfile(filename) or os.path.isdir(filename)): | ||||
| usage (defaultport, defaultmaxdown, | usage( | ||||
| "%s: Neither file nor directory" % filenames[0]) | defaultport, | ||||
| defaultmaxdown, | |||||
| "%s: Neither file nor directory" % filenames[0], | |||||
| ) | |||||
| serve_files (filename, maxdown, ip_addr, port) | serve_files(filename, maxdown, ip_addr, port) | ||||
| # wait for child processes to terminate | # wait for child processes to terminate | ||||
| if cpid != 0: | if cpid != 0: | ||||
| try: | try: | ||||
| while 1: | while 1: | ||||
| os.wait () | os.wait() | ||||
| except OSError: | except OSError: | ||||
| pass | pass | ||||
| if __name__ == "__main__": | |||||
| if __name__=='__main__': | |||||
| try: | try: | ||||
| main () | main() | ||||
| except KeyboardInterrupt: | except KeyboardInterrupt: | ||||
| print () | print() | ||||
Nasqueron DevCentral · If it had been much bigger the moon would have had a core of ice. · Powered by Phabricator