How to send data from localhost to server using Python requests? - python

I am trying to send data from localhost to an API in remote server using Python Requests & Django through an API: /api/send-data/
Path for /api/send-data/ in urls.py is path('send-data/',view_send_data.send_data,name='send_data')
This is my view_send_data.py in my localhost:
#api_view(('POST',))
#renderer_classes((TemplateHTMLRenderer, JSONRenderer))
def send_data():
# defining the API-endpoint
API_ENDPOINT = "http://68.183.89.234/api/screen/"
# data to be sent to API
data = {'data':1234}
# sending post request and saving response as response object
r = requests.post(url = API_ENDPOINT, data = data)
print(r.json())
return Response({"success": True}, status=status.HTTP_200_OK)
Path for api at http://68.183.89.234/api/screen/ in urls.py is path('screen/',views_fr.screen_display,name='screen')
This is my views_fr.py in my remote server:
#api_view(['POST'])
def screen_display(request):
if request.method == 'POST':
return Response({"success": True,
"response": request.data}, status=status.HTTP_200_OK)
When I call "http://127.0.0.1:8000/api/send-data/" in my browser, I am getting 405 Method Not Allowed
Is this the correct way to do it or am I missing something? Thank you.

The error you are getting is because the remote server API only accepts POST method, but you can't make a POST request using the browser url call. Test the API using postman or curl so you can set the correct method for request.

Related

CSRF token not set in Django with Python Request

I'm trying to send a POST request to a Django view from an ordinary Python script using Python-Request. The django view is not #login_required, so the only thing i need to send, other than my JSON data, is a CSRF token, here is what i tried:
token = session.get('http://127.0.0.1:8000/myview/view')
data = json.dumps({'test': 'value'})
session.post('http://127.0.0.1:8000/myview/myview',
data={
'csrfmiddlewaretoken': token,
'data': data})
The django view should just receive the Request and print it to my console:
def myview(request):
if request.method == 'POST':
data = request.POST.get('data')
print(json.loads(data))
print('received.')
response = HttpResponse(get_token(request))
return response
The problem with my current code is that my console will throw a log: WARNING - Forbidden (CSRF token missing or incorrect.). I cannot use #csrf_exempt, since i need this to be as safe as possible. Any advice? Thanks in advance!
Why might a user encounter a CSRF validation failure after logging in?
For security reasons, CSRF tokens are rotated each time a user logs in. Any page
with a form generated before a login will have an old, invalid CSRF token and need to be reloaded. This might happen if a user uses the back button after a login or if they log in a different browser tab.
This also goes for cookies. After you log in, django will send a new csrf cookie to the client. This will be stored in client.cookies and replaces the old one. The django server does not keep any record of the old token, so that's why you get the "CSRF token missing or incorrect." response.
You can access the new token from request.cookies['csrftoken'] as before.
import requests
LOGIN_URL = 'http://127.0.0.1:8000/myview/view'
request = requests.session()
request.get(LOGIN_URL)
# Retrieve the CSRF token first
csrftoken = request.cookies['csrftoken']
r1 = request.post(LOGIN_URL, headers={'X-CSRFToken': csrftoken},
allow_redirects=False))
new_csrftoken = r1.cookies['csrftoken']
data = json.dumps({'test': 'value'})
payload = {'csrfmiddlewaretoken': new_csrftoken,'data':data }
In fact, you can just use the client cookie directly. This would have avoided this bug in the first place. Requests keeps track of cookies for you when you use requests.session().
try :
r2 = request.post('http://127.0.0.1:8000/myview/myview', data=payload, headers={'X-CSRFToken': r1.cookies['crsftoken']})
except :
print('error expected')

Django view doesn't receive Json data?

