How to use Splash with python-requests? - python-2.7

I want to use splash in requests, something like this
requests.post(myUrl,headers=myHeaders, data=payload, meta={
'splash': {
'endpoint': 'render.html',
'args': {'wait': 1}
}
})
but I have this error
TypeError: request() got an unexpected keyword argument 'meta'
I know that this work with scrapy.Request but I want to use with requests

meta is Scrapy Request-specific and python-requests' request does not have a meta argument, hence the TypeError exception.
To use Splash with python-requests, read the HTTP API docs, especially on render.html as this is what you want to use it seems.
You'll want a GET request to the /render.html endpoint, and pass target URL, and wait argument as query parameter, e.g. like this:
import requests
requests.get('http://localhost:8050/render.html',
params={'url': 'http://www.example.com', 'wait': 2})
If you want Splash to issue a POST request to the target website, use http_method and body arguments:
import requests
requests.get('http://localhost:8050/render.html',
params={'url': 'http://httpbin.org/post',
'http_method': 'POST',
'body': 'a=b',
'wait': 2})
/render.html also allows POST-ed requests to the endpoint:
Splash is controlled via HTTP API. For all endpoints below parameters may be sent either as GET arguments or encoded to JSON and POSTed with Content-Type: application/json header.
but the default method is still GET. To do a POST to the target website, you still need to include a http_method argument:
import requests
requests.post('http://localhost:8050/render.html',
json={'url': 'http://httpbin.org/post',
'http_method': 'POST',
'body': 'a=b',
'wait': 2})

Related

Django CSRF Token present but still getting 403 Forbidden Error

I am trying to set up a Django API that receives POST requests with some JSON data and basically sends emails to a list of recipients. The logic is rather simple:
First I have the view for when I create a blog post. In the template, I include the csrf_token as specified on the Django Documentation. When I hit the submit button, behind the scene the create-post view, in addition to creating the post, makes a request (I am using the requests module) to the API which is charged with sending the emails. This is the piece of logic the sends the request to the API:
data = {
"title": new_post.title,
"summary": new_post.summary,
"link": var["BASE_URL"] + f"blog/post/{new_post.slug}"
}
csrf_token = get_token(request)
# print(csrf_token)
headers = {"X-CSRFToken": csrf_token}
requests.post(var["BASE_URL"] + "_api/send-notification/", json=data, headers=headers)
As you can see I am adding the X-CSRFToken to the headers which I generate through the get_token() method, as per the Django docs. However, the response in the API is a 403 Forbidden status CSRF Token not set.
I have checked the headers in the request and the token is indeed present. In addition, I have been providing other routes to the API and I have been using it for AJAX calls which again is very simple just follow the Django docs and they work perfectly well.
The problem seems to arise when I make the call from within the view, AJAX calls are handle by Javascript static files, and as I said they work fine.
I have thought that Django didn't allow the use of 2 CSRF tokens on the same page (one for the submit form and the other in the view by get_token()), but that's not the problem.
This is typically the error I get:
>>> Forbidden (CSRF cookie not set.): /_api/send-notification/
>>> "POST /_api/send-notification/ HTTP/1.1" 403 2864
I have read several similar questions on SO but they mostly involved using the csrf_exempt decorator, which in my opinion is not really a solution. It just gets rid of the CRSF token usefulness altogether.
Does anyone have any idea what might be causing this problem?
Thanks
Error tries to tell you that you need to add token into cookie storage like that:
cookies = {'csrftoken': csrf_token}
requests.post(var["BASE_URL"] + "_api/send-notification/", json=data, headers=headers, cookies=cookies)

Flask cannot parse JSON in Tabulator AJAX request (using advanced configuration)

I regularly use Tabulator's setData() method. I usually set parameters in the URL args, and have no problems with it. But I now have a complex use case that will be easier to solve if I can put a JSON payload into the request.
I've followed the Tabulator documentation for an advanced configuration.
I've made a series of attempts (putting the JSON in various places, using quotes/double quotes in the JSON, etc) at trying to work out the problem. The Flask server always returns this error:
Failed to decode JSON object: Expecting value: line 1 column 1 (char 0)
What makes me suspect the problem is with Tabulator, not Flask, is because I printed request.__dict__ and couldn't find the JSON in the request. (I.e. that seems to the reason for the error.)
The below example, which triggers the same error, is taken from the Fetch documentation (Tabulator uses the Fetch API).
Is there anything wrong with the below or should I be looking harder at Flask?
const data = { username: 'example' };
var ajaxURL = "/data/results";
var ajaxConfig = {
method:"POST",
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrf_token,
},
body: JSON.stringify(data)
};
ResultsTable.setData( ajaxURL, {}, ajaxConfig);
Notes:
I'm using the latest version of Tabulator (4.9).
ResultsTable is set elsewhere in the code and is successfully loading default data when the page loads. The use case kicks in when the user sets their own parameters for the data.
The CSRF token, which is set elsewhere in the code, is there because Flask requires it.
The reason that is failing is that Tabulator will build out its own request body when it builds a request and that will override your config.
In your usage case, you will need to override the build in ajax request promise and add your own function that makes the ajax request and then resolves the data.
You can do this using the ajaxRequestFunc.
Checkout the Ajax Request Documentation for full details

Axios Authorization not working - VueJS + Django

