Flask forgetting Routes on POST - python

I am trying to run a very simple flask-application on a (shared) WSGI server. The code works fine when I run it with the build-in server, but if I try to POST to the URL on the production WSGI server, I receive a 404, The requested URL was not found on the server error.
This only occurs for POST requests, GET and PUT are processed as expected.
By removing the placeholder tid, flask can be convinced to properly process the request, but this is obviously not a proper solution.
The server is running Phusion Passenger, the flask version is 1.0.2.
As it is a shared server, I have no further access to the server configuration.
What can cause flask to seemingly forget routes on a WSGI-server?
A minimal example that reproduces to behaviour (on the server only, of course) can be seen below:
from flask import Flask
from flask.views import MethodView
app = Flask(__name__)
class API(MethodView):
def get(self, tid=0):
return "Test"
def put(self, tid=0):
return "Test"
def post(self, tid=0):
return "Test"
app.add_url_rule("/test/<int:tid>", view_func=API.as_view('api'))

You have to specify the methods you use in add_url_rule:
app.add_url_rule("/test/<int:tid>", view_func=API.as_view('api'), methods=['GET', 'PUT', 'POST'])

Related

Python Flask - abort(400) does not use intended template when called from open_session

For my app, I manage session data on the server in a database with help form flask_session.
I want to modify behaviour so that a session is only created if the remote address is not on an IP blacklist.
I've amended SessionInterface's open_session to include the following:
self.firewall = Firewall # flask_sqlalchemy model
def open_session(self, app, request):
firewall = self.firewall.query.filter_by(ip_address=request.remote_addr).first()
if firewall and firewall.black_list:
abort(400)
...
To mark up to nicer errors, I create error handlers:
#main.app_errorhandler(400)
def bad_request(e):
return render_template("400.html"),400
The database firewall lookup works, and the abort(400) is called as expected.
The problem is the abort call from the open_session does not trigger the use of the template. When an abort is called from any blueprint view linked to the app, it does use the template.
How can I force the use of the abort template I have prepared from the open_session?

Previously-set request cookies returns None in a Flask application

