How to run CGI "hello world" with python http.server

39,141

Solution 1

From the http.server docs:

CGIHTTPRequestHandler can be enabled in the command line by passing the --cgi option:

$ python3 -m http.server --bind localhost --cgi 8000

Put your script into cgi_directories:

This defaults to ['/cgi-bin', '/htbin'] and describes directories to treat as containing CGI scripts.

Open in the browser:

$ python -mwebbrowser http://localhost:8000/cgi-bin/hello.py

where hello.py:

#!/usr/bin/env python3
print("Content-Type: text/html\n")
print("<!doctype html><title>Hello</title><h2>hello world</h2>")

I had to make it executable on POSIX: chmod +x cgi-bin/hello.py.

Solution 2

I created a complete example for a friend. It is a complete demo you can run with 8 simple copy-paste ready lines of code. Enjoy.

echo -e "\n\n    Usage: after running this script, visit http://localhost:8000/cgi-bin/hello    \n\n"
mkdir /tmp/cgi-bin/
cat > /tmp/cgi-bin/hello <<EOF
#!/bin/bash
echo -e "Content-Type: text/plain\n\n"; date; echo; env
EOF
chmod +x /tmp/cgi-bin/hello
(cd /tmp; python3 -m http.server --cgi 8000)

Solution 3

I did this some time ago for Python2.7

from BaseHTTPServer import BaseHTTPRequestHandler

class GetHandler(BaseHTTPRequestHandler):

    def do_HEAD(self):
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()

    def do_GET(self):
        x = self.wfile.write
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()
        # <--- HTML starts here --->
        x("<html>")
        # <--- HEAD starts here --->
        x("<head>")
        x("<title>Title goes here!</title>")
        x("</head>")
        # <--- HEAD ends here --->
        # <--- BODY starts here --->
        x("<body>")
        x("<p>This is a test.</p>")
        x("</body>")
        # <--- BODY ends here --->
        x("</html>")
        # <--- HTML ends here --->

if __name__ == '__main__':
    from BaseHTTPServer import HTTPServer
    server = HTTPServer(('localhost', 777), GetHandler)
    print 'Starting server, use <Ctrl + F2> to stop'
    server.serve_forever()

So in Python 3 you just need to change imports

from http.server import BaseHTTPRequestHandler

class GetHandler(BaseHTTPRequestHandler):

    def do_HEAD(self):
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()

    def do_GET(self):
        x = self.wfile.write
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()
        # <--- HTML starts here --->
        x("<html>")
        # <--- HEAD starts here --->
        x("<head>")
        x("<title>Title goes here!</title>")
        x("</head>")
        # <--- HEAD ends here --->
        # <--- BODY starts here --->
        x("<body>")
        x("<p>This is a test.</p>")
        x("</body>")
        # <--- BODY ends here --->
        x("</html>")
        # <--- HTML ends here --->

if __name__ == '__main__':
    from http.server import HTTPServer
    server = HTTPServer(('localhost', 777), GetHandler)
    print('Starting server, use <Ctrl + F2> to stop')
    server.serve_forever()
Share:
39,141

Related videos on Youtube

Yura
Author by

Yura

Updated on March 30, 2020

