Get full raw http request (complete with headers and body) - python

In a appengine project im trying to get the whole http request inside an webapp2.RequestHandler:
class ConnectedHandler(webapp2.RequestHandler):
def post(self):
logging.info("Someone connected: " + self.request.get('from'))
# How to get the raw http request from self.request?
Having looked through the documentation im begining to think its not possible
The result im looking for is something like this (What i would call a http request anyways):
POST /6473924464345088 HTTP/1.1
Accept: application/json
Accept-Encoding: gzip, deflate, compress
Content-Type: application/json; charset=utf-8
Host: localhost:10083
User-Agent: HTTPie/0.3.0
{
"u": "a"
}
Edit: Updated the example
Is there another cleaver way to access this data when using webapp2 ?

This should get you exactly that:
class MainPage(webapp2.RequestHandler):
def post(self):
self.response.write('Just received:\n\n' + str(self.request))

Related

Is there a way to form batched requests using python requests module ? I want to send multiple homogenous http API requests in a single POST request

Is there a way to form batched requests using python requests module ? I want to send multiple homogenous http API requests in a single POST request. I am trying to use the GCP documentation https://cloud.google.com/dns/docs/reference/batch?hl=en_US&_ga=2.138235123.-2126794010.1660759555 to create multiple DNS records in a single POST request. Can anyone help with a simple example of how this could be achieved using python requests module ?
This is how the sample POST request will look like:
POST /batch/farm/v1 HTTP/1.1
Authorization: Bearer your_auth_token
Host: www.googleapis.com
Content-Type: multipart/mixed; boundary=batch_foobarbaz
Content-Length: total_content_length
--batch_foobarbaz
Content-Type: application/http
Content-ID: <item1:12930812#barnyard.example.com>
GET /farm/v1/animals/pony
--batch_foobarbaz
Content-Type: application/http
Content-ID: <item2:12930812#barnyard.example.com>
PUT /farm/v1/animals/sheep
Content-Type: application/json
Content-Length: part_content_length
If-Match: "etag/sheep"
{
"animalName": "sheep",
"animalAge": "5"
"peltColor": "green",
}
--batch_foobarbaz
Content-Type: application/http
Content-ID: <item3:12930812#barnyard.example.com>
GET /farm/v1/animals
If-None-Match: "etag/animals"
--batch_foobarbaz--
Basically; the main intention here is to not overload the remote API with multiple http requests causing the rate limit throttling but instead use batched http requests so that the remote API gets only a single batched request embedded with multiple requests in the form of parts.
No. HTTP doesn't work that way. You can send multiple requests simultaneously using threads, but you can't send multiple POSTs through a single request.
According to the doc, the individual batch HTTP requests are supposed to go in the body of the request. You can try building the requests up manually. Like so:
import requests
body = """
--batch_foobarbaz
Content-Type: application/http
Content-ID: <item1:12930812#barnyard.example.com>
GET /farm/v1/animals/pony
--batch_foobarbaz
Content-Type: application/http
Content-ID: <item2:12930812#barnyard.example.com>
PUT /farm/v1/animals/sheep
Content-Type: application/json
Content-Length: part_content_length
If-Match: "etag/sheep"
{
"animalName": "sheep",
"animalAge": "5"
"peltColor": "green",
}
--batch_foobarbaz
Content-Type: application/http
Content-ID: <item3:12930812#barnyard.example.com>
GET /farm/v1/animals
If-None-Match: "etag/animals"
--batch_foobarbaz--
"""
response = requests.post(
"https://www.googleapis.com/batch/API/VERSION/batch/form/v1",
data=body,
headers={
'Authorization': 'Bearer your_auth_token',
'Host': 'www.googleapis.com',
'Content-Type': 'multipart/mixed; boundary=batch_foobarbaz'
}
)
Of course, you'd have to build the individual requests manually:
Content-Type: application/http
Content-ID: <item1:12930812#barnyard.example.com>
GET /farm/v1/animals/pony
Unless you can find a library that can construct HTTP requests according to the HTTP/1.1 RFC. I can't think of one off the top of my head.

CSRF validation works from Postman but not React/Axios