I'm trying to store JWT Tokens in cookies for a Flask application to restrict some endpoints. An endpoint, "/authorize" , is responsible for setting the cookies then redirect the page to the root endpoint, "/".
from flask import Flask, request, make_response, redirect
#app.route("/authorize", methods=["GET"])
def authorize():
token = request.args.get('token')
expires = request.args.get('expires')
# some code to validate the token
resp_output = make_response(redirect("/"))
resp_output.set_cookie("token", token, expires=expires)
return resp_output
#app.route("/", methods=["GET"])
def index():
token = request.cookies.get("token)
# do something with the token
However, when I tried to deploy this, I ran into some problems with the redirecting and therefore have to change redirect("/") to redirect("https://someaddress.com/)" where https://someaddress.com/ is the address of the flask application. Now when I try to retrieve the token cookies in the root endpoint, it returns None. I suspect it is because the redirection has turnt from an internal one to an external one.
Please help me find a workaround for this. Or if you think I should resolve the problems that lead to the change from internal to external redirection so I can go back to what works. (If anyone can point me to some resources explaining exactly how redirection, or more specifically Flask's redirection, works, I'd really appreciate it.)
Using url_for function from flask should work in your case, as it will look for the link within the app context:
from flask import Flask, request, make_response, redirect, url_for
#app.route("/authorize", methods=["GET"])
def authorize():
token = request.args.get('token')
expires = request.args.get('expires')
# some code to validate the token
resp_output = make_response(redirect(url_for('index')))
resp_output.set_cookie("token", token, expires=expires)
return resp_output
#app.route("/", methods=["GET"])
def index():
token = request.cookies.get("token)
# do something with the token
Btw, I would recommend you pass your authorization logic to a decorator, have a look on authorization decorators using flask.
In case this don't work in production, that can be some setting related to your reverse proxy - like nginx conf file. Let me know if it is the case
on Nginx file on sites-enabled folder etc/nginx/sites-enabled/<project-name>, comment or remove the following line:
proxy_set_header Host $host;
Hope it suits you well!

API and APP Flask [duplicate]

I'm trying to send a post request to my Flask app from one of its own views, but it hangs until I kill the server. If I do the request in JavaScript, it works fine. Why does it not work from the Python code?
from flask import Blueprint, render_template, abort, request, Response, session, url_for
from jinja2 import TemplateNotFound
from flask.ext.wtf import Form
from wtforms import BooleanField, TextField, PasswordField
import requests
login = Blueprint('login', __name__, template_folder='templates')
class LoginForm(Form):
email = TextField('Email')
password = PasswordField('Password')
#login.route('/login', methods=['GET', 'POST'])
def _login():
form = LoginForm(request.form, csrf_enabled=False)
if form.validate_on_submit():
return requests.post(request.url_root + '/api/login', data={"test": True})
return render_template('login.html', form=form)
Prior to 1.0, Flask's development server was single-threaded by default. In that mode, it can only handle one request at a time. Making a request blocks until it receives the response. Your Flask code makes a request in the one thread, and then waits. There are no other threads to handle this second request. So the request never completes, and the original request waits forever.
Enable threads in the dev server to avoid the deadlock and fix the immediate problem.
app.run(threaded=True)
However, making a full HTTP request to the app from within the app should never be necessary and indicates a deeper design issue. For example, observe that the internal request will not have access to the session on the client's browser. Extract the common code and call it internally, rather than making a new request.
def common_login(data):
...
#app.route("/login")
def login():
...
common_login(data)
...
#app.route("/api/login")
def api_login():
...
common_login(data)
...
I'm not familiar with Flask. However this bit of code:
if form.validate_on_submit():
return requests.post(request.url_root + '/api/login', data={"test": True})
Seems like you're accepting a posted form, validating it, and then posting it again. Over and over.

how do I make get request directly to a flask app object

I inherited a project that uses flask. This flask application has several APIs, each API has a GET function that returns a json object.
I was asked to implement an additional API that requests information from the other APIs. So my question is how do I make a GET request directly to a flask application? Is it something like....
from flask import request
#app.route('/root_dir/api_number_1/info', methods=['GET'])
def request_info_from_api_number_1():
return request.get_json()
#app.route('/root_dir/api_number_2/info', methods=['GET'])
def request_info_from_api_number_2():
return request.get_json()
When I do this the functions return None. I suppose I could always make an http request to the flask url and specify the address as localhost but it seems strange to have to make an http request when I can directly access the flask app object.
Could you just use the existing api functions?
from flask import Flask
app = Flask(__name__)
#app.route("/foo")
def foo():
return "foo"
#app.route("/foobar")
def foobar():
return foo() + "bar"
if __name__ == "__main__":
app.run(debug=True)

Flask hangs when sending a post request to itself

I'm trying to send a post request to my Flask app from one of its own views, but it hangs until I kill the server. If I do the request in JavaScript, it works fine. Why does it not work from the Python code?
from flask import Blueprint, render_template, abort, request, Response, session, url_for
from jinja2 import TemplateNotFound
from flask.ext.wtf import Form
from wtforms import BooleanField, TextField, PasswordField
import requests
login = Blueprint('login', __name__, template_folder='templates')
class LoginForm(Form):
email = TextField('Email')
password = PasswordField('Password')
#login.route('/login', methods=['GET', 'POST'])
def _login():
form = LoginForm(request.form, csrf_enabled=False)
if form.validate_on_submit():
return requests.post(request.url_root + '/api/login', data={"test": True})
return render_template('login.html', form=form)
Prior to 1.0, Flask's development server was single-threaded by default. In that mode, it can only handle one request at a time. Making a request blocks until it receives the response. Your Flask code makes a request in the one thread, and then waits. There are no other threads to handle this second request. So the request never completes, and the original request waits forever.
Enable threads in the dev server to avoid the deadlock and fix the immediate problem.
app.run(threaded=True)
However, making a full HTTP request to the app from within the app should never be necessary and indicates a deeper design issue. For example, observe that the internal request will not have access to the session on the client's browser. Extract the common code and call it internally, rather than making a new request.
def common_login(data):
...
#app.route("/login")
def login():
...
common_login(data)
...
#app.route("/api/login")
def api_login():
...
common_login(data)
...
I'm not familiar with Flask. However this bit of code:
if form.validate_on_submit():
return requests.post(request.url_root + '/api/login', data={"test": True})
Seems like you're accepting a posted form, validating it, and then posting it again. Over and over.

Categories

Resources