I receive a CannotSendRequest in my oauth library (Django socialauth) when I try to connect to Twitter.
Traceback:
File "/Library/Python/2.6/site-packages/django/core/handlers/base.py" in get_response
100. response = callback(request, *callback_args, **callback_kwargs)
File "/Users/me/webfaction/project/socialauth/views.py" in twitter_login
94. request_token = twitter.fetch_request_token(callback=request.build_absolute_uri(reverse('socialauth_twitter_login_done')))
File "/Users/me/webfaction/project/socialauth/lib/oauthtwitter2.py" in fetch_request_token
50. return oauth.OAuthToken.from_string(oauth_response(oauth_request))
File "/Users/me/webfaction/project/socialauth/lib/oauthtwitter2.py" in oauth_response
33. connection().request(req.http_method, req.to_url())
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/httplib.py" in request
914. self._send_request(method, url, body, headers)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/httplib.py" in _send_request
931. self.putrequest(method, url, **skips)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/httplib.py" in putrequest
818. raise CannotSendRequest()
Exception Type: CannotSendRequest at /accounts/twitter_login/
Exception Value:
Here's where I'm creating the HTTP connection
def connection():
try:
return connection._connection
except AttributeError:
connection._connection = httplib.HTTPSConnection(TWITTER_URL)
return connection._connection
def oauth_response(req):
connection().request(req.http_method, req.to_url())
return connection().getresponse().read()
I've searched SO and found these links, but I'm still not sure how to implement the solution. I've tried and failed. Any help would be appreciated.
httplib CannotSendRequest error in WSGI
When I use httplib for my OAUTH in Python, I always get "CannotSendRequest" and then "
The post you linked to says this error happens when you reuse connections that have thrown an exception and didn't make it to the getresponse() stage.
Indeed, connection.request("GET", "/") x 2 throws the error.
The solution suggested is to re-create the connection every time. Is that what you want to do? Note I have no opinions on this matter, you just asked how to implement what's on those posts.
If so, get rid of your connection() function and always do
connection = httplib.HTTPSConnection(TWITTER_URL)
connection.request(req.http_method, req.to_url())
response = connection.getresponse().read()
connection.close()
return response
Related
I'm running a webserver based on the Bottle framework. This framework exposes an endpoint where you can upload a file. Sometimes, if the disk is full, the webserver is supposed to return a code 429 without reading the file. For some reason, when I'm uploading a file, if the server tries to return a 429 status code the following exception is raised:
File "../hooks.py", line 325, in post_video_content
response = requests.post(url, data=fh)
File "/usr/local/lib/python2.7/site-packages/requests/api.py", line 110, in post
return request('post', url, data=data, json=json, **kwargs)
File "/usr/local/lib/python2.7/site-packages/requests/api.py", line 56, in request
return session.request(method=method, url=url, **kwargs)
File "/usr/local/lib/python2.7/site-packages/requests/sessions.py", line 488, in request
resp = self.send(prep, **send_kwargs)
File "/usr/local/lib/python2.7/site-packages/requests/sessions.py", line 609, in send
r = adapter.send(request, **kwargs)
File "/usr/local/lib/python2.7/site-packages/requests/adapters.py", line 473, in send
raise ConnectionError(err, request=request)
ConnectionError: ('Connection aborted.', error(32, 'Broken pipe'))
But if try the exact same post but instead of posting a file I simply post some small amount of data, I actually get a response object back from the request and I can inspect the status code.
To reproduce:
webserver.py
from bottle import Bottle, route, run, request, response, get, post, put, abort
#post('/content')
#authenticate
def content():
response.status = 429
return "failed to write incoming movie to temp file (space might be full temporarily)"
run(host="127.0.0.1", port=8080, debug=True)
send_request.py
import requests
# this works and prints the status code
ret = requests.post("127.0.0.1:8080/content", data="sdfsdfsdfsdf")
print ret.status_code
# this part will throw an exception
try:
with open("~/some_large_video_file.mp4", 'rb') as fh:
ret = requests.post('127.0.0.1:8080/content', data=fh)
except:
print traceback.format_exc()
EDIT - I've found out that it depends on the amount of data. If you try and post something like 10KB of data we get the 429 return code. I'm trying to figure out what the limit is that causes it to start raising an exception.
EDIT2 - So it looks like the magic filesize is somewhere between 117K and 131K. If I try the former it works as intended, I get the response from the request and can access the status code. If I try the former I get the exception raised.
My questions are:
Why does this happen? Is it a bug in bottle? A bug in requests? Why would the size/type of data I'm posting change the response?
Is there any way to get around this? I'm trying to associate a ConnectionError exception with the server being down, and a 429 response code meaning the disk is full. If I'm getting the same exception for both I can't tell the difference between the situations which blocks me from implementing a back-off to wait for disk space to open up
So I cross-posted this to the requests github issue page, and it looks like the issue is in the httplib module that requests is built on top of, so this is a no-fix for now.
see: https://github.com/kennethreitz/requests/issues/4062
I am unable to PUT Nest data like ambient_temperature_f to https://developer-api.nest.com or the redirected Firebase URL. I suspect there is something specific to the Nest that will need to be tweaked in the Firebase module I am using (https://ozgur.github.io/python-firebase/).
From firebase.py:
#http_connection(60)
def make_put_request(url, data, params, headers, connection):
"""
Helper function that makes an HTTP PUT request to the given firebase
endpoint. Timeout is 60 seconds.
`url`: The full URL of the firebase endpoint (DSN appended.)
`data`: JSON serializable dict that will be stored in the remote storage.
`params`: Python dict that is appended to the URL like a querystring.
`headers`: Python dict. HTTP request headers.
`connection`: Predefined HTTP connection instance. If not given, it
is supplied by the `decorators.http_connection` function.
The returning value is a Python dict deserialized by the JSON decoder. However,
if the status code is not 2x or 403, an requests.HTTPError is raised.
connection = connection_pool.get_available_connection()
response = make_put_request('http://firebase.localhost/users',
'{"1": "Ozgur Vatansever"}',
{'X_FIREBASE_SOMETHING': 'Hi'}, connection)
response => {'1': 'Ozgur Vatansever'} or {'error': 'Permission denied.'}
"""
timeout = getattr(connection, 'timeout')
response = connection.put(url, data=data, params=params, headers=headers, timeout=timeout)
print('[make_put_request]: [%s][%s][%s][%s]\n' %(url, data, params, headers))
if response.ok or response.status_code == 403:
return response.json() if response.content else None
else:
response.raise_for_status()
Prints out:
[make_put_request]: [https://developer-api.nest.com/devices/thermostats/DEVICE_ID/ambient_temperature_f.json?auth=VALID_AUTH_TOKEN][71][{}][{}]
Returns error:
Traceback (most recent call last):
File "C:\py\nest_auth.py", line 90, in <module>
put_result = firebase.put(data_url, field_name, 71)
File "C:\Python34\lib\site-packages\firebase\decorators.py", line 19, in wrapped
return f(*args, **kwargs)
File "C:\Python34\lib\site-packages\firebase\firebase.py", line 312, in put
connection=connection)
File "C:\Python34\lib\site-packages\firebase\decorators.py", line 19, in wrapped
return f(*args, **kwargs)
File "C:\Python34\lib\site-packages\firebase\firebase.py", line 77, in make_put_request
response.raise_for_status()
File "C:\Python34\lib\site-packages\requests\models.py", line 808, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 400 Client Error: Bad Request
This worked when using a firebaseio.com target but isn't working for Nest:
put_result = firebase.put('/devices/thermostats/DEVICE_ID/', 'ambient_temperature', 71)
According to the documentation ambient_temperature_f is a read only field that represent's the reported ambient temperature from the thermostat. It wouldn't make sense to override that since it is a sensor reading.
I think you want to write to target_temperature_f, which is the temperature the thermostat should heat or cool to.
I'm using python-social-auth to implement twitter login locally but I get the 401 client error. My django version is 1.6.
Traceback:
File "/Library/Python/2.7/site-packages/django/core/handlers/base.py" in get_response
112. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Library/Python/2.7/site-packages/social/apps/django_app/utils.py" in wrapper
45. return func(request, backend, *args, **kwargs)
File "/Library/Python/2.7/site-packages/social/apps/django_app/views.py" in auth
12. return do_auth(request.social_strategy, redirect_name=REDIRECT_FIELD_NAME)
File "/Library/Python/2.7/site-packages/social/actions.py" in do_auth
25. return strategy.start()
File "/Library/Python/2.7/site-packages/social/strategies/base.py" in start
66. return self.redirect(self.backend.auth_url())
File "/Library/Python/2.7/site-packages/social/backends/oauth.py" in auth_url
99. token = self.set_unauthorized_token()
File "/Library/Python/2.7/site-packages/social/backends/oauth.py" in set_unauthorized_token
158. token = self.unauthorized_token()
File "/Library/Python/2.7/site-packages/social/backends/oauth.py" in unauthorized_token
177. method=self.REQUEST_TOKEN_METHOD)
File "/Library/Python/2.7/site-packages/social/backends/base.py" in request
205. response.raise_for_status()
File "/Library/Python/2.7/site-packages/requests/models.py" in raise_for_status
808. raise HTTPError(http_error_msg, response=self)
Exception Type: HTTPError at /login/twitter/
Exception Value: 401 Client Error: Authorization Required
In documentation it suggests to install ntp.I have no clue how to install ntp.
It turns out I left the callback url field blank in the twitter app console. Although, it's not required, but putting http://127.0.0.1:8000/complete/twitter/ (Note the slash at the end) did the job.
Note also that if you leave the final '/' off the end of the call back URL, you will get this error. It should read
http://127.0.0.1:8000/complete/twitter/
Traceback:
File "/usr/local/lib/python2.6/dist-packages/django/core/handlers/base.py" in get_response
92. response = callback(request, *callback_args, **callback_kwargs)
File "/home/ea/ea/hell/life/views.py" in linkedin_auth
274. token = oauth_linkedin.get_unauthorised_request_token()
File "/home/ea/ea/hell/life/oauth_linkedin.py" in get_unauthorised_request_token
52. resp = fetch_response(oauth_request, connection)
File "/home/ea/ea/hell/life/oauth_linkedin.py" in fetch_response
42. connection.request(oauth_request.http_method,url)
File "/usr/lib/python2.6/httplib.py" in request
874. self._send_request(method, url, body, headers)
File "/usr/lib/python2.6/httplib.py" in _send_request
891. self.putrequest(method, url, **skips)
File "/usr/lib/python2.6/httplib.py" in putrequest
778. raise CannotSendRequest()
Exception Type: CannotSendRequest at /linkedin/auth
Exception Value:
And then, sometimes I get: BadStatusLine error instead of this.
It's pretty random. I don't know when or why they happen. It happens more frequently when I'm running the Django development server (and less frequently when in APACHE2...but it still happens at random times). When this error happens, I have to restart my server.
Apparently (from here) this happens if you try to reuse an httplib.HTTP object which had not been fully used. Maybe a connection pool in the library you're using, and an exception getting thrown during the request processing? Suggestion is to create new connection objects every time.
I've used two different python oauth libraries with Django to authenticate with twitter. The setup is on apache with WSGI. When I restart the server everything works great for about 10 minutes and then the httplib seems to lock up (see the following error).
I'm running only 1 process and 1 thread of WSGI but that seems to make no difference.
I cannot figure out why it's locking up and giving this CannotSendRequest error. I've spent a lot of hours on this frustrating problem. Any hints/suggestions of what it could be would be greatly appreciated.
File "/usr/lib/python2.5/site-packages/django/core/handlers/base.py", line 92, in get_response
response = callback(request, *callback_args, **callback_kwargs)
File "mypath/auth/decorators.py", line 9, in decorated
return f(*args, **kwargs)
File "mypath/auth/views.py", line 30, in login
token = get_unauthorized_token()
File "/root/storm/eye/auth/utils.py", line 49, in get_unauthorized_token
return oauth.OAuthToken.from_string(oauth_response(req))
File "mypath/auth/utils.py", line 41, in oauth_response
connection().request(req.http_method, req.to_url())
File "/usr/lib/python2.5/httplib.py", line 866, in request
self._send_request(method, url, body, headers)
File "/usr/lib/python2.5/httplib.py", line 883, in _send_request
self.putrequest(method, url, **skips)
File "/usr/lib/python2.5/httplib.py", line 770, in putrequest
raise CannotSendRequest()
CannotSendRequest
This exception is raised when you reuse httplib.HTTP object for new request while you havn't called its getresponse() method for previous request. Probably there was some other error before this one that left connection in broken state. The simplest reliable way to fix the problem is creating new connection for each request, not reusing it. Sure, it will be a bit slower, but I think it's not an issue having you are running application in single process and single thread.
Also check your Python version. I had a similar situation after updating to Py-2.7 from Py-2.6. In Py-2.6 everything worked without any problems. Py-2.7 httplib uses HTTP/1.1 by default which made the server did not send back the Connection: close option in the respond, therefore the connection handling was broken. In my case this worked with HTTP/1.0 though.
http.client.CannotSendRequest: Request-sent
while using http.client module HTTPConnection class ran into the error caus my host name was incorrect