Hello I am trying to test Token Authentication i have implemented with DRF using httpie as per the tutorial in this following link
The following command:
http GET 127.0.0.1:8000/api/projects/ 'Authorization: Token b453919a139448c5891eadeb14bf1080a2624b03'
yields the following error.
usage: http [--json] [--form] [--pretty {all,colors,format,none}]
[--style STYLE] [--print WHAT] [--headers] [--body] [--verbose]
[--all] [--history-print WHAT] [--stream] [--output FILE]
[--download] [--continue]
[--session SESSION_NAME_OR_PATH | --session-read-only SESSION_NAME_OR_PATH]
[--auth USER[:PASS]] [--auth-type {basic,digest}]
[--proxy PROTOCOL:PROXY_URL] [--follow]
[--max-redirects MAX_REDIRECTS] [--timeout SECONDS]
[--check-status] [--verify VERIFY]
[--ssl {ssl2.3,ssl3,tls1,tls1.1,tls1.2}] [--cert CERT]
[--cert-key CERT_KEY] [--ignore-stdin] [--help] [--version]
[--traceback] [--default-scheme DEFAULT_SCHEME] [--debug]
[METHOD] URL [REQUEST_ITEM [REQUEST_ITEM ...]]http: error: argument REQUEST_ITEM: "Token" is not a valid value
So i decided to differ from the tutorial and made my request like this
http GET 127.0.0.1:8000/api/projects/ 'Authorization:b453919a139448c5891eadeb14bf1080a2624b03'
The following message was returned
HTTP/1.0 401 Unauthorized
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Date: Thu, 03 Nov 2016 09:52:05 GMT
Server: WSGIServer/0.1 Python/2.7.10
Vary: Accept
WWW-Authenticate: Token
X-Frame-Options: SAMEORIGIN
{
"detail": "Authentication credentials were not provided."
}
Any assistance offered would be great. I am running on local machine at home.
The solution is simple as is as follows . Use double quotes in the place of single quotes contrary to what the DRF Documentation says
For curl use the command below
curl -H "Authorization: Token b453919a139448c5891eadeb14bf1080a2624b03" http://127.0.0.1:8000/api/projects/
For HTTPie use
http GET http://127.0.0.1:8000/api/projects/ "Authorization: Token b453919a139448c5891eadeb14bf1080a2624b03"
Note that Double quotes are used contrary to single quotes in the documentation.
Contrary to Paul Nyondo's experience, for me the issue is not single quotes / double quotes (both are fine when using bash as shell), but the space between Authorization: and Token.
This fails:
» http GET http://service:8000/api/v1/envs/ 'Authorization: Token 3ea4d8306c6702dcefabb4ea49cfb052f15af85c'
http: error: InvalidHeader: Invalid return character or leading space in header: Authorization
This works (with double quotes):
» http GET http://service:8000/api/v1/envs/ "Authorization:Token 3ea4d8306c6702dcefabb4ea49cfb052f15af85c"
HTTP/1.1 200 OK
Allow: GET, HEAD, OPTIONS
Content-Length: 90
Content-Type: application/json
And this also works (with single quotes):
» http GET http://svc.userv.dgvmetro:8000/api/v1/envs/ 'Authorization:Token 3ea4d8306c6702dcefabb4ea49cfb052f15af85c'
HTTP/1.1 200 OK
Allow: GET, HEAD, OPTIONS
Content-Length: 90
Content-Type: application/json
Related
Is there a way to force gunicorn to pass the handling of "HEAD" request method to a drf application?
Currently, I have a view which looks similar to the code below :-
#api_view(["POST", "GET", "DELETE", "PUT", "PATCH", "HEAD"])
#renderer_classes([ProxyRender])
def my_proxy_view(request, path=""):
return proxy_dispatch(
urljoin(settings.PROXY["ENDPOINT"], path),
request,
)
However, when sending a "HEAD" request to the endpoint it seems like gunicorn or Django is the one handling the response, not my view as invoking my view should yield a head result of the service behind.
$ curl -I "http://localhost:8000/proxy/some-endpoint"
HTTP/1.1 200 OK
Server: gunicorn
Date: Sat, 20 Aug 2022 15:29:57 GMT
Connection: close
Content-Type: application/json
Allow: HEAD, POST, PUT, DELETE, GET, PATCH, OPTIONS
X-Frame-Options: DENY
Content-Length: 106
Vary: Cookie
X-Content-Type-Options: nosniff
Referrer-Policy: same-origin
I am using anki-connect to communicate with Anki, a spaced repetition software.
In readme.md, it uses following command to get deck name.
curl localhost:8765 -X POST -d "{\"action\": \"deckNames\", \"version\": 5}"
It works right in my Windows system.
How can I use python instead of cURL?
I've tried this but get no luck.
import requests
r = requests.post("http://127.0.0.1:8765", data={'action': 'guiAddCards', 'version': 5})
print(r.text)
When creating request you should:
provide Content-Type header
provide data in format that matches Content-Type header
make sure application supports the format
Both curl and python examples you gave sends request with Content-Type: application/x-www-form-urlencoded, the default one. The difference is curl passes string and python passes an array.
Let's compare curl and requests and what is really posted:
Curl
$ curl localhost -X POST -d "{\"action\": \"deckNames\", \"version\": 5}"
Headers:
Host: localhost
User-Agent: curl/7.52.1
Accept: */*
Content-Length: 37
Content-Type: application/x-www-form-urlencoded
Posted data:
[
'{"action": "deckNames", "version": 5}'
]
Python
import requests
r = requests.post("http://127.0.0.1", data={'action': 'guiAddCards', 'version': 5})
print(r.text)
Headers:
Host: 127.0.0.1
Connection: keep-alive
Accept-Encoding: gzip, deflate
Accept: */*
User-Agent: python-requests/2.10.0
Content-Length: 28
Content-Type: application/x-www-form-urlencoded
Posted data:
[
'action' -> 'guiAddCards',
'version' -> '5',
]
As you can see, incorrect post data format breaks your app.
To be sure, that posted JSON data will be properly read by application you should make requests like that:
Curl
$ curl localhost:8765 -H 'Content-Type: application/json' -d '{"action": "deckNames", "version": 5}'
Python
import requests
r = requests.post("http://127.0.0.1:8765", json={'action': 'guiAddCards', 'version': 5})
print(r.text)
I've tried following after digging and this works.
Can anybody share the reason. Thanks.
import requests
import json
#r = requests.post("http://127.0.0.1:8765", data={'action': 'guiAddCards', 'version': 5})
r = requests.post('http://localhost:8765', data=json.dumps({'action': 'guiAddCards', 'version': 5}))
print(r.text)
This is a reply to user2444791's answer. I can't reply with a comment because I don't have the reputation to comment (I'm new, please forgive a breech of etiquette!)
Without the exact error message, it's hard to be sure, but...
Looking at the Anki Connect API, it expects its POST-ed data to be a single string which contains a JSON object, not a key/value dictionary equivalent to that JSON object.
Every request consists of a JSON-encoded object containing an action, a version, and a set of contextual params.
Their example code (in Javascript): xhr.send(JSON.stringify({action, version, params}));
It might be as simple as sending your data in the wrong format. In the first example, you are sending a dictionary with the key/vale pairs already parsed. In the second example, you're sending a string for them to parse instead.
I am trying to create simple API for my site. I created the route with flask:
#api.route('/api/rate&message_id=<message_id>&performer=<performer_login>', methods=['POST'])
def api_rate_msg(message_id, performer_login):
print("RATE API ", message_id, ' ', performer_id)
return 400
print(...) function don't execute...
I use flask-socketio to communicate between client and server.
I send json from client and process it with:
#socket.on('rate')
def handle_rate(data):
print(data)
payload = {'message_id':data['message_id'], 'performer':data['performer']}
r = requests.post('/api/rate', params=payload)
print (r.status_code)
Note, that data variable is sending from client and is correct(I've checked it).
print(r.status_code) don't exec too...
Where I'm wrong? Please, sorry for my bad english :(
This api function must increase rate of message, which stored in mongodb, if interesting.
Don't put &message_id=<message_id>&performer=<performer_login> in your route string. Instead, get these arguments from request.args.
Try it:
from flask import request
...
#api.route('/api/rate', methods=['POST'])
def api_rate_msg():
print(request.args)
return ''
I've tested it with httpie:
$ http -v POST :5000/api/rate message_id==123 performer_login==foo
POST /api/rate?message_id=123&performer_login=foo HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 0
Host: localhost:5000
User-Agent: HTTPie/0.9.8
HTTP/1.0 200 OK
Content-Length: 0
Content-Type: text/html; charset=utf-8
Date: Sun, 02 Apr 2017 13:54:40 GMT
Server: Werkzeug/0.11.11 Python/2.7.13
And from flask's log:
ImmutableMultiDict([('message_id', u'123'), ('performer_login', u'foo')])
127.0.0.1 - - [02/Apr/2017 22:54:40] "POST /api/rate?message_id=123&performer_login=foo HTTP/1.1" 200 -
Remove the below part from your api route
&message_id=<message_id>&performer=<performer_login
This is not required in POST request. It helps in GET requests. API call in request is not matching the route definition and therefore you have the current problem
I am trying to perform a simple action:
POST to a URL
Return HTTP 303 (SeeOther)
GET from new URL
From what I can tell, this is a pretty standard practice:
http://en.wikipedia.org/wiki/Post/Redirect/Get
Also, it would seem that SeeOther is designed to work this way:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.4
I'm using web.py as my server-side controller, but I suspect that it's not the issue. If I GET, SeeOther works flawlessly as expected. If I POST to the same URL, the browser fails to redirect or load anything at all.
Thinking it was a browser issue, I tried both IE9 and Google Chrome (v23 ish). Both have the same issue.
Thinking web.py might be serving the page incorrectly, or generating a bad URL, I used telnet to examine the headers. I found this:
HTTP GET (this works in the browser):
GET /Users/1 HTTP/1.1
HOST: domain.com
HTTP/1.1 303 See Other
Date: Mon, 24 Dec 2012 18:07:55 GMT
Server: Apache/2
Cache-control: no-cache
Location: http://domain.com/Users
Content-Length: 0
Content-Type: text/html
HTTP POST (this does not work in the browser):
POST /Users/1 HTTP/1.1
HOST: domain.com
HTTP/1.1 303 See Other
Date: Mon, 24 Dec 2012 18:12:35 GMT
Server: Apache/2
Cache-control: no-cache
Location: http://domain.com/Users
Content-Length: 0
Content-Type: text/html
Another thing that could be throwing a wrench in the works:
I'm using mod-rewrite so that the user-visible domain.com/Users/1 is actually domain.com/control.py/Users/1
There may be more information/troubleshooting that I have, but I'm drawing a blank right now.
The Question:
Why does this work with a GET request, but not a POST request? Am I missing a response header somewhere?
EDIT:
Using IE9 Developer Tools and Chrome's Inspector, it looks like the 303 isn't coming back to the browser after a POST. However, I can see the 303 come in when I do a GET request.
However, after looking more closely at Chrome's Inspector, I saw the ability to log every request (don't clear w/ each page call). This allowed me to see that for some reason, my POST request looks like it's failing. Again - GET works just fine.
It's entirely possible that this isn't your issue, but since you don't have your code posted I'll take a shot (just in case).
Since you're using web.py, do you have the POST method defined on your object?
i.e.
urls = (
'/page', 'page'
)
class page:
def POST(self):
# Do something
def GET(self):
# Do something else
I would like an automated way to test how my app handles email, with attachments.
Firstly I modified my app (on App Engine) to log the contents of the request body for a received message (as sent through appspotmail). I copied these contents into a file called test_mail.txt
I figured I could post this file to imitate the inbound mail tester, something like so.
curl --header "Content-Type:message/rfc822" -X POST -d #test_mail.txt http://localhost:8080/_ah/mail/test#example.com
Whenever I do this, the message isn't properly instantiated, and I get an exception when I refer to any of the standard attributes.
Am I missing something in how I am using curl?
I run into the same problem using a simpler email, as posted by _ah/admin/inboundmail
MIME-Version: 1.0
Date: Wed, 25 Apr 2012 15:50:06 +1000
From: test#example.com
To: test#example.com
Subject: Hello
Content-Type: multipart/alternative; boundary=cRtRRiD-6434410
--cRtRRiD-6434410
Content-Type: text/plain; charset=UTF-8
There
--cRtRRiD-6434410
Content-Type: text/html; charset=UTF-8
There
--cRtRRiD-6434410--
Try --data-binary instead of -d as the flag for the input file. When I tried with your flags, it looked like curl stripped the carriage returns out of the input file, which meant the MIME parser choked on the POST data.
Black,
I noticed your program is written in python? Why not use twisted to create a tiny smtp client?
Here are a few examples..
http://twistedmatrix.com/documents/current/mail/tutorial/smtpclient/smtpclient.html