Can I set a header with python's SimpleHTTPServer?

Question:

I’m using SimpleHTTPServer to test some webpages I’m working on. It works great, however I need to do some cross-domain requests. That requires setting a Access-Control-Allow-Origin header with the domains the page is allowed to access.

Is there an easy way to set a header with SimpleHTTPServer and serve the original content? The header would be the same on each request.

Asked By: nynexman4464

||

Answers:

# coding: utf-8
import SimpleHTTPServer
import SocketServer
PORT = 9999

def do_GET(self):
    self.send_response(200)
    self.send_header('Access-Control-Allow-Origin', 'http://example.com')           
    self.end_headers()

Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
Handler.do_GET = do_GET
httpd = SocketServer.TCPServer(("", PORT), Handler)
httpd.serve_forever()
Answered By: iMom0

I’d say there’s no simple way of doing it, where simple means “just add 1-2 lines that will write the additional header and keep the existing functionality”. So, the best solution would be to subclass the SimpleHTTPRequestHandler class and re-implement the functionality, with the addition of the new header.

The problem behind why there is no simple way of doing this can be observed by looking at the implementation of the SimpleHTTPRequestHandler class in the Python library: http://hg.python.org/cpython/file/19c74cadea95/Lib/http/server.py#l654

Notice the send_head() method, particularly the lines at the end of the method which send the response headers. Notice the invocation of the end_headers() method. This method writes the headers to the output, together with a blank line which signals the end of all headers and the start of the response body: http://docs.python.org/py3k/library/http.server.html#http.server.BaseHTTPRequestHandler.end_headers

Therefore, it would not be possible to subclass the SimpleHTTPRequestHandler handler, invoke the super-class do_GET() method, and then just add another header — because the sending of the headers has already finished when the call to the super-class do_GET() method returns. And it has to work like this because the do_GET() method has to send the body (the file that is requested), and to send the body – it has to finalize sending the headers.

So, again, I think you’re stuck with sub-classing the SimpleHTTPRequestHandler class, implementing it exactly as the code in the library (just copy-paste it?), and add another header before the call to the end_headers() method in send_head():

...
self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
# this below is the new header
self.send_header('Access-Control-Allow-Origin', '*')
self.end_headers()
return f
...
Answered By: Ivan Zuzak

This is a bit of a hack because it changes end_headers() behavior, but I think it’s slightly better than copying and pasting the entire SimpleHTTPServer.py file.

My approach overrides end_headers() in a subclass and in it calls send_my_headers() followed by calling the superclass’s end_headers().

It’s not 1 – 2 lines either, less than 20 though; mostly boilerplate.

#!/usr/bin/env python
try:
    from http import server # Python 3
except ImportError:
    import SimpleHTTPServer as server # Python 2

class MyHTTPRequestHandler(server.SimpleHTTPRequestHandler):
    def end_headers(self):
        self.send_my_headers()

        server.SimpleHTTPRequestHandler.end_headers(self)

    def send_my_headers(self):
        self.send_header("Access-Control-Allow-Origin", "*")


if __name__ == '__main__':
    server.test(HandlerClass=MyHTTPRequestHandler)
Answered By: berto

While this is an older answer, its the first result in google…

Basically what @iMon0 suggested..Seems correct?..Example of doPOST

def do_POST(self):
    self.send_response()
    self.send_header('Content-type','application/json')
    self.send_header('Access-Control-Allow-Origin','*')
    self.end_headers()
    sTest = {}
    sTest['dummyitem'] = "Just an example of JSON"
    self.wfile.write(json.dumps(sTest))

By doing this, the flow feels correct..

1: You get a request

2: You apply the headers and response type you want

3: You post back the data you want, be this what or how ever you want.,

The above example is working fine for me and can be extended further, its just a bare bone JSON post server. So i’ll leave this here on SOF incase someone needs it or i myself come back in a few months for it.

This does produce a valid JSON file with only the sTest object, Same as a PHP generated page/file.

Answered By: Angry 84