I am not able to update a file using github-flask.
It gives me a 404 error (https://developer.github.com/v3/troubleshooting/#why-am-i-getting-a-404-error-on-a-repository-that-exists) but I have verified that my auth token is good and has repo scope. I verified so by
Anshu-MacBook-Pro:~ anshup$ curl -H "Authorization: token mytoken" https://api.github.com/users/anshprat -I
HTTP/1.1 200 OK
Server: GitHub.com
Date: Fri, 11 Jul 2014 07:21:34 GMT
Content-Type: application/json; charset=utf-8
Status: 200 OK
X-RateLimit-Limit: 5000
X-RateLimit-Remaining: 4991
X-RateLimit-Reset: 1405065424
Cache-Control: private, max-age=60, s-maxage=60
Last-Modified: Fri, 11 Jul 2014 06:25:54 GMT
ETag: "etag"
X-OAuth-Scopes: repo
My code is:
def git_push(file_path,file_path_s,commit_message,raw_file_data):
u_file_data = base64.b64encode(raw_file_data,salt())
#print u_file_data
params = {
'path':file_path_s
'message':commit_message,
'content':u_file_data,
'sha':file_sha #Its a global variable
}
#print raw_file_data,u_file_data,params
params_json = json.dumps(params)
return github.post(file_path,params_json) #params fails as well
The flask frame dumps shows:
resource 'repos/anshprat/git-test/contents/play1.txt'
status_code '404'
self <flask_github.GitHub object at 0x2733b90>
response <Response [404]>
kwargs {'headers': {'Content-Type': 'application/x-www-form-urlencoded'}, 'data': '"{\\"content\\": \\"dXNlcjE6cGFzc3dvcmQxCnVzZXIyOnBhc3N3b3JkMgp1c2VyMzpNQlpvRDJLOWJQQS9vCg==\\", \\"sha\\": \\"ce4979fccba7ef259910c355ca6e1993d7ea436c\\", \\"message\\": \\"modifying user user3\\"}"' }
method 'POST'
If I use params in the post, the double quotes are not escaped.
POST also fails for me on curl, so I think I am doing something very basic wrong out here?
curl -H "Authorization: token mytoken" --data '{"content": "dXNlcjE6cGFzc3dvcmQxCnVzZXIyOnBhc3N3b3JkMgp1c2VyMzpEQXR2VUNweUJrbjdFCg==", "message": "modifying user user3", "sha": "ce4979fccba7ef259910c355ca6e1993d7ea436c"}' https://api.github.com/repos/anshprat/git-test/contents/play1.txt
{
"message": "Not Found",
"documentation_url": "https://developer.github.com/v3"
}
github.get for the same file_path works.
The API is listed at
https://developer.github.com/v3/repos/contents/#update-a-file
My app should be doing a code commit and then deploy it to some other non github related work.
I had to change
def post(self, resource, data, **kwargs):
"""Shortcut for ``request('POST', resource)``.
Use this to make POST request since it will also encode ``data`` to
'application/x-www-form-urlencoded' format."""
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
to
def post(self, resource, data, **kwargs):
"""Shortcut for ``request('POST', resource)``.
Use this to make POST request since it will also encode ``data`` to
'application/x-www-form-urlencoded' format."""
headers = {}
headers['Content-type'] = 'application/json'
headers['X-HTTP-Method-Override'] = 'PUT'
for it work correctly.
Related
I need to automate connecting to logs analytics on Azure. Before I can do that, I need to get an access token.
With different docs and https://www.youtube.com/watch?v=ujzrq8Fg9Gc, I am trying to set that up.
TRY1
My first try was using SoapUI to send a POST request to:
https://login.microsoftonline.com/MY TENANT ID/oauth2/token
?grant_type=client_credentials
&client_id=MY CLIENT ID
&redirect_uri=MY URL
&resource=https%3A%2F%2Fwestus2.api.loganalytics.io
&client_secret=MY CLIENT SECRET
With header:
Content-Type: application/x-www-form-urlencoded
I always get this response:
HTTP/1.1 400 Bad Request
Cache-Control: no-cache, no-store
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
x-ms-request-id: SOMETHING
P3P: CP="DSP CUR OTPi IND OTRi ONL FIN"
Set-Cookie: fpc=SOMETHING; expires=Mon, 05-Aug-2019 13:14:50 GMT; path=/; secure; HttpOnly
Set-Cookie: x-ms-gateway-slice=prod; path=/; secure; HttpOnly
Set-Cookie: stsservicecookie=ests; path=/; secure; HttpOnly
Date: Sat, 06 Jul 2019 13:14:49 GMT
Content-Length: 437
{
"error":"invalid_request",
"error_description":"AADSTS900144: The request body must contain
the following parameter: 'grant_type'.\r\n
Trace ID: SOMETHING\r\n
Correlation ID: SOMETHING\r\n
Timestamp: 2019-07-06 13:14:50Z",
"error_codes":[900144],
"timestamp":"2019-07-06 13:14:50Z",
"trace_id":"SOMETHING",
"correlation_id":"SOMETHING"
}
TRY 2
I wrote it in Python using import requests, like so:
import os,sys
import requests
Azure_client_id = 'MY CLIENT ID'
Azure_redirect_uri = 'MY URL'
Azure_client_secret = 'CLIENT SECRET'
Azure_tenant_id = 'TENANT ID'
Azure_resource = 'https://westus2.api.loganalytics.io'
###############################################################################
token_url = 'https://login.microsoftonline.com/' + Azure_tenant_id + '/oauth2/token'
token_headers = {
'Content-type': 'application/x-www-form-urlencoded',
}
token_params = {
'grant_type': 'client_credentials',
'client_id': Azure_client_id,
'redirect_uri': Azure_redirect_uri,
'resource': Azure_resource,
'client_secret': Azure_client_secret,
}
token_response = requests.post(token_url, headers=token_headers, params=token_params)
# This is to see what was sent
print(token_response.url + "\n\n")
# get the response and print it
token_result = ''
for chunk in token_response.iter_content(chunk_size=128):
token_result = token_result + str(chunk)
print(token_result.replace("\\n","\n"))
The URL that was sent is this (formatted for readability):
https://login.microsoftonline.com/MY TENANT ID/oauth2/token
?grant_type=client_credentials
&client_id=MY CLIENT ID
&redirect_uri=https%3A%2F%2FMY URL
&resource=https%3A%2F%2Fwestus2.api.loganalytics.io
&client_secret=MY SECRET URL ENCODED
The response I get is this (reformatted for readability):
b'{"error":"invalid_request",
"error_description":"AADSTS900144: The request body must contain
the following parameter: \'grant_type'b"'.\\r\
Trace ID: SOMETHING\\r\
Correlation ID: SOMETHING\\r\
Timestamp: 2019-"b'07-06 13:49:59Z",
"error_codes":[900144],
"timestamp":"2019-07-06 13:49:59Z",
"trace_id":"SOMETHING",
"co'b'rrelation_id":"SOMETHING"}''
At least I get the same error (!). Since my requests clearly include a "grant_type" parameter, my guess is that there is either something wrong with the encoding (which is done by SoapUI and Python's requests), something wrong with my URL, or I am not using the proper IDs.
Is there a way in Azure to validate that my client secret is valid? Once created, it cannot be read anymore. And someone else created this key so I cannot assume what he gave me is ok.
Any comment, hints, pointing out blatant mistakes on my part are appreciated.
Change
token_response = requests.post(token_url, headers=token_headers, params=token_params)
to
token_response = requests.post(token_url, data=token_params)
You don't need to specify the Content-type header, it's inferred from your payload (dictionary, so x-www-form-urlencoded), also data is what you want (payload), not params (URL parameters).
Your request should look like this on the wire -
POST /TENANT_ID/oauth2/token HTTP/1.1
Host: localhost:9000
User-Agent: python-requests/2.22.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Content-Length: 151
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&client_id=MY+CLIENT+ID
&redirect_uri=MY+URL
&resource=https%3A%2F%2Fwestus2.api.loganalytics.io
&client_secret=CLIENT+SECRET
Everything is in the body where it should be for x-www-form-urlencoded.
More on x-www-form-urlencoded here -
https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST#Example
I am trying to post data to my server from my microcontroller. I need to send raw http data from my controller and this is what I am sending below:
POST /postpage HTTP/1.1
Host: https://example.com
Accept: */*
Content-Length: 18
Content-Type: application/json
{"cage":"abcdefg"}
My server requires JSON encoding and not form encoded request.
For the above request sent, I get an 400 error from the server, HTTP/1.1 400 Bad Request
However, when I try to reach the post to my server via a python script via my laptop, I am able to get a proper response.
import requests
url='https://example.com'
mycode = 'abcdefg'
def enter():
value = requests.post('url/postpage',
params={'cage': mycode})
print vars(value)
enter()
Can anyone please let me know where I could be going wrong in the raw http data I'm sending above ?
HTTP specifies the separator between headers as a single newline, and requires a double newline before the content:
POST /postpage HTTP/1.1
Host: https://example.com
Accept: */*
Content-Length: 18
Content-Type: application/json
{"cage":"abcdefg"}
If you don’t think you’ve got all of the request right, try seeing what was sent by Python:
response = ...
request = response.request # request is a PreparedRequest.
headers = request.headers
url = request.url
Read the docs for PreparedRequest for more information.
To pass a parameter, use this Python:
REQUEST = 'POST /postpage%s HTTP/1.1\r\nHost: example.com\r\nContent-Length: 0\r\nConnection: keep-alive\r\nAccept-Encoding: gzip, deflate\r\nAccept: */*\r\nUser-Agent: python-requests/2.4.3 CPython/2.7.9 Linux/4.4.11-v7+\r\n\r\n';
query = ''
for k, v in params.items():
query += '&' + k + '=' + v # URL-encode here if you want.
if len(query): query = '?' + query[1:]
return REQUEST % query
I'm using Observium to pull Nginx stats on localhost however it returns '405 Not Allowed':
# curl -I localhost/nginx_status
HTTP/1.1 405 Not Allowed
Server: nginx
Date: Wed, 19 Jun 2013 22:12:37 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 166
Connection: keep-alive
Keep-Alive: timeout=5
# curl -I -H "Host: example.com" localhost/nginx_status
HTTP/1.1 200 OK
Server: nginx
Date: Wed, 19 Jun 2013 22:12:43 GMT
Content-Type: text/plain
Connection: keep-alive
Keep-Alive: timeout=5
Could you please advise how to add Host header with 'urllib2.urlopen' in Python (Python 2.6.6
):
Current script:
#!/usr/bin/env python
import urllib2
import re
data = urllib2.urlopen('http://localhost/nginx_status').read()
params = {}
for line in data.split("\n"):
smallstat = re.match(r"\s?Reading:\s(.*)\sWriting:\s(.*)\sWaiting:\s(.*)$", line)
req = re.match(r"\s+(\d+)\s+(\d+)\s+(\d+)", line)
if smallstat:
params["Reading"] = smallstat.group(1)
params["Writing"] = smallstat.group(2)
params["Waiting"] = smallstat.group(3)
elif req:
params["Requests"] = req.group(3)
else:
pass
dataorder = [
"Active",
"Reading",
"Writing",
"Waiting",
"Requests"
]
print "<<<nginx>>>\n";
for param in dataorder:
if param == "Active":
Active = int(params["Reading"]) + int(params["Writing"]) + int(params["Waiting"])
print Active
else:
print params[param]
You might want to check out the urllib2 missing manual for more information, but basically you create a dictionary of your header labels and values and pass it to the urllib2.Request method. A (slightly) modified version of the code from the linked manual:
from urllib import urlencode
from urllib2 import Request urlopen
# Define values that we'll pass to our urllib and urllib2 methods
url = 'http://www.something.com/blah'
user_host = 'example.com'
values = {'name' : 'Engineero', # dict of keys and values for our POST data
'location' : 'Interwebs',
'language' : 'Python' }
headers = { 'Host' : user_host } # dict of keys and values for our header
# Set up our request, execute, and read
data = urlencode(values) # encode for sending URL request
req = Request(url, data, headers) # make POST request to url with data and headers
response = urlopen(req) # get the response from the server
the_page = response.read() # read the response from the server
# Do other stuff with the response
I'm trying to use pysimplesoap to communicate with the Websitepanel SOAP-API.
The WebsitePanel API Introduction says:
For interacting with WebsitePanel API you should use Basic Authentication. WebsitePanel recognizes “Authorization” header with the user credentials provided in the following format: username:password
My first try was the following:
client = SoapClient(wsdl=endpoint_url, trace=True)
client['Authorization'] = "%s:%s" % (username, password)
which returns a 401 "Unauthorized".
Second try was:
client = SoapClient(wsdl=endpoint_url, trace=True)
client['wsse:Security'] = {
'wsse:UsernameToken': {
'wsse:Username': username,
'wsse:Password': password,
}
}
which works as expected but returns the following:
status: 500
content-length: 924
x-aspnet-version: 4.0.30319
x-powered-by: ASP.NET
server: Microsoft-IIS/7.5
cache-control: private
date: Tue, 12 Feb 2013 14:23:56 GMT
content-type: text/xml; charset=utf-8
And
pysimplesoap.client.SoapFault: q0:Security: SOAP response should be signed.
Why does client['Authorization'] not work and what is meant by the Response should be signed error message?
Thanks in advance.
I figured it out: To authenticate correctly with pysimplesoap you have to call
client = SoapClient(wsdl=u, trace=True,
http_headers={'Authorization': 'Basic %s' % encoded})
with encodedbeeing the base64-encoded string username:password
I'm having problems with a Flask view that should return a response with content-type "application/json" in response to a POST request.
Specifically, if I do:
curl -v -d 'foo=bar' http://example.org/jsonpost
to this view:
#app.route('/jsonpost', methods=['GET', 'POST'])
def json_post():
resp = make_response('{"test": "ok"}')
resp.headers['Content-Type'] = "application/json"
return resp
I get some sort of connection reset:
* About to connect() to example.org port 80 (#0)
* Trying xxx.xxx.xxx.xxx... connected
* Connected to example.org (xxx.xxx.xxx.xxx) port 80 (#0)
> POST /routing/jsonpost HTTP/1.1
> User-Agent: curl/7.19.7 (i486-pc-linux-gnu) libcurl/7.19.7 OpenSSL/0.9.8k zlib/1.2.3.3 libidn/1.15
> Host: example.org
> Accept: */*
> Content-Length: 7
> Content-Type: application/x-www-form-urlencoded
>
< HTTP/1.1 200 OK
< Server: nginx/1.2.4
< Date: Thu, 27 Dec 2012 14:07:59 GMT
< Content-Type: application/json
< Content-Length: 14
< Connection: keep-alive
< Set-Cookie: session="..."; Path=/; HttpOnly
< Cache-Control: public
<
* transfer closed with 14 bytes remaining to read
* Closing connection #0
curl: (18) transfer closed with 14 bytes remaining to read
If instead I do:
curl -d 'foo=bar' http://example.org/htmlpost
to:
#app.route('/htmlpost', methods=['GET', 'POST'])
def html_post():
resp = make_response('{"test": "ok"}')
resp.headers['Content-Type'] = "text/html"
return resp
I get the expected the full response (200-ok)
{"test": "ok"}
By the way, if I send a GET request to the same JSON route:
curl http://example.org/jsonpost
I also get the expected response..
Any ideas?
Thanks to Audrius's comments I tracked a possible source of the problem to the interaction between uWSGI and nginx: apparently, if you receive POST data in a request you must read it before returning a response.
This, for example, fixes my issue.
#app.route('/jsonpost', methods=['GET', 'POST'])
def json_post():
if request.method == 'POST':
dummy = request.form
resp = make_response('{"test": "ok"}')
resp.headers['Content-Type'] = "application/json"
return resp
A different solution involves passing --post-buffering 1 to uWSGI as described by uWSGI's author Roberto De Ioris.
I still don't understand why the problem does not present itself with Content-Type set to "text/html"