psf / requests

A simple, yet elegant, HTTP library.
https://requests.readthedocs.io/en/latest/
Apache License 2.0
52k stars 9.29k forks source link

SSL request hangs #2312

Closed ilya112358 closed 9 years ago

ilya112358 commented 9 years ago

The following curl test works fine:

curl -q -k --cert client-2048.crt --key client-2048.key https://identitysso.betfair.com/api/certlogin -d "username=testuser&password=testpassword" -H "X-Application: TestKey"

But the following python code hangs indefinitely on requests.post:

import requests

print 'Request test'

payload = 'username=testuser&password=testpassword'
headers = {
    'X-Application': 'TestKey',
    'Content-Type': 'application/x-www-form-urlencoded' }

resp = requests.post(
    'https://identitysso.betfair.com/api/certlogin',
    data=payload,
    cert=('client-2048.crt', 'client-2048.key'),
    headers=headers )

print 'Status code: ', resp.status_code

Last line never reached, the script hangs, no replies, no errors. Pressing Ctrl-C does not immediately abort but after several minutes prints:

Traceback (most recent call last):
  File "F:\LMG\test.py", line 14, in <module>
    headers=headers )
  File "C:\Python27\lib\site-packages\requests\api.py", line 94, in post
    return request('post', url, data=data, json=json, **kwargs)
  File "C:\Python27\lib\site-packages\requests\api.py", line 49, in request
    return session.request(method=method, url=url, **kwargs)
  File "C:\Python27\lib\site-packages\requests\sessions.py", line 457, in request
    resp = self.send(prep, **send_kwargs)
  File "C:\Python27\lib\site-packages\requests\sessions.py", line 569, in send
    r = adapter.send(request, **kwargs)
  File "C:\Python27\lib\site-packages\requests\adapters.py", line 362, in send
    timeout=timeout
  File "C:\Python27\lib\site-packages\requests\packages\urllib3\connectionpool.py", line 516, in urlopen
    body=body, headers=headers)
  File "C:\Python27\lib\site-packages\requests\packages\urllib3\connectionpool.py", line 331, in _make_request
    httplib_response = conn.getresponse(buffering=True)
  File "C:\Python27\lib\httplib.py", line 1030, in getresponse
    response.begin()
  File "C:\Python27\lib\httplib.py", line 407, in begin
    version, status, reason = self._read_status()
  File "C:\Python27\lib\httplib.py", line 365, in _read_status
    line = self.fp.readline()
  File "C:\Python27\lib\socket.py", line 447, in readline
    data = self._sock.recv(self._rbufsize)
  File "C:\Python27\lib\ssl.py", line 241, in recv
    return self.read(buflen)
  File "C:\Python27\lib\ssl.py", line 160, in read
    return self._sslobj.read(len)
KeyboardInterrupt

Python 2.7 under Windows 7. Requests ver. 2.4.3. I don't have much experience with Internet connection programming, I don't even understand where to go from here. Any ideas why it doesn't work as intended?

Lukasa commented 9 years ago

The server doesn't appear to be responding to the request. The handshake appears to have succeeded, but the server isn't sending anything back. I recommend sending all the headers cURL sent.

ilya112358 commented 9 years ago

Thanks for quick reaction, here is verbose reply from curl:

* Hostname was NOT found in DNS cache
*   Trying 84.20.200.150...
* Connected to identitysso.betfair.com (84.20.200.150) port 443 (#0)
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Server finished (14):
* SSLv3, TLS handshake, Client key exchange (16):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSL connection using TLSv1.0 / AES128-SHA
* Server certificate:
*        subject: C=GB; ST=London; L=London; O=The Sporting Exchange Limited; OU
=IT Networks; CN=betfair.com
*        start date: 2014-10-08 09:06:00 GMT
*        expire date: 2016-10-08 09:05:51 GMT
*        issuer: C=US; O=HydrantID (Avalanche Cloud Corporation); CN=HydrantID S
SL ICA G2
*        SSL certificate verify result: self signed certificate in certificate c
hain (19), continuing anyway.
> POST /api/certlogin HTTP/1.1
> User-Agent: curl/7.38.0
> Host: identitysso.betfair.com
> Accept: */*
> X-Application: TestKey
> Content-Length: 39
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 39 out of 39 bytes
* SSLv3, TLS handshake, Hello request (0):
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Request CERT (13):
* SSLv3, TLS handshake, Server finished (14):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Client key exchange (16):
* SSLv3, TLS handshake, CERT verify (15):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
< HTTP/1.1 200 OK
< Content-Type: text/plain;charset=ISO-8859-1
< Content-Length: 46
< Date: Tue, 28 Oct 2014 19:14:41 GMT
< Vary: Accept-Encoding
<
{"loginStatus":"INVALID_USERNAME_OR_PASSWORD"}* Connection #0 to host identityss
o.betfair.com left intact

Anything wrong here?

I tried adding the following fields one by one to the headers to no avail.

    'Content-Length': '39',
    'Accept': '*/*',
    'Host': 'identitysso.betfair.com',
    'User-Agent': 'curl/7.38.0' 

Seriously mind-boggling )

Lukasa commented 9 years ago

Hmm. What Python version are you using?

ilya112358 commented 9 years ago

As a matter of fact, 2.7.3... Wait a minute! Could it be?.. Installed 2.7.8, works smoothly and efficiently as advertised. Mesa soo stupid! Somehow thought they wouldn't update 2.x versions since they have 3.x already.

Lukasa, thank you so much, man! You literally saved my day!

Lukasa commented 9 years ago

My pleasure, glad I could help!

skvsn commented 8 years ago

I'm having exactly the same issue with Python 2.7.11 (Anaconda 2.4.0), Requests 2.9.0 on 64-bit Windows 7. Post request with certificate attached hangs. If I remove the certificate from requests.post call - then I receive 500 error from the server as expected.

Lukasa commented 8 years ago

You say "post request with the certificate attached": what exactly does that mean? What specifically are you doing?

skvsn commented 8 years ago

I'm trying to submit a SOAP request. By "certificate attached" I mean "cert" parameter set in a requests.post call

headers = {
    'Accept-Encoding': 'gzip,deflate',
    'Content-Type': 'application/soap+xml;charset=UTF-8',
    'User-Agent': 'Apache-HttpClient/4.1.1 (java 1.5)',
}
response = requests.post(
    url, 
    data=soap_request_data,
    cert=('cert.pem', 'key.pem'),
    verify=False,
    timeout=15,
    headers=headers,
)
Lukasa commented 8 years ago

@skvsn Is your key encrypted? That is, does it have a passphrase?

skvsn commented 8 years ago

Yes, it is encrypted. Do I have to provide unencrypted one? Or is there a way to pass the passphrase to requests?

Lukasa commented 8 years ago

Currently we have no way for you to provide the passphrase, so you'd have to decrypt it. =(

skvsn commented 8 years ago

@Lukasa Thanks a lot. It works perfectly with unencrypted key. Probably worth mentioning this in the docs.

Lukasa commented 8 years ago

Agreed. =)

skvsn commented 8 years ago

By the way, decrypting the key is really simple:

openssl rsa -in encrypted_key.pem -out unencrypted_key.pem