It's honestly a catastrophic blow to the ego I haven't already figured this out--spent 6 hours so far...
I have a React app running off a Django Rest Framework backend. For the password reset functionality I am using Django's builtin view (auth_views.PasswordResetView). I have a form in React that accepts an email and sends a post request to reset the users password. The way I send the data in postman is:
Url: http://192.168.0.85:8000/reset_password
Body: {'email': 'blabla#bla.com'}
Headers: {'X-CSRFToken': OGH9iUEtGPqntMYifQ5kiin2ufV9tK39tbp9Wmh6tLST0DXCXSkY8mOvyq5AjjnZ}
...and it works like a charm! Until I try to replicate the same exact call using axios in React:
axios.defaults.xsrfCookieName = 'csrftoken';
axios.defaults.xsrfHeaderName = 'X-CSRFToken';
axios.post('http://192.168.0.85:8000/reset_password',{'email': 'blabla#bla.com'},{headers}))
...this results in a 403 error with this message from the backend:
WARNING:django.security.csrf:Forbidden (CSRF cookie not set.): /reset_password
I've spent 6 hours googling and experimenting and can't figure out for the life of me why the Axios request would be any different than the Postman one. This problem is particularly infuriating because #csrf_exempt won't work on the django builtin views.
Here are the headers from a successful request in Postman:
X-CSRFToken: OGH9iUEtGPqntMYifQ5kiin2ufV9tK39tbp9Wmh6tLST0DXCXSkY8mOvyq5AjjnZ
User-Agent: PostmanRuntime/7.28.0
Accept: */*
Postman-Token: 91cbbfe7-b434-45fc-97ec-7d442c091070
Host: 192.168.0.85:8000
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 33
Cookie: csrftoken=gawXPEZQfN4qC4aKPhiIvK5qpjvkp4WCVFeXt6Ct2JwW9V94xjxmlOwTtuFLfDgs
...and from the failed request using Axios from React:
baseURL: "http://192.168.0.85:8000"
data: "{\"email\":\"blabla#bla.com\"}"
headers:
Accept: "*/*"
Authorization: ""
Content-Type: "application/json"
X-CSRFToken: "udd4yAGCJuTxw95kCdHYwwEQmGwu1bwxqEQjZhI56v1qWY143S4IPCrUSvk9xkV8"
__proto__: Object
maxBodyLength: -1
maxContentLength: -1
method: "post"
timeout: 0
transformRequest: [ƒ]
transformResponse: [ƒ]
url: "/reset_password"
validateStatus: ƒ validateStatus(status)
xsrfCookieName: "csrftoken"
xsrfHeaderName: "X-CSRFToken"
__proto__: Object
isAxiosError: true
Does this answer your question, https://stackoverflow.com/a/66550363/7838574 ?
With emphasis on the settings.py portion. That is what tripped me up about a week ago.
Honestly great job keeping at this and asking for help! Programming can be insanely frustrating and once the hurdle is behind you very rewarding!

Python - sending http requests as strings

How can I send HTTP requests as string with python? something like this:
r = """GET /hello.htm HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)
Host: www.stackoverflow.com
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive"""
answer = send(r)
print answer # gives me the response as string
Assuming python 3, it is recommended that you use urllib.request.
But since you specifically ask for providing the HTTP message as a string,
I assume you want to do low level stuff, so you can also use http.client:
import http.client
connection = http.client.HTTPConnection('www.python.org')
connection.request('GET', '/')
response = connection.getresponse()
print(response.status)
print(response.msg)
answer = response.read()
print(answer)

Receiving JSON from AngularJS in Flask

