1

I have a simple flask server

import pdb

from flask import Flask, jsonify, abort, make_response, request, send_from_directory
from flask_cors import CORS, cross_origin
from pprint import pprint

import argparse

from mylib.mylib_rest_api import ProcessRestApiRequest


DEBUG=True
app = Flask(__name__)
CORS(app)

parser = argparse.ArgumentParser(description='Run the server')

parser.add_argument('--ip-address', default='127.0.0.1', help='Server IP Address. Default: %(default)s')
parser.add_argument('--port', type=int, default=8081, help='Server port')

args = parser.parse_args()

@app.errorhandler(404)
def not_found(error):
    return make_response(jsonify({'error': 'Not found'}), 404)

def do_pre_serve_actions():
    if not request.json: abort(400)
    # Extract the data
    dictReq = request.get_json(force=True)
    if DEBUG:
        pprint('dictReq: '+str(dictReq))
    return dictReq

def do_post_serve_actions(dictResp):
    if DEBUG:
        pprint("dictResp: "+str(dictResp))
    dictJSONResp = jsonify(dictResp)
    objRespADF = make_response(dictJSONResp)
    return objRespADF

@app.route('/<target>', methods=['POST'])
def serve(target):
    dictReq = do_pre_serve_actions()
    dictResp = ProcessRestApiRequest(dictReq, target)
    return do_post_serve_actions(dictResp)

if __name__ == '__main__':
    app.run(debug=DEBUG, host=args.ip_address, port=args.port)

This is how a request looks like:

makeRequestAndSendData(xhr, dict) {
    dict['Interface'] = this.getChipInterface();
    var data = JSON.stringify(dict);
    var url = this.server.getUrl();

    console.log("url: "+url);
    console.log("Request Dictionary:");
    console.log(dict);

    xhr.open("POST", url, true);
    xhr.setRequestHeader("Access-Control-Allow-Origin", "*");
    xhr.setRequestHeader("Access-Control-Allow-Headers","*");
    xhr.setRequestHeader("Access-Control-Allow-Credentials", "true");
    xhr.setRequestHeader("Content-type","application/json");
    xhr.send(data);
}

Here is what I'm getting:

Failed to load http://192.168.0.132:8084/mychip: Response to preflight request doesn't pass access control check: The 'Access-Control-Allow-Origin' header has a value 'null' that is not equal to the supplied origin. Origin 'null' is therefore not allowed access.

What am I doing wrong? I've looked everywhere online and it seems like it got everything I need. Am I missing something?

flashburn
  • 4,180
  • 7
  • 54
  • 109
  • Those headers are supposed to come from the server, not from the client. Make your server return them. But be careful so you don't introduce any CORS vulnerabilities. – kichik Apr 03 '18 at 01:32
  • @kichik I'm using this only for testing. The product will never be released in the wild. Various reasons for doing it that way. – flashburn Apr 03 '18 at 04:02
  • @kichik I've added all the headers to the response, but I'm still getting the same error. Tried running `curl -i http://192.168.0.132:8084/mychip` and got the following https://pastebin.com/uZ44WKXb. I'm somewhat new to readers and responses so any help would be appreciated. – flashburn Apr 03 '18 at 04:13
  • Your server is returning 405 for some reason. Maybe have it accept `OPTIONS`. – kichik Apr 03 '18 at 04:20
  • 1
    @kichik I'm confused. My server works without any modifications with a Firefox browser, but doesn't work with Chrome. What is the reason for that? – flashburn Apr 03 '18 at 05:14
  • Probably a small variance in CORS handling. Try using Firefox developer tools and you should only see a `POST` request. Use it on Chrome and you'll see the preflight `OPTIONS` request. – kichik Apr 03 '18 at 05:16
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/168081/discussion-between-flashburn-and-kichik). – flashburn Apr 03 '18 at 05:17
  • I'm also suffering because of this today - Firefox gets further than Chrome presumably because there's no preflight check, but still fails at the response stage. None of the solutions at https://stackoverflow.com/questions/26980713/solve-cross-origin-resource-sharing-with-flask work for me... – jtlz2 Apr 03 '18 at 08:18
  • Take that back - works fine in Firefox but not in Chrome – jtlz2 Apr 03 '18 at 08:21

1 Answers1

0

This can happen with Chrome and WebKit/Chrome based browsers (Opera, Brave, etc.) if you serve the page from the file system instead of the network. In that case there is no origin site (because it was served from file), and Chrome will send the header Origin: null in the preflight OPTIONS request. Your CORS enabled Flask server will reply with this origin in its preflight response, however, Chrome rejects it as an invalid origin, even though that is what Chrome sent in the first place.

Firefox also sends header Origin: null in the OPTIONS request, but it is OK with the response and so it does issue the actual POST request. I have also found that Chrome on Android does seem to work when loading from the file system.

As a work-around, serve your test file from a HTTP server. The easiest way (for testing purposes only) is to use Python's SimpleHTTPSever. Simply change to the directory containing your test HTML file and run this command:

$ python -m SimpleHTTPServer

It will start a HTTP server listening on port 8000 so you can load the file into your browser using URL http://localhost:8000/cors_test.html for example.

Also note that the Access-Control-Allow-* headers are meant to be sent in the preflight response, not the request. flask-cors will generally handle that for you and the client side XMLHttpRequest object should properly construct the request for you.

mhawke
  • 84,695
  • 9
  • 117
  • 138