I want to set all of my http headers responses to something like this:
response.headers["X-Frame-Options"] = "SAMEORIGIN"
I checked this question, but it only changes the header for one specific controller. I want to change all of my headers maybe in "before_request" function similar to the following logic. How can I do that?
#app.before_request
def before_request():
# response.headers["X-Frame-Options"] = "SAMEORIGIN"
Set the header in a #app.after_request() hook, at which point you have a response object to set the header on:
#app.after_request
def apply_caching(response):
response.headers["X-Frame-Options"] = "SAMEORIGIN"
return response
The flask.request context is still available when this hook runs, so you can still vary the response based on the request at this time.
The #app.after_request() hook was not adequate for my use case.
My use case is as follows: I have a google cloud function, and I want to set the CORS headers for all responses. There are possibly multiple responses, as I have to validate the input and return if there are issues with it, I have to process data and possibly return early if something fails etc. So I've created a helper function as follows:
# Helper function to return a response with status code and CORS headers
def prepare_response(res_object, status_code):
response = flask.jsonify(res_object)
response.headers.set('Access-Control-Allow-Origin', '*')
response.headers.set('Access-Control-Allow-Methods', 'GET, POST')
return response, status_code
Thus, when I want to return a response (always with CORS headers), I can now call this function and I do not duplicate the response.headers setup necessary to enable CORS.
We can set the response headers for all responses in Python Flask application gracefully using WSGI Middleware
This way of setting response headers in Flask application context using middleware is thread safe and can be used to set custom & dynamic attributes, read the request headers this is especially helpful if we are setting custom/dynamic response headers from any helper class.
file: middleware.py
import flask
from flask import request, g
class SimpleMiddleWare(object):
"""
Simple WSGI middleware
"""
def __init__(self, app):
self.app = app
self._header_name = "any_request_header"
def __call__(self, environ, start_response):
"""
middleware to capture request header from incoming http request
"""
request_id_header = environ.get(self._header_name) # reading all request headers
environ[self._header_name] = request_id_header
def new_start_response(status, response_headers, exc_info=None):
"""
set custom response headers
"""
# set the above captured request header as response header
response_headers.append((self._header_name, request_id_header))
# example to access flask.g values set in any class thats part of the Flask app & then set that as response header
values = g.get(my_response_header, {})
if values.get('x-custom-header'):
response_headers.append(('x-custom-header', values.get('x-custom-header')))
return start_response(status, response_headers, exc_info)
return self.app(environ, new_start_response)
Calling the middleware from main class
file : main.py
from flask import Flask
import asyncio
from gevent.pywsgi import WSGIServer
from middleware import SimpleMiddleWare
app = Flask(__name__)
app.wsgi_app = SimpleMiddleWare(app.wsgi_app)
Related
Chrome warns:
A site requested a resource from a network that it could only access because of its users' privileged network position. These requests expose devices and servers to the internet, increasing the risk of a cross-site request forgery (CSRF) attack, and/or information leakage.
To mitigate these risks, Chrome will require non-public subresources to opt-into being accessed with a preflight request and will start blocking them in Chrome 101 (April 2022).
To fix this issue, ensure that response to the preflight request for the private network resource has the Access-Control-Allow-Private-Network header set to true.
I am using flask, but unsure how to add this header to the preflight check. I can add a header to the responses manually, but how to add a header to the preflight check?
I am using Flask-Cors and this is the code:
app = Flask(__name__)
cors = CORS(app)
app.config['CORS_HEADERS'] = 'Content-Type'
I dropped the Flask-Cors package, and made my own implementation:
""" Note:
We need to use functools wraps, or else #route thinks all functions
are named the same, and errors out that a route is overriding another
Test Preflight with:
curl -i -X OPTIONS http://127.0.0.1:5000/foo/
Then test reponse with:
curl -i http://127.0.0.1:5000/api/foo/
"""
from functools import wraps
from flask import Response, request
def add_cors_preflight_headers(response):
allow_request = 'foo' in request.origin
if allow_request:
response.headers['Access-Control-Allow-Origin'] = request.origin
if request.method == 'OPTIONS':
response.headers['Access-Control-Allow-Methods'] = 'GET, OPTIONS'
response.headers['Access-Control-Allow-Headers'] = 'Content-Type'
# Allow chrome to access private network ajax requests
response.headers['Access-Control-Allow-Private-Network'] = 'true'
return response
def handle_cors(func):
#wraps(func)
def decorator(*args, **kwargs):
if request.method == 'OPTIONS':
response = Response()
else:
response = func(*args, **kwargs)
response = add_cors_preflight_headers(response)
return response
return decorator
Then used as follows (note how we add options to the allowed methods):
#app.route("/api/foo/", methods=['GET', 'OPTIONS'])
#handle_cors
def get_foo():
return Response({'foo': 'hello world!'})
I am new to python and flask and I am encountering a problem with Flask. I am trying to use a local HTTP POST (webhook) to call a function from another file, but when I do nothing happens.
from flask import Flask
from BotSpeak import main
app = Flask(__name__)
#app.route('/', methods=['POST'])
def respond():
main('hello')
if __name__ == '__main__':
app.run()
This is my very basic Flask app. As you can see it is trying to call the main function from this file (BotSpeak):
from json import dumps
from httplib2 import Http
def main(botmsg):
url = 'PLACEHOLDER FOR GOOGLE CHAT WEBHOOK URL'
bot_message = {
'text' : botmsg}
message_headers = {'Content-Type': 'application/json; charset=UTF-8'}
http_obj = Http()
response = http_obj.request(
uri=url,
method='post',
headers=message_headers,
body=dumps(bot_message),
)
print(response)
if __name__ == '__main__':
main("TEST MESSAGE")
This is the code that shoots local HTTP POSTs to my flask app:
import json
import requests
webhook_url ='http://127.0.0.1:5000/'
data = {PLACE HOLDER FOR JSON DATA}
r = requests.post(webhook_url, data=json.dumps(data), headers={'Content-Type': 'application/json'})
I can call the main function from other files outside the flask app and it'll work but it just wont trigger in the app.route decorator like it should. I really appreciate anyone's help and I encourage you to throw these into VS Code and try it for yourself.
If you're using flask you don't have to manually construct an HTTP response using httplib2 unless you have some very specific use case.
In your case you can just return bot_message since if the return value of a Flask handler is a dict it will convert it to a JSON response (including the correct headers). See
https://flask.palletsprojects.com/en/2.0.x/quickstart/#about-responses
In other words, your entire route handler could be rewritten (based off your example at least):
#app.route('/', methods=['POST'])
def respond():
return {'text': 'hello'}
If you want to pass the handling off to some utility function you can do that too, just make sure it returns a value, and that you in turn return an appropriate value from your respond() function.
Assuming that I have an API endpoint api.example.com/v1/data and a GET method with #jwt-required similar to this:
from flask_jwt_extended import jwt_required
from flask_restful import Resource
class Data(Resource):
#jwt_required
def get(self):
"""
GET Response message.
"""
return {"message":"important-info", "ts":datetime}, 200
So to GET this message you need to authenticate yourself with a Bearer "access_token" in the request's header.
How could I create an HMAC for this message. Ideally I would like to add the access token, so to check the integrity of the whole message.
So I would like to have an extra field in the returned JSON called checksum with a value hash(whole_message).
You can use Flask's after_request to register a function that processes the response after it was generated by the view.
For example, to do exactly what you ask for (I am using built-in python's hash function, you can import/write your own as needed):
#app.after_request
def after_request(response):
data = json.loads(response.get_data())
data['checksum'] = hash(response.get_data())
response.set_data(json.dumps(data))
return response
However, you will have to make sure to always return a dictionary for this to work. Here are a couple alternatives:
1) Include the view's response inside another json, e.g.:
#app.after_request
def after_request(response):
data = json.loads(response.get_data())
data = {
'response': data,
'checksum': hash(response.get_data())
}
response.set_data(json.dumps(data))
return response
2) Add the checksum to the response headers (I would go with this one). E.g.:
#app.after_request
def after_request(response):
response.headers['Checksum'] = hash(response.get_data())
return response
As a final note, if you want to hash the response using the access token, as you state in your question, you can access this token from the request object, like so:
from flask import request
access_token = request.headers.get('Authorization')
So now you can use access_token in whatever way you need.
I am new to unit testing using script. I tried to verify login with arguments in post data, but I am getting login page as response and not get logged in.Because of #tornado.web.authenticated i can't access other functions without login and it responding to login page
import tornado
from tornado.testing import AsyncTestCase
from tornado.web import Application, RequestHandler
import app
import urllib
class MyTestCase(AsyncTestCase):
#tornado.testing.gen_test
def test_http_fetch_login(self):
data = urllib.urlencode(dict(username='admin', password=''))
client = AsyncHTTPClient(self.io_loop)
response = yield client.fetch("http://localhost:8888/console/login/?", method="POST",body=data)
# Test contents of response
self.assertIn("Automaton web console", response.body)
#tornado.testing.gen_test
def test_http_fetch_config(self):
client = AsyncHTTPClient(self.io_loop)
response = yield client.fetch("http://localhost:8888/console/configuration/?")
self.assertIn("server-version",response.body)
To test code that uses #authenticated (unless you are testing the redirection to the login page itself), you need to pass a cookie (or whatever form of authentication you're using) that will be accepted by your get_current_user method. The details of this will vary depending on how exactly you are doing your authentication, but if you're using Tornado's secure cookies you'll probably use the create_signed_value function to encode a cookie.
From documentation:
If you decorate post() methods with the authenticated decorator, and the user is not logged in, the server will send a 403 response. The #authenticated decorator is simply shorthand for if not self.current_user: self.redirect() and may not be appropriate for non-browser-based login schemes.
So you can use mock do like pointed in this answer: https://stackoverflow.com/a/18286742/1090700
Another 403 status will be thrown on POST calls if you have secure_cookies=True app param. If you want to test the code in a non debug fashion, you can also using mock POST actions while keeping the secure_cookies=True application parameter and then just mock the check_xsrf_cookie Handler method as well, like this:
# Some previous stuff...
with mock.patch.object(YourSecuredHandler, 'get_secure_cookie') as mget:
mget.return_value = 'user_email'
response = self.fetch('/', method='GET')
with mock.patch.object(
YourSecuredHandler, 'check_xsrf_cookie') as mpost:
mpost.return_value = None
response = self.fetch(
url, method="POST", body=parse.urlencode(body1),
headers=headers)
self.assertEqual(response.code, 201)
I need to have a proxy that acts as an intermediary to fetch images. An example would be, my server requests domain1.com/?url=domain2.com/image.png and domain1.com server will respond with the data at domain2.com/image.png via domain1.com server.
Essentially I want to pass to the proxy the URL I want fetched, and have the proxy server respond with that resource.
Any suggestions on where to start on this?
I need something very easy to use or implement as I'm very much a beginner at all of this.
Most solutions I have found in python and/or django have the proxy acts as a "translater" i.e. domain1.com/image.png translates to domain2.com/image.png, which is obviously not the same.
I currently have the following code, but fetching images results in garbled data:
import httplib2
from django.conf.urls.defaults import *
from django.http import HttpResponse
def proxy(request, url):
conn = httplib2.Http()
if request.method == "GET":
url = request.GET['url']
resp, content = conn.request(url, request.method)
return HttpResponse(content)
Old question but for future googlers, I think this is what you want:
# proxies the google logo
def test(request):
url = "http://www.google.com/logos/classicplus.png"
req = urllib2.Request(url)
response = urllib2.urlopen(req)
return HttpResponse(response.read(), mimetype="image/png")
A very simple Django proxy view with requests and StreamingHttpResponse:
import requests
from django.http import StreamingHttpResponse
def my_proxy_view(request):
url = request.GET['url']
response = requests.get(url, stream=True)
return StreamingHttpResponse(
response.raw,
content_type=response.headers.get('content-type'),
status=response.status_code,
reason=response.reason)
The advantage of this approach is that you don't need to load the complete file in memory before streaming the content to the client.
As you can see, it forwards some response headers. Depending on your needs, you may want to forward the request headers as well; for example:
response = requests.get(url, stream=True,
headers={'user-agent': request.headers.get('user-agent')})
If you need something more complete than my previous answer, you can use this class:
import requests
from django.http import StreamingHttpResponse
class ProxyHttpResponse(StreamingHttpResponse):
def __init__(self, url, headers=None, **kwargs):
upstream = requests.get(url, stream=True, headers=headers)
kwargs.setdefault('content_type', upstream.headers.get('content-type'))
kwargs.setdefault('status', upstream.status_code)
kwargs.setdefault('reason', upstream.reason)
super().__init__(upstream.raw, **kwargs)
for name, value in upstream.headers.items():
self[name] = value
You can use this class like so:
def my_proxy_view(request):
url = request.GET['url']
return ProxyHttpResponse(url, headers=request.headers)
The advantage of this version is that you can reuse it in multiple views. Also, it forwards all headers, and you can easily extend it to add or exclude some other headers.
If the file you're fetching and returning is an image, you'll need to change the mimetype of your HttpResponse Object.
Use mechanize, it allow you to choose a proxy and act like a browser, making it easy to change the user agent, to go back and forth in the history and to handle authentification or cookies.