I have an AngularJS app, which is sending HTTP PUT data to flask; I can see that the data arrives at the server correctly... however, for some reason, my flask method can't read it when Angular makes an HTTP PUT to the server...
Flask code:
#app.route('/api/thing/hostform', methods=['GET'])
#login_required
def get_blank_host_row():
retval = [host_row(host_name="RANDOM_HOST")]
return Response(dumps(retval), mimetype='application/json')
#app.route('/api/thing/hostform', methods=['PUT'])
#login_required
def append_blank_host_row():
retval = request.form.get('hosts', "!! ERROR !!")
print "PUT RESULT", retval
retval.append(host_row())
return Response(dumps(retval), mimetype='application/json')
"formsubmit_add2" correctly GETs from /api/thing/hostform; however, for some reason request.form.get('hosts', "!! ERROR !!") always errors out with an HTTP 500 error as you can see below...
10.93.10.120 - - [11/Apr/2014 13:15:22] "GET /formsubmit_add2 HTTP/1.1" 200 -
10.93.10.120 - - [11/Apr/2014 13:15:22] "GET /api/thing/hostform HTTP/1.1" 200 -
PUT RESULT !! ERROR !!
10.93.10.120 - - [11/Apr/2014 13:15:25] "PUT /api/thing/hostform HTTP/1.1" 500 -
For anyone who is curious, request.json is None when I get the HTTP PUT...
Question
How can I correctly receive what AngularJS is sending to flask?
Wireshark dump of the HTTP PUT:
This is a wireshark dump of the HTTP PUT from AngularJS...
Hypertext Transfer Protocol
PUT /api/thing/hostform HTTP/1.1\r\n
[Expert Info (Chat/Sequence): PUT /api/thing/hostform HTTP/1.1\r\n]
[Message: PUT /api/thing/hostform HTTP/1.1\r\n]
[Severity level: Chat]
[Group: Sequence]
Request Method: PUT
Request URI: /api/thing/hostform
Request Version: HTTP/1.1
Host: tsunami:5000\r\n
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:28.0) Gecko/20100101 Firefox/28.0\r\n
Accept: application/json, text/plain, */*\r\n
Accept-Language: en-US,en;q=0.5\r\n
Accept-Encoding: gzip, deflate\r\n
Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n
Referer: http://server_name:5000/formsubmit_add2\r\n
Content-Length: 164\r\n
[Content length: 164]
Connection: keep-alive\r\n
\r\n
[Full request URI: http://server_name:5000/api/thing/hostform]
Line-based text data: application/x-www-form-urlencoded
{"hosts":[{"real_ip_addr":"","switch_port":"","host_nic_role":"Console",
"host_name":"RANDOM_HOST","host_nic_name":"","switch_name":"",
"altn_ip_addr":"192.0.2.42"}]}
AngularJS $http PUT:
$scope.add_row = function (data) {
// build an ajax request with $scope.data
var send = $http({
method : "PUT",
url : "/api/thing/hostform",
headers : {"Content-Type":
"application/x-www-form-urlencoded; charset=UTF-8"},
data: {"hosts": data},
});
send.success(
// something irrelevant here
);
You are using the wrong mimetype for JSON. Rather than application/x-www-form-urlencoded, it should be application/json.
From the Flask Request class documentation:
json
If the mimetype is application/json this will contain the parsed JSON data. Otherwise this will be None.
The get_json() method should be used instead.
I think your problem appears because request.form doesn't contain hosts key (contains something else), because your mimetype is not json (application/json).
For a more precise answer please write what comes in request.form?

How to send/receive URL parameters in a HTTP POST correctly?

I am using cakephp 2.4.5. I want to send a HTTP POST with URL parameters. I am using python 2.7 request module to send the HTTP POST. Please assume the payload is structured correctly as I have tested that part.
URL_post = http://127.0.0.1/webroot/TestFunc?identity_number=S111A/post
r = requests.post(URL_post, payload)
On the cakephp side, the controller looks something like this;
public function TestFunc($id=null)
{
$identity_number = $this->request->query['identity_number'];
$this->request->data['Model']['associated_id']=$identity_number;
$this->Model->saveAll($this->request->data, array('deep' => true));
}
I have tested that the query is not received correctly. However, if I am not using HTTP POST and just throwing in a normal URL, the query can be received correctly.
What have I done wrong?
The query part of the url is sent correctly:
import requests
requests.post('http://localhost/webroot/TestFunc?identity_number=S111A/post',
{'Model': 'data'})
The Request
POST /webroot/TestFunc?identity_number=S111A/post HTTP/1.1
Host: localhost
User-Agent: python-requests/2.2.1 CPython/3.4 Linux/3.2
Accept: */*
Accept-Encoding: gzip, deflate, compress
Content-Type: application/x-www-form-urlencoded
Content-Length: 10
Model=data
You could also make the requests using params:
requests.post('http://localhost/webroot/TestFunc',
data={'Model': 'data'},
params={'identity_number': 'S111A/post'})
The only difference is that S111A/post is sent as S111A%2Fpost (the same url in the end).
Look at http://docs.python-requests.org/en/latest/user/quickstart/#passing-parameters-in-urls.
payload = {"identity_number": "S111A/post"}
URL_post = "http://127.0.0.1/webroot/TestFunc"
req = requests.post(URL_post, params=payload)
print(req.status_code)

Categories

Resources