Skip to content

Instantly share code, notes, and snippets.

@darkr4y
Last active May 2, 2024 20:42
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save darkr4y/761d7536100d2124f5d0db36d4890109 to your computer and use it in GitHub Desktop.
Save darkr4y/761d7536100d2124f5d0db36d4890109 to your computer and use it in GitHub Desktop.
python simple http server with upload & download
#!/usr/bin/env python
"""Extend Python's built in HTTP server to save files
curl or wget can be used to send files with options similar to the following
curl -X PUT --upload-file somefile.txt http://localhost:8000
wget -O- --method=PUT --body-file=somefile.txt http://localhost:8000/somefile.txt
__Note__: curl automatically appends the filename onto the end of the URL so
the path can be omitted.
Windows upload & download
powershell -ep bypass -c "$wc=New-Object Net.WebClient;$wc.UploadFile('http://target.com/upload.bin', 'PUT', 'c:\\upload.bin');"
powershell -ep bypass -c "$wc=New-Object Net.WebClient;$wc.DownloadFile('http://target.com/download.bin','c:\\download.bin');"
Linux upload & download
curl -X PUT --upload-file upload.bin http://target.com/upload.bin
wget -O- --method=PUT --body-file=upload.bin http://target.com/upload.bin
wget http://target.com/download.bin -O /tmp/download.bin
curl http://target.com/download.bin -o /tmp/download.bin
"""
import os
try:
import http.server as server
except ImportError:
# Handle Python 2.x
import SimpleHTTPServer as server
class HTTPRequestHandler(server.SimpleHTTPRequestHandler):
"""Extend SimpleHTTPRequestHandler to handle PUT requests"""
def do_PUT(self):
"""Save a file following a HTTP PUT request"""
filename = os.path.basename(self.path)
# Don't overwrite files
if os.path.exists(filename):
self.send_response(409, 'Conflict')
self.end_headers()
reply_body = '"%s" already exists\n' % filename
self.wfile.write(reply_body.encode('utf-8'))
return
file_length = int(self.headers['Content-Length'])
read = 0
with open(filename, 'wb+') as output_file:
while read < file_length:
new_read = self.rfile.read(min(66556, file_length - read))
read += len(new_read)
output_file.write(new_read)
self.send_response(201, 'Created')
self.end_headers()
reply_body = 'Saved "%s"\n' % filename
self.wfile.write(reply_body.encode('utf-8'))
def do_GET(self):
self.send_response(404, 'Not Found')
self.end_headers()
self.wfile.write(b'')
if __name__ == '__main__':
server.test(HandlerClass=HTTPRequestHandler)
@BloodhoundAllfather
Copy link

It has errors with Python3

Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
127.0.0.1 - - [27/Jul/2021 17:51:34] "GET / HTTP/1.1" 404 -
----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 47764)
Traceback (most recent call last):
  File "/usr/lib/python3.8/socketserver.py", line 683, in process_request_thread
    self.finish_request(request, client_address)
  File "/usr/lib/python3.8/socketserver.py", line 360, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "/usr/lib/python3.8/http/server.py", line 647, in __init__
    super().__init__(*args, **kwargs)
  File "/usr/lib/python3.8/socketserver.py", line 747, in __init__
    self.handle()
  File "/usr/lib/python3.8/http/server.py", line 427, in handle
    self.handle_one_request()
  File "/usr/lib/python3.8/http/server.py", line 415, in handle_one_request
    method()
  File "httpsrv.py", line 64, in do_GET
    self.wfile.write('')
  File "/usr/lib/python3.8/socketserver.py", line 826, in write
    self._sock.sendall(b)
TypeError: a bytes-like object is required, not 'str'
----------------------------------------

@baiwfg2
Copy link

baiwfg2 commented Dec 31, 2021

change

with open(filename, 'wb+') as output_file:
            while read < file_length:

to

read = 0
with open(filename, 'wb+') as output_file:
            while read < file_length:

The rest is good

@BloodhoundAllfather
Copy link

@baiwfg2 Thank you for comment. The script runs but when you open the link from browser exception happens:

TypeError: a bytes-like object is required, not 'str'

@darkr4y
Copy link
Author

darkr4y commented Jan 4, 2022

works fine on my pc

$ python3 -V
Python 3.9.9

$ python3 httpsrv.py
Serving HTTP on :: port 8000 (http://[::]:8000/) ...

need more information to debug

@BloodhoundAllfather
Copy link

@darkr4y It happens when you open the browser

@darkr4y
Copy link
Author

darkr4y commented Jan 5, 2022

@MChelik updated.
The modified code may break python2 compatibility, and I need to improve it further when I have time.

$ curl -v localhost:8000
*   Trying 127.0.0.1:8000...
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET / HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.80.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
* HTTP 1.0, assume close after body
< HTTP/1.0 404 Not Found
< Server: SimpleHTTP/0.6 Python/3.9.9
< Date: Wed, 05 Jan 2022 09:12:42 GMT
<
* Closing connection 0
$ python3 httpsrv.py
Serving HTTP on :: port 8000 (http://[::]:8000/) ...
::ffff:127.0.0.1 - - [05/Jan/2022 17:12:42] "GET / HTTP/1.1" 404 -

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment