Open beardhatcode opened 4 years ago
Hi,
I started to create a py3 version of woof a couple of months ago, and now I noticed that you already pushed it here.
It's practically the same, but:
Just wanted to put this on your radar. I auropep8ed my code, so below a diff between our versions.
My code is at https://github.com/beardhatcode/python3-woof
If you are interested, I can make a PR for the tests and/or the removal of the evilZipWrapper (or you can just steal it).
1c1 < #!/usr/bin/env python3 --- > #!/usr/bin/env python 27a28 > # Python 3 support by Robbert Gurdeep Singh <git@beardhatcode.be> 34d34 < import subprocess 37c37 < import urllib.request --- > import urllib 54,103d53 < class EvilZipStreamWrapper(TM): < def __init__(self, victim): < self.victim_fd = victim < self.position = 0 < self.tells = [] < self.in_file_data = 0 < < def tell(self): < self.tells.append(self.position) < return self.position < < def seek(self, offset, whence=0): < if offset != 0: < if offset == self.tells[0] + 14: < # the zipfile module tries to fix up the file header. < # write Data descriptor header instead, < # the next write from zipfile < # is CRC, compressed_size and file_size (as required) < self.write(b"PK\007\010") < elif offset == self.tells[1]: < # the zipfile module goes to the end of the file. The next < # data written definitely is infrastructure (in_file_data = 0) < self.tells = [] < self.in_file_data = 0 < else: < raise IOError("unexpected seek for EvilZipStreamWrapper") < < def write(self, data): < # only test for headers if we know that we're not writing < # (potentially compressed) data. < if self.in_file_data == 0: < if data[:4] == zipfile.stringFileHeader: < # fix the file header for extra Data descriptor < hdr = list(struct.unpack(zipfile.structFileHeader, data[:30])) < hdr[3] |= (1 << 3) < data = struct.pack(zipfile.structFileHeader, *hdr) + data[30:] < self.in_file_data = 1 < elif data[:4] == zipfile.stringCentralDir: < # fix the directory entry to match file header. < hdr = list(struct.unpack(zipfile.structCentralDir, data[:46])) < hdr[5] |= (1 << 3) < data = struct.pack(zipfile.structCentralDir, *hdr) + data[46:] < < self.position += len(data) < self.victim_fd.write(data) < < def __getattr__(self, name): < return getattr(self.victim_fd, name) < < 164d113 < ctype, pdict = cgi.parse_header(self.headers['Content-Type']) 170c119 < if "upfile" not in form: --- > if not "upfile" in form: 191,192c140,141 < 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) 204,205c153,154 < print("accepting uploaded file: %s -> %s" % < (upfilename, destfilename), file=sys.stderr) --- > print( > f"accepting uploaded file: {upfilename} -> {destfilename}", file=sys.stderr) 212c161,162 < txt = b"""\ --- > txt = """\ > <!DOCTYPE html> 225c175 < self.wfile.write(txt) --- > self.wfile.write(txt.encode("utf-8")) 236,247c186,201 < txt = b"""\ < <html> < <head><title>Woof Upload</title></head> < <body> < <h1>Woof Upload</title></h1> < <form name="upload" method="POST" enctype="multipart/form-data"> < <p><input type="file" name="upfile" /></p> < <p><input type="submit" value="Upload!" /></p> < </form> < </body> < </html> < """ --- > txt = """\ > <!DOCTYPE html> > <html lang="en"> > <head> > <meta charset="utf-8"/> > <title>Woof Upload</title> > </head> > <body> > <h1>Woof Upload</h1> > <form name="upload" method="POST" enctype="multipart/form-data"> > <p><input type="file" name="upfile" /></p> > <p><input type="submit" value="Upload!" /></p> > </form> > </body> > </html>""" > 252c206 < self.wfile.write(txt) --- > self.wfile.write(txt.encode("utf-8")) 271c225,226 < txt = """\ --- > txt = f"""\ > <!DOCTYPE html> 274,276c229,230 < <body>302 Found <a href="%s">here</a>.</body> < </html>\n""" % location < txt = txt.encode('ascii') --- > <body>302 Found <a href="{location}">here</a>.</body> > </html>\n""" 282c236 < self.wfile.write(txt) --- > self.wfile.write(txt.encode("utf-8")) 303c257 < print("can only serve files or directories. Aborting.", --- > print("can only serve files or directories. Aborting.", 309,310c263,265 < self.send_header("Content-Disposition", "attachment;filename=%s" % < urllib.parse.quote(os.path.basename(self.filename))) --- > safe_filename = urllib.parse.quote(os.path.basename(self.filename)) > self.send_header("Content-Disposition", > f"attachment;filename={safe_filename}") 318,320c273,274 < datafile = open(self.filename, "rb") < shutil.copyfileobj(datafile, self.wfile) < datafile.close() --- > with open(self.filename, "rb") as datafile: > shutil.copyfileobj(datafile, self.wfile) 323,335c277,288 < ezfile = EvilZipStreamWrapper(self.wfile) < zfile = zipfile.ZipFile( < ezfile, 'w', zipfile.ZIP_DEFLATED) < stripoff = os.path.dirname(self.filename) + os.sep < < for root, dirs, files in os.walk(self.filename): < for f in files: < filename = os.path.join(root, f) < if filename[:len(stripoff)] != stripoff: < raise RuntimeException( < "invalid filename assumptions, please report!") < zfile.write(filename, filename[len(stripoff):]) < zfile.close() --- > with zipfile.ZipFile(self.wfile, 'w', > zipfile.ZIP_DEFLATED) as zfile: > stripoff = os.path.dirname(self.filename) + os.sep > > for root, dirs, files in os.walk(self.filename): > for f in files: > filename = os.path.join(root, f) > if filename[:len(stripoff)] != stripoff: > raise Exception( > "invalid filename assumptions, please report!") > zfile.write( > filename, filename[len(stripoff):]) 337,341c290,293 < tfile = tarfile.open(mode=('w|' + compressed), < fileobj=self.wfile) < tfile.add(self.filename, < arcname=os.path.basename(self.filename)) < tfile.close() --- > with tarfile.open(mode=('w|' + compressed), > fileobj=self.wfile) as tfile: > tfile.add(self.filename, > arcname=os.path.basename(self.filename)) 343a296 > print(e.with_traceback()) 360,361c313,314 < print("cannot bind to IP address '%s' port %d" % < (ip_addr, port), file=sys.stderr) --- > print(f"cannot bind to IP address '{ip_addr}' port {port}", > file=sys.stderr) 368,369c321 < location = "http://%s:%s/%s" % (ip_addr, httpd.server_port, < urllib.parse.quote(os.path.basename(filename))) --- > location = f"http://{ip_addr}:{httpd.server_port}/{urllib.parse.quote(os.path.basename(filename))}" 380c332 < location = "http://%s:%s/" % (ip_addr, httpd.server_port) --- > location = f"http://{ip_addr}:{httpd.server_port}" 382c334 < print("Now serving on %s" % location) --- > print(f"Now serving on {location}") 390,394c342,348 < print(""" < 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>] -s < %s [-i <ip_addr>] [-p <port>] [-c <count>] -U --- > print(f""" > Usage: {name} [-i <ip_addr>] [-p <port>] [-c <count>] <file> > {name} [-i <ip_addr>] [-p <port>] [-c <count>] [-z|-j|-Z|-u] <dir> > {name} [-i <ip_addr>] [-p <port>] [-c <count>] -s > {name} [-i <ip_addr>] [-p <port>] [-c <count>] -U > > {name} <url> 396,397d349 < %s <url> < 401,403c353,355 < it is gzip compressed. You can specify -z for gzip compression, < -j for bzip2 compression, -Z for ZIP compression or -u for no compression. < You can configure your default compression method in the configuration --- > it is gzip compressed. You can specify -z for gzip compression, -j for > bzip2 compression, -Z for ZIP compression or -u for no compression (tar). > You can configure your default compression method in the configuration 406c358 < When -s is specified instead of a filename, %s distributes itself. --- > When -s is specified instead of a filename, {name} distributes itself. 409,410c361,362 < < defaults: count = %d, port = %d --- > > defaults: count = {defmaxdown}, port = {defport} 427c379 < """ % (name, name, name, name, name, name, defmaxdown, defport), file=sys.stderr) --- > """, file=sys.stderr) 431c383 < print(file=sys.stderr) --- > print("", file=sys.stderr) 442c394 < f = urllib.request.urlopen(url) --- > f = urllib.urlopen(url) 445c397 < disp = f_meta["Content-Disposition"] --- > disp = f_meta.getheader("Content-Disposition") 507c459 < print("downloading file: %s -> %s" % (fname, destfilename)) --- > print(f"downloading file: {fname} -> {destfilename}") 509c461 < shutil.copyfileobj(f, os.fdopen(destfile, "wb")) --- > shutil.copyfileobj(f, os.fdopen(destfile, "w")) 560,561c512,513 < "invalid download count: %r. " < "Please specify an integer >= 0." % val) --- > f"invalid download count: {val}. " > "Please specify an integer >= 0.") 571c523 < "invalid port number: %r. Please specify an integer" % val) --- > f"invalid port number: {val}. Please specify an integer") 592c544 < usage(defaultport, defaultmaxdown, "Unknown option: %r" % option) --- > usage(defaultport, defaultmaxdown, f"Unknown option: {option}") 602c554 < if woof_client(filenames[0]) != None: --- > if woof_client(filenames[0]) is not None: 612c564 < "%s: No such file or directory" % filenames[0]) --- > f"{filenames[0]}: No such file or directory") 616c568 < "%s: Neither file nor directory" % filenames[0]) --- > f"{filenames[0]}: Neither file nor directory") 633c585 < print() --- > print("")
@beardhatcode Most recent no longer has the evil zip stream wrapper.
Hi,
I started to create a py3 version of woof a couple of months ago, and now I noticed that you already pushed it here.
It's practically the same, but:
Just wanted to put this on your radar. I auropep8ed my code, so below a diff between our versions.
My code is at https://github.com/beardhatcode/python3-woof
If you are interested, I can make a PR for the tests and/or the removal of the evilZipWrapper (or you can just steal it).