2

This question comes from this one.

What I want is to be able to return the HTTP 303 header from my python script, when the user clicks on a button. My script is very simple and as far as output is concerned, it only prints the following two lines:

print "HTTP/1.1 303 See Other\n\n"
print "Location: http://192.168.1.109\n\n"

I have also tried many different variants of the above (with a different number of \r and \n at the end of the lines), but without success; so far I always get Internal Server Error.

Are the above two lines enough for sending a HTTP 303 response? Should there be something else?

Community
  • 1
  • 1
panos
  • 41
  • 2
  • 9
  • Have you read http://stackoverflow.com/q/6122957/3001761? – jonrsharpe May 25 '16 at 19:36
  • Thanks John! Yes, I have, but it doesn't solve my problem. Instead of `Internal Server Error` I get a page containing the text `Location: http://192.168.1.109`, instead of being redirected to that page. – panos May 25 '16 at 20:12
  • So I had a look at the apache error log and I see that there's no error when the first line is `Status: 303 See other\n`. So this other question is right in this part. The second line (`Location: ...`), however, doesn't appear to work... – panos May 25 '16 at 20:35

3 Answers3

3

Assuming you are using cgi (2.7)(3.5)

The example below should redirect to the same page. The example doesn't attempt to parse headers, check what POST was send, it simply redirects to the page '/' when a POST is detected.

# python 3 import below:
# from http.server import HTTPServer, BaseHTTPRequestHandler
# python 2 import below:
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import cgi
#stuff ...
class WebServerHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        try:
            if self.path.endswith("/"):
                self.send_response(200)
                self.send_header('Content-type', 'text/html')
                self.end_headers()

                page ='''<html>
                         <body>
                         <form action="/" method="POST">
                         <input type="submit" value="Reload" >
                         </form>
                         </body>
                         </html'''

                self.wfile.write(page)
        except IOError:
            self.send_error(404, "File Not Found {}".format(self.path))
    def do_POST(self):
        self.send_response(303)
        self.send_header('Content-type', 'text/html')
        self.send_header('Location', '/') #This will navigate to the original page
        self.end_headers()

def main():
    try:
        port = 8080
        server = HTTPServer(('', port), WebServerHandler)
        print("Web server is running on port {}".format(port))
        server.serve_forever()

    except KeyboardInterrupt:
        print("^C entered, stopping web server...")
        server.socket.close()


if __name__ == '__main__':
    main()
Michal Frystacky
  • 1,418
  • 21
  • 38
  • Thanks Michal! I'm getting an error though :( `name 'self' is not defined`. I am using python2. – panos May 26 '16 at 19:29
  • @panos , this is a more self(haha) contained example of what you are trying to accomplish. – Michal Frystacky May 26 '16 at 19:52
  • @panos it should be python two compatible now – Michal Frystacky May 26 '16 at 19:54
  • Thanks man! I'm trying to make it work but I get `IndentationError:` at the first `if`... And since I'm a python newbie I don't really know where to put the indent... – panos May 26 '16 at 20:07
  • @panos Try it now. – Michal Frystacky May 26 '16 at 20:09
  • @panos I removed the `except` block and forgot to put it back, the current version should clear up that error. Sorry bud, I don't have a python2 interpreter on me at the moment. – Michal Frystacky May 26 '16 at 20:25
  • I think it worked this time! But it died when I pressed the button for the second time. The error I get is `UnboundLocalError: local variable 'server' referenced before assignment`. Oh, and don't worry about python2; I changed my (tiny) script to python3 ;) – panos May 26 '16 at 20:26
  • @panos this should work. I changed up the main method a bit so that you shouldn't catch that exception. Note for python3 the line: `self.wfile.write(page)` needs to be changed to `self.wfile.write(page.encode())` – Michal Frystacky May 26 '16 at 20:32
  • ...and now I get `OSError: [Errno 98] Address already in use` – panos May 26 '16 at 20:33
  • Restart/or close the original server script. Its still running (probably under python 2) – Michal Frystacky May 26 '16 at 20:34
  • It's the same script that keeps running in the background after I press the button for the first time... – panos May 26 '16 at 20:44
  • Michal, I eventually found another way to solve my problem. I posted the answer to my [other question](http://stackoverflow.com/questions/37399965/refresh-web-page-using-a-cgi-python-script/37491794), since it's not exactly the solution to "return the HTTP 303 status code". Thanks a lot for your time in helping me with this :) – panos May 27 '16 at 20:38
0

Typically browsers like to see /r/n/r/n at the end of an HTTP response.

alltrue
  • 585
  • 4
  • 5
0

Be very careful about what Python automatically does. For example, in Python 3, the print function adds line endings to each print, which can mess with HTTP's very specific number of line endings between each message. You also still need a content type header, for some reason.

This worked for me in Python 3 on Apache 2:

print('Status: 303 See Other')
print('Location: /foo')
print('Content-type:text/plain')
print()
ILoveGit
  • 316
  • 3
  • 9