206

I have the following shell script for a very simple HTTP server:

#!/bin/sh

echo "Serving at http://localhost:3000"
python -m SimpleHTTPServer 3000

I was wondering how I can enable or add a CORS header like Access-Control-Allow-Origin: * to this server?

1
  • 6
    Lolol I love how the simple server, which probably the very point of using it is to serve things up because you can't use local files, requires one to configure this. Commented Jan 17, 2021 at 3:22

8 Answers 8

305

Unfortunately, the simple HTTP server is really that simple that it does not allow any customization, especially not for the headers it sends. You can however create a simple HTTP server yourself, using most of SimpleHTTPRequestHandler, and just add that desired header.

For that, simply create a file simple-cors-http-server.py (or whatever) and, depending on the Python version you are using, put one of the following codes inside.

Then you can do python simple-cors-http-server.py and it will launch your modified server which will set the CORS header for every response.

With the shebang at the top, make the file executable and put it into your PATH, and you can just run it using simple-cors-http-server.py too.

Python 3 solution

Python 3 uses SimpleHTTPRequestHandler and HTTPServer from the http.server module to run the server:

#!/usr/bin/env python3
from http.server import HTTPServer, SimpleHTTPRequestHandler, test
import sys

class CORSRequestHandler (SimpleHTTPRequestHandler):
    def end_headers (self):
        self.send_header('Access-Control-Allow-Origin', '*')
        SimpleHTTPRequestHandler.end_headers(self)

if __name__ == '__main__':
    test(CORSRequestHandler, HTTPServer, port=int(sys.argv[1]) if len(sys.argv) > 1 else 8000)

Python 2 solution

Python 2 uses SimpleHTTPServer.SimpleHTTPRequestHandler and the BaseHTTPServer module to run the server.

#!/usr/bin/env python2
from SimpleHTTPServer import SimpleHTTPRequestHandler
import BaseHTTPServer

class CORSRequestHandler (SimpleHTTPRequestHandler):
    def end_headers (self):
        self.send_header('Access-Control-Allow-Origin', '*')
        SimpleHTTPRequestHandler.end_headers(self)

if __name__ == '__main__':
    BaseHTTPServer.test(CORSRequestHandler, BaseHTTPServer.HTTPServer)

Python 2 & 3 solution

If you need compatibility for both Python 3 and Python 2, you could use this polyglot script that works in both versions. It first tries to import from the Python 3 locations, and otherwise falls back to Python 2:

#!/usr/bin/env python
try:
    # Python 3
    from http.server import HTTPServer, SimpleHTTPRequestHandler, test as test_orig
    import sys
    def test (*args):
        test_orig(*args, port=int(sys.argv[1]) if len(sys.argv) > 1 else 8000)
except ImportError: # Python 2
    from BaseHTTPServer import HTTPServer, test
    from SimpleHTTPServer import SimpleHTTPRequestHandler

class CORSRequestHandler (SimpleHTTPRequestHandler):
    def end_headers (self):
        self.send_header('Access-Control-Allow-Origin', '*')
        SimpleHTTPRequestHandler.end_headers(self)

if __name__ == '__main__':
    test(CORSRequestHandler, HTTPServer)
Sign up to request clarification or add additional context in comments.

17 Comments

@poke The server responds with 501 Unsupported method ('OPTIONS'). I'm running OS X 10.10.1 with Python 2.7.6. Any suggestions? HTTP/1.0 501 Unsupported method ('OPTIONS') Server: SimpleHTTP/0.6 Python/2.7.6 Date: Wed, 21 Jan 2015 23:16:10 GMT Content-Type: text/html Connection: close Access-Control-Allow-Origin: *
@HairOfTheDog The SimpleHTTPRequestHandler doesn’t support the OPTIONS HTTP method. You could add it if you want (read the Python manual about HTTP servers); or you could just not try to access the server like that.
this looks great, but is this still working? I just tried and my Chrome keeps complaining in the console.
@RobertoFranceschini You might be running into preflighted requests which require the OPTIONS method to be implemented properly. As for simple requests, the solution of sending just the Access-Control-Allow-Origin header should still work fine.
@Tyguy7 That might be a general behavior with the simple HTTP server though. I had varying results regarding performance before. But for simply running a server for a moment, I still consider it the quickest solution.
|
175

Try an alternative like http-server

As SimpleHTTPServer is not really the kind of server you deploy to production, I'm assuming here that you don't care that much about which tool you use as long as it does the job of exposing your files at http://localhost:3000 with CORS headers in a simple command line

# install (it requires nodejs/npm)
npm install http-server -g

#run
http-server -p 3000 --cors

Need HTTPS?

If you need https in local you can also try caddy or certbot


Edit 2022: my favorite solution is now serve, used internally by Next.js.

Just run npx serve --cors


Some related tools you might find useful

  • ngrok: when running ngrok http 3000, it creates an url https://$random.ngrok.com that permits anyone to access your http://localhost:3000 server. It can expose to the world what runs locally on your computer (including local backends/apis)

  • localtunnel: almost the same as ngrok

  • now: when running now, it uploads your static assets online and deploy them to https://$random.now.sh. They remain online forever unless you decide otherwise. Deployment is fast (except the first one) thanks to diffing. Now is suitable for production frontend/SPA code deployment It can also deploy Docker and NodeJS apps. It is not really free, but they have a free plan.

