3

I have a Python HTTP server and I'm trying to make downloading files from it to work. For an example, I have HTTP server in a /server directory and I want to be able to download any file from that directory with a GET request. So if I type http://localhost:8000/example.txt, it should offer to download example.txt, if it exists.

How would I achieve so? The current behavior is that is does nothing with any GET request, other than show Hi.

My code:

import argparse
from http.server import HTTPServer, BaseHTTPRequestHandler

from shutil import copyfileobj
from os import path as ospath
import cgi
import cgitb; cgitb.enable(format="text")
from io import StringIO
import urllib




class S(BaseHTTPRequestHandler):
    def _set_headers(self):
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()

    def _html(self, message):
        """This just generates an HTML document that includes `message`
        in the body. Override, or re-write this do do more interesting stuff.
        """
        content = f"<html><body><h1>{message}</h1></body></html>"
        return content.encode("utf8")  # NOTE: must return a bytes object!

    def do_GET(self):
        self._set_headers()
        self.wfile.write(self._html("hi!"))

    def do_HEAD(self):
        self._set_headers()


def run(server_class=HTTPServer, handler_class=S, addr="localhost", port=8000):
    server_address = (addr, port)
    httpd = server_class(server_address, handler_class)

    print(f"Starting httpd server on {addr}:{port}")
    httpd.serve_forever()


if __name__ == "__main__":

    parser = argparse.ArgumentParser(description="Run a simple HTTP server")
    parser.add_argument(
        "-l",
        "--listen",
        default="localhost",
        help="Specify the IP address on which the server listens",
    )
    parser.add_argument(
        "-p",
        "--port",
        type=int,
        default=8000,
        help="Specify the port on which the server listens",
    )
    args = parser.parse_args()
    run(addr=args.listen, port=args.port)

Thanks

petezurich
  • 9,280
  • 9
  • 43
  • 57
  • 2
    If you want it for testing things you could use SimpleHTTPServer module in python. python -m SimpleHTTPServer 8081 creates a simple HTTP server using which you can download files. You have to just run it from the folder which you have to serve. – koushikmln Jan 01 '20 at 16:25
  • @koushikmln That's what I have been using, but I need both POST to upload files and GET to download files and POST is AFAIK hard to implement that way. That's why I'm using a custom code. – user12637035 Jan 01 '20 at 16:27
  • Does this answer your question? [Serve directory in Python 3](https://stackoverflow.com/questions/55052811/serve-directory-in-python-3) – Maurice Meyer Jan 01 '20 at 16:33
  • 1
    Its easier if you use a framework like Flask. You have to configure paths etc here to serve static files. Plus you have to write too much of boiler plate code. Eg. Flask code is given below: https://docs.faculty.ai/user-guide/apis/flask_apis/flask_file_upload_download.html – koushikmln Jan 01 '20 at 16:37
  • @MauriceMeyer Not really, not sure how to implement it and code from the thread is not working for me. – user12637035 Jan 01 '20 at 16:39
  • @koushikmln Never heard about Flask and I really need it just for some basic script so I would prefer to create it that way. – user12637035 Jan 01 '20 at 16:39
  • The script in the example is pretty basic. You could try it out. POST would require lot of code if you want to upload files. – koushikmln Jan 01 '20 at 16:44
  • @koushikmln My POST is already working, just not GET. Didn't include the code in order to make it more readable. Tried the Flask code, however I'm getting Not Found The requested URL was not found on the server error when trying to download files. – user12637035 Jan 01 '20 at 16:46
  • Did you configure the directories? The UPLOAD_DIRECTORY variable should be set to the project path and files folder. Also, the GET request should be done to /files/ – koushikmln Jan 01 '20 at 16:53
  • @koushikmln Figured out GET, just POST is throwing METHOD NOT ALLOWED. – user12637035 Jan 01 '20 at 17:09
  • @koushikmln POST is not working. It's either creating new files or throwing METHOD NOT ALLOWED. How should I configure path for POST? – user12637035 Jan 01 '20 at 17:36
  • It is creating files right? What issue do you have? – koushikmln Jan 01 '20 at 17:55
  • Well I want to upload files, however it's either creating new empty files or throwing 404 NOT FOUND or METHOD NOT ALLOWED, depending on how I set api.route for POST. I have POST configured that way: @api.route("/", methods=["POST"]) . Is it right? – user12637035 Jan 01 '20 at 17:58
  • it seems fine. what is the curl request you are using? – koushikmln Jan 01 '20 at 18:17
  • @koushikmln I'm using webclient.uploadFile in PowerShell. – user12637035 Jan 01 '20 at 18:45

0 Answers0