The Python Oracle

How to set up CORS in CherryPy

--------------------------------------------------
Rise to the top 3% as a developer or hire one of them at Toptal: https://topt.al/25cXVn
--------------------------------------------------

Music by Eric Matyas
https://www.soundimage.org
Track title: Puzzle Game 5 Looping

--

Chapters
00:00 How To Set Up Cors In Cherrypy
02:55 Accepted Answer Score 8
04:52 Thank you

--

Full question
https://stackoverflow.com/questions/5741...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #cors #cherrypy

#avk47



ACCEPTED ANSWER

Score 8


So first, you need to set pre-flight headers when processing OPTIONS request, you can list allowed methods there. Then, you also need to enable the cors.expose tool.

There's some usage hints in the docstring of cherrypy-cors. For example, when using a MethodDispatcher, you could just decorate an OPTIONS handler method with @cherrypy_cors.tools.preflight() instead of doing this in every HTTP handler.

Here's a simple traversal example (without a method dispatcher). To test it, visit http://127.0.0.1/ and it will make requests against http://localhost:3333/add_meeting which is a different Origin in terms of CORS ('localhost' != '127.0.0.1').

"""Example of CORS setup using cherrypy-cors library."""

import cherrypy
import cherrypy_cors


# Python 2 compat: make all classes new-style by default
__metaclass__ = type  # pylint: disable=invalid-name


class WebRoot:
    """Root node for HTTP handlers."""

    @cherrypy.expose
    def index(self):  # pylint: disable=no-self-use
        """Render a web page handling request against ``/``.

        Contains client JS snippet which will query the API endpoint.
        It will be executed by the browser while loading the page.
        """
        return """<html>
            <script type="text/javascript">
                async function addMeeting() {
                  /*
                   * Example coroutine for querying /add_meeing
                   * HTTP endpoint. It uses localhost as in the URL.
                   * For testing CORS, make sure to visit
                   * http://127.0.0.1/ which is a different origin
                   * from browser's perspective.
                   * /
                  const request_payload = {
                    some: 'data',
                    listed: ['h', 'er', 'e'],
                  }
                  try {
                    const resp = await fetch(
                      'http://localhost:3333/add_meeting',
                      {
                        method: 'POST',
                        mode: 'cors',  // Required for customizing HTTP request headers
                        credentials: 'same-origin',
                        headers: {
                          'Content-Type': 'application/json; charset=UTF-8',  // Required for ``cherrypy.tools.json_in`` to identify JSON payload and parse it automatically
                        },
                        body: JSON.stringify(request_payload),
                      },
                    )
                    const json_resp = await resp.json()
                    console.log(json_resp)  // Will print: {"method": "POST", "payload": {"listed": ["h", "er", "e"], "some": "data"}}
                  } catch (e) {
                    console.warn('Exception: ' + e)
                  }
                }

                async function main() {
                  await addMeeting()
                }

                main()  // Entry point
            </script>
        </html>"""  # noqa: E501

    @cherrypy.expose
    @cherrypy.tools.json_in()  # turn HTTP payload into an object; also checking the Content-Type header
    @cherrypy.tools.json_out()  # turn ``return``ed Python object into a JSON string; also setting corresponding Content-Type
    def add_meeting(self):
        """Handle HTTP requests against ``/add_meeting`` URI."""
        if cherrypy.request.method == 'OPTIONS':
            # This is a request that browser sends in CORS prior to
            # sending a real request.

            # Set up extra headers for a pre-flight OPTIONS request.
            cherrypy_cors.preflight(allowed_methods=['GET', 'POST'])

        if cherrypy.request.method == 'POST':
            return {'method': 'POST', 'payload': cherrypy.request.json}

        return {'method': 'non-POST'}


def main():
    """Set up and run the web app.

    Initializes CORS tools.
    Sets up web server socket.
    Enables the CORS tool.
    """
    cherrypy_cors.install()
    cherrypy.config.update({
        'server.socket_host': '127.0.0.1',
        'server.socket_port': 3333,
        'cors.expose.on': True,
    })
    cherrypy.quickstart(WebRoot())


__name__ == '__main__' and main()  # pylint: disable=expression-not-assigned