10 Comments

I'm a simple man. I see a solution that requires installing npm on a machine that is only known to have python, I downvote.
@ParthianShot: you might want to learn to use the best tool for the job.
I do know how to use the best tool for the job. Which is why I've never installed npm on a production machine, nor do I ever intend to. I especially don't install a new language or package manager every time I want to solve a simple problem like CORS headers on an HTTP server. But either way... OP is comfortable in python, asked for a python solution. Therefore, by definition, the "right tool for the job" is python.
Adding an additional language and framework incurs technical debt and increases the attack surface of an environment. "Fatal mistakes can be made in any programming language" True, but JS makes that way easier than most other languages. And every language has gotchas; the fewer languages you use, the less likely it is that some developer who is unfamiliar with one of the languages makes a mistake that wouldn't be a mistake in another language.
This is like adopting a child every time you need help around the house; it creates more problems than it solves down the road.
|
9

I had the same problem and came to this solution:

class Handler(SimpleHTTPRequestHandler):
    def send_response(self, *args, **kwargs):
        SimpleHTTPRequestHandler.send_response(self, *args, **kwargs)
        self.send_header('Access-Control-Allow-Origin', '*')

I simply created a new class inheriting from SimpleHTTPRequestHandler that only changes the send_response method.

Comments

4

try this: https://github.com/zk4/livehttp. support CORS.

python3 -m pip install livehttp

goto your folder, and run livehttp. that`s all.

http://localhost:5000

Comments

2

You'll need to provide your own instances of do_GET() (and do_HEAD() if choose to support HEAD operations). something like this:

class MyHTTPServer(SimpleHTTPServer):

    allowed_hosts = (('127.0.0.1', 80),)

    def do_GET(self):
        if self.client_address not in allowed_hosts:
            self.send_response(401, 'request not allowed')
        else:
            super(MyHTTPServer, self).do_Get()

5 Comments

Thanks for your answer, but I have no Python knowledge what so ever, I am just using the shell script mentioned above as a simple http server for my Emberjs apps. Only when collided with the access control problem, I researched to find that I need to enable it in this simple http server. So after some research I added (enable 'CrossOrigin', origins => '*';) but not-surprisingly it didn't work. If you can please point me to any Python simple http server shell script that include the access control feature that will be highly appreciated
On a minor note, I am not trying to be lazy here really but start learning python just to add this feature to the simpleHTTP server doesn't sound logical at this point so I was hoping it will be easy to add OR hopefully I can find an alternative / ready made Python script that can do the job so that I can continue with my dev work
The SimpleHTTPServer has no options to support access controls. Either you'll need to roll your own code -- or switch to another web server that supports access controls. Think about lighttpd.net
For anyone taking this approach, if you want it to support "non simple" cors requests (ones that require "preflight" permission) you will want to implement a do_OPTIONS method which returns a 204 response with the following headers: 'Access-Control-Allow-Origin', 'Access-Control-Allow-Methods' and 'Access-Control-Allow-Headers'.
As @RogerHeathcote noted the do_OPTIONS method would work but be carefull as it is enough to have a missing allowed header to have your request ditched... like when you make a partial request and don't allow for range header (took me a moment to find that out) self.send_header("Access-Control-Allow-Headers", "range, accept, accept-encoding, authorization, content-type, dnt, origin, user-agent, x-csrftoken, x-requested-with")
1

My working code:

self.send_response(200)
        self.send_header( "Access-Control-Allow-Origin", "*")
        self.end_headers()
        self.wfile.write( bytes(json.dumps( answ ), 'utf-8'))

Comments

1

I'm using python one-liner to add Access-Control-Allow-Origin header and bash's alias feature. In this case we don't need to store somewhere custom python script.

You just have to add

alias srv='echo -e "from sys import argv as a\nfrom http.server import HTTPServer as H, SimpleHTTPRequestHandler as HH, test as t\nclass C(HH):\n def end_headers (self):\n  self.send_header(a[2],a[3])\n  HH.end_headers(self)\nt(C,H,port=int(a[1]))" | /usr/bin/env python3 -- - 8000 "Access-Control-Allow-Origin" "*"'

line into ~/.bashrc file and run simple server by srv command

Comments

0

That's a code that worked for me (Python 3), not a line less:

from http.server import SimpleHTTPRequestHandler, HTTPServer

class CORSRequestHandler(SimpleHTTPRequestHandler):

    def end_headers (self):
        self.send_header('Access-Control-Allow-Origin', '*')
        self.send_header('Access-Control-Allow-Methods', '*')
        self.send_header('Access-Control-Allow-Headers', '*')
        SimpleHTTPRequestHandler.end_headers(self)
        
    def do_OPTIONS(self):
        self.send_response(200)
        self.end_headers()

httpd = HTTPServer(('localhost', 8000), CORSRequestHandler)
httpd.serve_forever()

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.