Using a simple Python script, i want to send a request, with Python-Requests, to a Django view. The Django view should receive the json data inside the request and should print it to my console; here is what i tried:
This is how i send the request:
url = 'http://127.0.0.1:8000/myview/view'
client = requests.session()
csrftoken = requests.get(url).cookies['csrftoken']
data = json.dumps({'data': 'test-value'})
header = {'X-CSRFToken': csrftoken}
cookies = {'csrftoken': csrftoken}
resp = requests.post(url, data=data, headers=header, cookies=cookies)
And this is how the Django view receives it:
def myview(request):
if request.method == 'POST':
data = request.POST.get('data')
print(data)
print('received.')
response = HttpResponse(get_token(request))
return response
The problem with my current code is that print(data) will throw the following output:
None
received.
[06/Jan/2020 21:23:57] "POST /myview/view HTTP/1.1" 200 64
So, instead of printing test-value, it prints nothing. I don't understand whether the error is in my Django view or in how i'm sending the request. Any advice is appreciated!
The problem is with your request, and entirely caused by this line:
data = json.dumps({'data': 'test-value'})
You simply want
data = {'data': 'test-value'}
The POST data should be sent as a simple dictionary, not a JSON string - see the documentation and example here.

Test GET and POST calls

I need to test POST and GET calls against an NGINX server.
I need to capture the error codes and verify the response. I was able to test the GET requests by hitting localhost:8080 (NGINX is running on docker exposing 8080), but I'm not sure how to test the POST calls.
Can we construct a dummy request and test POST call? NGINX runs with default page.
Below is one way to make a post request to an endpoint in python
import requests
API_ENDPOINT = "http://pastebin.com/api/api_post.php"
data = {param1:value1,
param2:value2}
#sending post request and saving response as response object
r = requests.post(url = API_ENDPOINT, data = data)
#extracting response text
pastebin_url = r.text
print("The pastebin URL is:%s"%pastebin_url)

Can't send http request using python, only sends to https

I have the request below:
#app.route('/solve', methods=['POST'])
def solve():
if request.method == "POST":
token = request.form.get('g-recaptcha-response', '')
print('Posted Token : ' + token)
Thread(target = tokenremoval, args = [token]).start()
return('Success')
I want to send this post request to http://127.0.0.1:5000/solve , but it seems like it is sending to https://127.0.0.1:5000/solve. When I make the post request it sends it to that link above and i get:
This site can’t provide a secure connection
127.0.0.1 sent an invalid response.
Try running Windows Network Diagnostics.
ERR_SSL_PROTOCOL_ERROR
Why can't i send the post request to the http link?

hosting an image with the flask and then processing the same using another view function in the same code

so I am hosting an image using flask and then I want to do a post request to an API using the url all in the same code:
#app.route('/host')
def host():
return send_from_directory("C:/images", "image1.png")
#app.route('/post')
def post():
response = requests.post(url, data={'input':'<url for host>', headers=headers)
return jsonify(response.json())
I believe as both these view functions are in the same python file, post() gets blocked.
Is there a workaround this problem ?
PS: if I host images on a different machine, it works, but that's not what I desire.
Thanks!
I think there are some problems with your code.
First, I don't believe there is an #app.post() decorator in Flask. My guess is that you were trying to specify that that route should be POSTed to by your users. The way to do that would be #app.route('/post', methods=['POST']).
Next, it seems like you want the /post endpoint to send a POST request to a user-specified(?) URL when the user sends an HTTP request to this endpoint. The way you would do that for a user-specified / user-POSTed URL is something like this (I haven't run this code to test it):
#app.route('/send_post_request', methods=['POST'])
def send_post_request():
user_posted_data = json.loads(request.data)
user_specified_url = user_posted_data['url']
dict_to_post= { 'input': url_for('hosts') }
headers = {} # Fill these in
response = requests.post(user_specified_url , json=dict_to_post, headers=headers)
return jsonify(response.json())
If the URL to send the POST request to is known by the server, you could have your user simply send a GET request:
#app.route('/send_post_request', methods=['GET'])
def send_post_request():
dict_to_post = { 'input': url_for('hosts') }
headers = {} # Fill these in
server_specified_url = '' # Fill this in
response = requests.post(server_specified_url, json=dict_to_post, headers=headers)
return jsonify(response.json())

Categories