Comments

  • Yura
    Yura about 4 years

    I am using Windows 7 and Python 3.4.3. I would like to run this simple helloworld.py file in my browser:

    print('Content-Type: text/html')
    print( '<html>')
    print( '<head></head>')
    print( '<body>')
    print( '<h2>Hello World</h2>')
    print( '</body></html>')
    

    What I do is:

    1) Go to command line C:\Python (where python is installed)

    2) run: python -m http.server

    3) Got to Firefox and type http://localhost:8000/hello.py

    However, instead of "Hello World", the browser just prints the content of the hello.py file.

    How can I fix it?

    • TehTris
      TehTris almost 9 years
      your webserver isnt "running python". your python is running a webserver.
    • kylieCatt
      kylieCatt almost 9 years
      You should edit your original question instead of just reposting it.
    • TehTris
      TehTris almost 9 years
      after re-reading my comment it seemed kinda sarcastic, so let me explain a little more. visit bootstrap.pypa.io/get-pip.py and watch how the file contents are just displayed in your browser. Your webserver is not configured to actually do anything with python commands, its just serving whatever files you have in the directory as the most basic of all no frills webserver.
    • Yura
      Yura almost 9 years
      @IanAuld, my other question was regarding configuring WAMP. This question is regarding http.server. No reposting - this is a different question
    • kylieCatt
      kylieCatt almost 9 years
      Once again I will point you to Flask and Bottle
    • Yura
      Yura almost 9 years
      @TehTris, I clicked the link and it has downloaded a .py file. Nothing was displayed in my browser. what should I do with it?
    • Yura
      Yura almost 9 years
      @IanAuld, I tried to read it the last time, but it seems Chinese to me, I dont really know where to start and what to do with that. If you want to prompt me to a more precise to read, Id love your help.
    • Tom-Oliver Heidel
      Tom-Oliver Heidel almost 9 years
      @IanAuld depending on what you are doing it is enough to use the python built-in functions. tho' of course you are right that flask and other (micro-)frameworks can help a lot,
    • kylieCatt
      kylieCatt almost 9 years
      If the OP is a beginner (which I'm assuming they are) dealing with server configs and rendering out different pages, routing and security concerns can quickly become overwhelming. Letting a framework do the heavy lifting while they learn will probably be much easier in the long run.
    • kylieCatt
      kylieCatt almost 9 years
      @Yura This tutorial will cover a lot of things but is pretty easy to follow along with. This one is much more basic (and slightly out dated) but will show you the basics.
    • Yura
      Yura almost 9 years
      @IanAuld, Thank you. I'll read it now ! :)
    • Tom-Oliver Heidel
      Tom-Oliver Heidel almost 9 years
      By the way you do not type in 'localhost:8000/hello.py' do it WITHOUT 'hello.py'
    • Yura
      Yura almost 9 years
      @ Tom-Oliver Heidel, in that case, I just get a list of all the files in the directory. In fact, if I dont type the hello.py, how would the server know to execute the :hello.py" and not "some-other-file-I-have.py"...?
  • Yura
    Yura almost 9 years
    Thanks @Tom-Oliver Heidel, Im a newbie, please guide me what to do with this code you have posted and where to place it to make my hello-world.py work oin the browser. Thanks
  • Tom-Oliver Heidel
    Tom-Oliver Heidel almost 9 years
    I cannot guarantuee 100% that the python3 code will work because I just used python docs in short time. But there is a tool called '2to3' which will convert python2 script into python3 script docs.python.org/2/glossary.html#term-to3 Actually you just need to copy the scripty and name it like e.g. 'httpserver.py' then you can use cmd and type in 'python httpserver.py' to start it.
  • Tom-Oliver Heidel
    Tom-Oliver Heidel almost 9 years
    can you test my python3 script if it really works. I do not want to install python3 right now or use some online python because those work some different.
  • jfs
    jfs almost 9 years
    @Tom-OliverHeidel: sure. What commands do you want me to run and what do you expect to happen (define "really works": do you care about multiple concurrent clients, security, buffers, etc)?
  • Tom-Oliver Heidel
    Tom-Oliver Heidel almost 9 years
    scroll down a bit - the other answer is mine.
  • Yura
    Yura almost 9 years
    @J.F. Sebastian, I did it (except "I had to make it executable on POSIX: chmod +x cgi-bin/hello.py." - since I dont understand what this is. is it Linux? I am on Win) and it did not work for me... stil printing the content of the file onto the browser
  • jfs
    jfs almost 9 years
    I've changed 777 to 7777 (permission error on Unix) and replaced all str literals by bytes literals on Python 3. Ctrl + F2 does something unrelated on my Ubuntu machine. After that it shows: "This is a test." if you visit: localhost:7777.
  • Yura
    Yura almost 9 years
    @Tom-OliverHeidel How should I run the files? On port 777?
  • jfs
    jfs almost 9 years
    @Yura: 1. have you put hello.py into cgi-bin directory? 2. Have you appended --cgi as shown above? 3. Have you visited localhost:8000/cgi-bin/hello.py (note: cgi-bin in url)? 4. Have your added additional "\r\n" after the http header?
  • Tom-Oliver Heidel
    Tom-Oliver Heidel almost 9 years
    Thank you @J.F.Sebastian yes I just choose an unused port (win7). Ctrl+F2 was the IDE I am working with - actually in console you abort with ctrl+c. But it seems everything is running fine then :)
  • Tom-Oliver Heidel
    Tom-Oliver Heidel almost 9 years
    @Yura when you got the file saved and executed with 'python filename.py' you can go and open your browser. type in 'localhost:777' or to whatever you changed the port in the script.
  • Tom-Oliver Heidel
    Tom-Oliver Heidel almost 9 years
    @Yura is using windows so. J.F. Sebastian he will not have a cgi-bin by default. I guess he is just testing some python at all.
  • jfs
    jfs almost 9 years
    @Tom-OliverHeidel: cgi-bin is just a directory name: it can be anything from cgi_directories (click the link in the answer)
  • Yura
    Yura almost 9 years
    @ J.F. Sebastian. (1)-Yes (2)-Yes (3)-Yes (4)-I guess no, since I have no idea what you are talking about. As for the file, indeed om my screen is printed "hello". BUT, this is just a print of a file and not a result of running it. It I put print("<h2>hello</h2>") instead of the 2nd line , then I would get "<h2>hello</h2>" on my screen. Meaning that this is just a print of the file.... :(
  • jfs
    jfs almost 9 years
    @Yura: have you tried to change: "Content-Type: text/plain\n\nhello\n" to "Content-Type: text/html\n\n<!doctype html><title>Hello</title><h2>hello world</h2>"?
  • Yura
    Yura almost 9 years
    @ Tom-Oliver Heidel, Ok, I did it. saved and run the server file and then typed "localhost:777/hello.py" in the browser. => the browser showed a blank page...
  • Tom-Oliver Heidel
    Tom-Oliver Heidel almost 9 years
    I never said to type in 'localhost:777/hello.py' when you executing the python file you can read 'Starting server ........' then you type into your browser 'localhost:777' nothing more.
  • Yura
    Yura almost 9 years
    @J.F. Sebastian, YOU ARE RIGHT!!!! I have been struggling with it for 3 days. You helped me alot Thank You very much!!! when I put this line as the first one: print ("Content-type:text/html\r\n\r\n") , it does not work. However, when I put this line: print ("Content-Type: text/html\n\n<!doctype html>"), it works. Do you know why?
  • Yura
    Yura almost 9 years
    @Tom-Oliver Heidel, I just tried typing only "localhost:777" but got a blank result again. Anyway, seems that J.F. Sebastian solved the problem. Thank you very much Tom-OliverHeide for you support and your time! Thanks!
  • jfs
    jfs almost 9 years
    @Yura: If something stops working; start with a known state that works and change one thing at a time until it breaks again. "\n" is replaced with "\r\n" while printing by Python on Windows. The client (browser) expects \r\n\r\n before the html body. My previous (removed) comment was wrong: you don't need a space before the field value. There are several html versions. <!doctype html> indicates html5
  • W.M.
    W.M. almost 8 years
    How to make the server accept SSL connections, what modifications must be made for this line python3 -m http.server --bind localhost --cgi 8000? Thanks
  • jfs
    jfs about 6 years
    @W.M.: you could add httpd.socket = ssl.wrap_socket( httpd.socket, keyfile=keypath, certfile=certpath, server_side=True) to http.server.test() function (or use more flexible SSLContext.wrap_socket). Here's a code example for a python3 -mhttp.server analog [text in Russian]. For the cgi case, pass CGIHTTPRequestHandler instead of SimpleHTTPRequestHandler