simon-budig / woof

an ad-hoc single file webserver
120 stars 17 forks source link

Another py3 version #1

Open beardhatcode opened 4 years ago

beardhatcode commented 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("")
CoolCat467 commented 3 years ago

@beardhatcode Most recent no longer has the evil zip stream wrapper.