I am trying to build an application using VueJS and Django. I am also using Graphene-Django library, as the project utilize GraphQL.
Now, The authentication works fine and i get a JWT Token back.
But when i use the token for other queries that need authentication, i got this error in Vue:
"Error decoding signature"
and the Django Log also returns this:
graphql.error.located_error.GraphQLLocatedError: Error decoding signature
jwt.exceptions.DecodeError: Not enough segments
ValueError: not enough values to unpack (expected 2, got 1)
the bizarre thing is that the same query when executed in Postman just works fine.
As i mentioned in the title is use Axios for my requests, here's an example of a request:
axios({
method: "POST",
headers: { Authorization: "JWT " + localStorage.getItem("token") },
data: {
query: `{
dailyAppoint (today: "${today}") {
id
dateTime
}
}`
}
});
Note: It uses 'JWT' not 'Bearer' because somehow 'Bearer' didn't work for me.
Ok, couple of questions, does you API work without Vue.js from curl. Generate token, check API from curl.
If it does, then check the Headers sent from the request, from Network Inspector, mozilla dev tools/chrome devtools. And update your Post with those RAW Headers.
This particular error arises when your public key is unable to decode the string[token] signed by your private key. Which ultimately means the access token has been tampered with. It could also mean you're sending values like 'unkown'-- JS state initialization error.
Check the RAW headers of the request. It'll help.
Use a request interceptor to set the Authorization header:
axios.interceptors.request.use(config => {
if (localStorage.getItem("token") != null)
config.headers["Authorization"] = "JWT " + localStorage.getItem("token");
return config;
});

Return data as json from odoo 9

I want get data in JSON format from odoo controllery.py
Example:
import openerp.http as http
from openerp.http import request
class MyController(http.Controller):
#http.route('/test_html', type="http", auth="public")
def some_html(self):
return "<h1>Test</h1>"
#Work fine when open http://localhost:8069/test.html
#http.route('/test_json', type="json", website=True, auth="public")
def some_json(self):
return [{"name": "Odoo", 'website': 'www.123.com'}]
How get data in json format, I want data from json read in other app with ajax.
Is it possible view json after open url http://localhost:8069/test_json ???
The important part is to define the contentType of your request properly.
import json
#http.route('/test_json', type="json", auth="public")
def some_json(self):
return json.dumps({"name": "Odoo", 'website': 'www.123.com'})
In your client using javascript you can request the json like this.
$.ajax({
type: "POST",
url: "/test_json",
async: false,
data: JSON.stringify({}),
contentType: "application/json",
complete: function (data) {
console.log(data);
}
});
Or using requests in python
import requests,json
res = requests.post("http://localhost:8069/test_json",data=json.dumps({}),headers={"Content-Type":"application/json"})
To access the response body
body = res.text
As to whether you can simply open a browser and view the json. No, not by default.
Here is what I get
Bad Request
<function some_json at 0x7f48386ceb90>, /test_json: Function declared as capable of handling request of type 'json' but called with a request of type 'http'
You could probably do something pretty fancy with a controller if you really wanted to be able to view it in a browser as well as make json requests. I would post a second question though.
Your controller endpoint looks ok and should function correctly, so I guess your main question is how to test it.
Once you declare that the endpoint type is json, Odoo will check that the request content type header is in fact JSON, so in order to test it your requests will need to have Content-Type: application/json header set. This is a bit difficult using a regular browser, unless you edit the request headers before seinding or call your JSON endpoint from JavaScript via Ajax.
Alternatively, you can test your API from command line using a tool like curl:
curl 'http://localhost:8069/test_json' -H 'Content-Type: application/json' --data "{}"
--data "{}" here indicates an empty JSON structure which will be passed to your endpoint as request parameters.
Please note that you might also have to pass an additional header containing your session_id cookie if you are using more than one Odoo database.

Ajax, CSRF and DELETE

I use the getCookie function from the django documentation to get the csrfmiddlewaretoken value.
I have the following ajax call:
var url = reverse_removeprofile.replace(/deadbeef/, key);
$.ajax({
type: "DELETE",
url: url,
data: "csrfmiddlewaretoken=" + getCookie("csrftoken"),
success: function() { ... },
});
When this code gets executed then django raises a 403 exception telling me that the CSRF verification failed. However, if I change the type from DELETE to POST then django is happy about it and doesn't complain at all.
I was not really able to find something useful in Google about this, but I've found this (now closed and fixed) ticket: https://code.djangoproject.com/ticket/15258
If I understand it correctly then this issue has been fixed in the 1.4 milestone. I use django 1.4 but still I cannot verify the CSRF token with a DELETE request.
Am I missing something here?
This appears to be a jQuery bug, caused by some confusion as to whether DELETE data should be attached to the URL (like a GET request) or the request body (like a POST)
See this bug report.
You can probably get around this by using the alternative CSRF method for AJAX calls, setting an X-CSRFToken header on the request. Try changing your AJAX call to look like this:
$.ajax({
type: "DELETE",
url: url,
beforeSend: function(xhr) {
xhr.setRequestHeader("X-CSRFToken", getCookie("csrftoken"));
},
success: function() { ... },
});
Please note, when it comes to DELETE requests DJango does not check for csrfmiddlewaretoken in the request body. Rather it looks for X-CSRFToken header
Coming to working of DJango CSRFMiddleware you can see the source code of django > middleware > csrf.py > CsrfViewMiddleware in which it is very clear that DJango does not scan for csrfmiddlewaretoken in request body if the request is of DELETE type:
# Check non-cookie token for match.
request_csrf_token = ""
if request.method == "POST":
try:
request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
except OSError:
# Handle a broken connection before we've completed reading
# the POST data. process_view shouldn't raise any
# exceptions, so we'll ignore and serve the user a 403
# (assuming they're still listening, which they probably
# aren't because of the error).
pass
if request_csrf_token == "":
# Fall back to X-CSRFToken, to make things easier for AJAX,
# and possible for PUT/DELETE.
request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')