I am adding a custom route handler to a Playwright page and I am trying to inspect the request passed into the handler. For context here is a following code snippet:
def handler(route: Route, request: Request):
# Do things with `request`
...
await page.route('**/*', handler=handler)
For POST/PUT requests with a Content-Type of application/json, I have been able to successfully inspect the payload by using request.post_data_buffer. However, when the Content-Type is multipart/form-data, I have not been able locate where I can get the form data. All of the post_data, post_data_buffer, and post_data_json properties have a value of None, and I couldn't see anything else in the documentation which could contain the form_data.
The issue had nothing to do with really any details in my original post. The issue was I was using Chromium, and it is a known bug that post_data does not contain file/blob data.
Related
I am trying to update an already saved form on a system using HTTP requests. Due to the server configuration for the third party app we use, updating by POST requires sending a fully filled out payload every single time.
I want to get round this by recovering the form data already present on the server and converting it into a dictionary. Then changing any values I need and reposting to make changes sever side.
The application we use sends a POST request when the save button is clicked for a particular form.
Here I send a post request with no payload.
[This simulates pressing the save button and is also the point where dev tools shows me a the payload I want to capture]
post_test = self.session.post(url_to_retrieve_from)
I thought that now I should be able to print the output, which should resemble what Google Dev tools Form data captures.
print(post_test.text)
This just gives me html found on the webpage.
If Dev Tools can get this from the server then I should also be able to?
Example of Data I am trying to get via requests:
Form Data
If Dev Tools can get this from the server then I should also be able to?
Yes, of course. In requests you pass form data in data keyword:
import requests
url = 'http://www.example.com'
data = {
'name': 'value',
}
response = requests.post(url, data=data)
You can get the data you sent with a request from the response in this way:
import requests
response = requests.post('http://your_url', data=data) # send request
body = response.request.body
parsed_data = dict(data.split('=') for data in body.split('&')) # parse request body
Here you can find more information about data argument
In the documentation, in the class requests.Response we can find the attribute:
request = None
The PreparedRequest object to which this is a response.
In requests.PreparedRequest class we can read:
body = None
request body to send to the server.
I am using Python flask. I have a POST request with some payload coming on say:
abc.com/hello/hello1
I want to redirect this (302) to:
xyz.com/hello/hello1
only changing the domain name while keeping the remaining part as it is and also the payload. Is there a simple way to do this?
As per RFC, redirect requests (all 3xx) cannot contain request data or headers. You will miss the payload, supplied via POST in original request.
There are two possible workaround I could think of right away:
Give the client new URL, and implement further logic on client side;
Create a proxy handler on backend, which will do a request by itself and give the answer back as it's own.
EDIT: As per Andrejs Cainikovs's comment below, this would not work for a POST with payload.
In your endpoint, get the url that was used using request.url (see request API here for more options). Then you can rewrite it and make a redirect.
newUrl = "xyz.com/" + route
return redirect(newUrl, code=302)
I decided to try to make an automated login script for Minecraft. However, the new authentication API is stumping me. I can't find any mentions of the new functionality of the API on here. This is my code as it stands:
import requests
import json
data = json.dumps({"agent":{"name":"Minecraft","version":1},"username":"abcdef","password":"abcdef","clientToken":""})
headers = {'Content-Type': 'application/json'}
r = requests.post('https://authserver.mojang.com', data=data, headers=headers)
print (r.text)
Unfortunately, this returns:
{"error":"Method Not Allowed","errorMessage":"The method specified in the request is not allowed for the resource identified by the request URI"}
According to this resource on request format, this error means that I didn't correctly send a post request. However, I clearly declared requests.post(), so my first question is how am I incorrect, and what is the correct way to go about this?
My second question is, since I'm relatively new to Python and JSON, how would I replace the username and password fields with my own data, inside a variable?
You haven't specified an endpoint in your POST request, for example:
https://authserver.mojang.com/authenticate
The root of the website probably does not accept POST requests
http://wiki.vg/Authentication#Authenticate
I've got a Backbone application that doesn't redirect after a save. I don't know if this is something to do with Backbone or the server side code.
On the server:
url = request.route_url('test')
return HTTPFound(location=url)
I can see that location is correctly set to /test in the response headers. And following that there is a request with 200 OK to /test yet the page is not redirected.
Because you are saving by using an AJAX request (Backbone save documentation here: http://backbonejs.org/#Model-save) the client will not be redirected by the server response. This is not just because of Backbone, this is the nature of AJAX requests. If you want to redirect after a successful save you need to do that manually by setting a callback in the success option of the save. The success callback will given three arguments, model, response, and options (in that order), so you can use the response from the server to redirect.
In your server, you should respond to a successful save with the saved model rendered as a JSON object. What I did to then redirect the page was I added the target location to the location attribute of the response header. You can get the xhr attribute from the options object in the success callback, and call getResponseHeader('location') on it to get the location and then direct the window there:
model.save({}, {
success: function(model, response, options){
window.location = options.xhr.getResponseHeader('location');
})
});
I'm not too familiar with Pyramid, so if someone wants to edit this answer with the best way to return a JSON object and modify the response location header in the server please do. According to these docs and these docs, it should look something like this:
from pyramid.view import view_config
class MyObject(object):
def __init__(self, x):
self.x = x
def __json__(self, request):
return {'x':self.x}
#view_config(renderer='json')
def object(request):
request.response.location = "http://LocationToRedirectTo.com"
return MyObject(1)
# the JSON value returned by ``object`` will be:
# {"x": 1}
And of course you need to change all that to actually save your object instead of creating the sample MyObject object.
I wrote a Django view that responses ether a text/html or a application/json depending on request.is_ajax().
So far so good, but when I use my browsers history buttons, I end up getting a JSON response rather than the HTML.
I can't figure out the problem. It's true an jQuery ajax request is getting the same url after the page was loaded, but that shouldn't end up in the history, or should it?
Thanks, Joe
If you send different content depending on request.is_ajax(), you need to send Vary: X-Requested-With to the browser. That way, the browser will be able to distinguish the two kinds of response based on the value of the X-Requested-With header on the request. You can do that via:
from django.views.decorators.vary import vary_on_headers
#vary_on_headers('X-Requested-With')
def yourview(request, ...):
pass