Fix SSL3 error on Ubuntu 12.04

When attempting to request (get or post) to a resource responding only to SSL version 3, we'd get the following response on Ubuntu 12.04:  

```

>>> import requests
>>> requests.post("https://sis-portal-prod.uttyler.edu/psp/TAPPRD/EMPLOYEE/EMPL/?&cmd=login")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "requests/api.py", line 98, in post
    return request('post', url, data=data, **kwargs)
  File "requests/safe_mode.py", line 39, in wrapped
    return function(method, url, **kwargs)
  File "requests/api.py", line 51, in request
    return session.request(method=method, url=url, **kwargs)
  File "requests/sessions.py", line 243, in request
    r.send(prefetch=prefetch)
  File "requests/models.py", line 630, in send
    raise SSLError(e)
requests.exceptions.SSLError: [Errno 1] _ssl.c:504: error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version

```

There's a [good number of people](http://www.google.com/search?q=python+error%3A1407742E%3ASSL+routines%3ASSL23_GET_SERVER_HELLO%3Atlsv1+alert+protocol+version&sugexp=chrome,mod=8&sourceid=chrome&ie=UTF-8) having the error. 

Fix taken from [this thread](http://bugs.python.org/issue11220). Specs pass. Even if you don't accept this into master, hopefully someone will see this pull request on Google. 


This pull request [fails](http://travis-ci.org/kennethreitz/requests/builds/2173252) (merged 413d4b3d into b130b980).


This pull request [fails](http://travis-ci.org/kennethreitz/requests/builds/2173256) (merged 413d4b3d into b130b980).


This pull request [passes](http://travis-ci.org/kennethreitz/requests/builds/2173308) (merged 6ac66b3d into b130b980).


Rebasing for a neater pull. 


This pull request [passes](http://travis-ci.org/kennethreitz/requests/builds/2173320) (merged c19650b0 into b130b980).


@joequery You should be making this pull request against urllib3, not requests :)


@kennethreitz :O You merged urllib3 pull request code into requests. Naughty.


god damn it, i hit the wrong button


Consequences will never be the same. :P


Reverted


Is there a known fix for this issue elsewhere? It looks like [#606](https://github.com/kennethreitz/requests/issues/606) is along the lines of what I'm looking for. However, requests was functioning fine on my mac, but not on Ubuntu 12.04, even after upgrading OpenSSL. 


@Schwanksta The respective issue on urllib3 has been closed. :)


I'm a little confused as to the status of what happened, here. My perception is that one change was made to urllib (allowing a SSL version to be passed) and that this PR was reverted, leaving only the @joequery fork of requests, where the only real change was to attempt SSL3 and _then_ SSL23.

There still exists a problem where any error will be caught and another connection reattempted using SSL23, sometimes or always causing the "unknown protocol" error. This can simply be fixed by reraising the exception unless the message matches the TLS-version error:

```
    try:
      self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file,
                                  cert_reqs=self.cert_reqs,
                                  ca_certs=self.ca_certs,
                                  ssl_version=ssl.PROTOCOL_SSLv3)
    except ssl.SSLError as e:
      if str(e).endswith(':tlsv1 alert protocol version') is False:
        raise

      self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file,
                                  cert_reqs=self.cert_reqs,
                                  ca_certs=self.ca_certs,
                                  ssl_version=ssl.PROTOCOL_SSLv23)
```

I'd submit an issue, but apparently forks can't have issues.

@joequery I think your fork might still be the only solution. Please confirm. If so, please consider the fix, above.


@dsoprea Please think very carefully before commenting on two-year-old issues. There was definitely a better, less-noisy way to handle providing your input.

Your reading of this issue is wrong. This pull request contained only changes to urllib3, which is a separate module to requests, maintained elsewhere. We do not accept code changes in urllib3 in this repository, as we simply bring in urllib3 wholesale. Any urllib3 changes therefore need to be made at the core repository, shazow/urllib3. This means even if we wanted to, we could not consider this fix, because it's not our fix to make.

Kenneth accidentally merged this fix when he intended to close it, so he also reverted it.

If you'd carefully checked the internet, you'd know that there is an accepted way to choose the SSL version used by Requests. It is documented [in this blog post](https://lukasa.co.uk/2013/01/Choosing_SSL_Version_In_Requests/) (now more than a year old), [this StackOverflow question](http://stackoverflow.com/questions/14102416/python-requests-requests-exceptions-sslerror-errno-8-ssl-c504-eof-occurred), [this Requests issue](https://github.com/kennethreitz/requests/issues/1083), and will be implemented in [this open-source library](https://github.com/sigmavirus24/requests-toolbelt).


I did a search for the bug that I was having, and I ended-up in that PR. I
apologize for posting the comment. Joe seemed to be fixing a bug that I
encountered first thing in the morning, and it seemed the most relevant to
a bug that never got fixed. I did not notice the timestamp, and got lost in
all of the various cross-linking. I appreciate the links in your response.

I would caution you against being so abrasive. I'll be careful to respond
to you as you have responded to me, should you ever have a question about
anomalous behavior in one of my projects that you might suddenly find
yourself relying on.

On Tue, Jan 7, 2014 at 10:58 AM, Cory Benfield notifications@github.comwrote:

> @dsoprea https://github.com/dsoprea Please think very carefully before
> commenting on two-year-old issues. There was definitely a better,
> less-noisy way to handle providing your input.
> 
> Your reading of this issue is wrong. This pull request contained only
> changes to urllib3, which is a separate module to requests, maintained
> elsewhere. We do not accept code changes in urllib3 in this repository, as
> we simply bring in urllib3 wholesale. Any urllib3 changes therefore need to
> be made at the core repository, shazow/urllib3. This means even if we
> wanted to, we could not consider this fix, because it's not our fix to make.
> 
> Kenneth accidentally merged this fix when he intended to close it, so he
> also reverted it.
> 
> If you'd carefully checked the internet, you'd know that there is an
> accepted way to choose the SSL version used by Requests. It is documented in
> this blog posthttps://lukasa.co.uk/2013/01/Choosing_SSL_Version_In_Requests/(now more than a year old), this
> StackOverflow questionhttp://stackoverflow.com/questions/14102416/python-requests-requests-exceptions-sslerror-errno-8-ssl-c504-eof-occurred,
> this Requests issue https://github.com/kennethreitz/requests/issues/1083,
> and will be implemented in this open-source libraryhttps://github.com/sigmavirus24/requests-toolbelt
> .
> 
> —
> Reply to this email directly or view it on GitHubhttps://github.com/kennethreitz/requests/pull/799#issuecomment-31749628
> .


I did not intend for that message to seem like I was chastising you, or to seem abrasive: I'm sorry.

It's worth noting that, as I mentioned, this comes up very frequently. This means that a lot of developer time is spent responding to duplicate issues and comments on previous issues. Any GitHub comment is responded to as if it is urgent, because they often are. This means a comment or GitHub issue is an instant cost of our time (as I'm sure you can appreciate from your own projects).

This is what I meant when I said there were "lower-noise" ways of raising this issue. For example, Stack Overflow would have been a suitable place to ask. Alternatively, emailing one of the triagers would have been just as appropriate: both @sigmavirus24 and I have our email addresses published very clearly.

My response was born in part from frustration at repeatedly having to follow up on issues opened or commented on that could have been resolved by more care. I'm sure you just made a mistake, and as I said, I'm sorry for not taking care with my language.


I appreciate that, Cory. I was also very frustrated, as it seems like I've
been dealing with tiny, obstructive bugs from every dependency lately, and
I just spent a week rebuilding a new solution as an alternative to an
existing one that was broken and blocking me. Right when I was about to
check-off the last feature, I run into a mechanical issue with SSL, where
I'm a bit fuzzy when it comes to implementation on _ssl and urllib, and how
requests wraps one or both. I'd be more careful in the afternoon, but when
I just couldn't get it done before having to walk out, this morning, I got
hasty.

On Tue, Jan 7, 2014 at 1:57 PM, Cory Benfield notifications@github.comwrote:

> I did not intend for that message to seem like I was chastising you, or to
> seem abrasive: I'm sorry.
> 
> It's worth noting that, as I mentioned, this comes up very frequently.
> This means that a lot of developer time is spent responding to duplicate
> issues and comments on previous issues. Any GitHub comment is responded to
> as if it is urgent, because they often are. This means a comment or GitHub
> issue is an instant cost of our time (as I'm sure you can appreciate from
> your own projects).
> 
> This is what I meant when I said there were "lower-noise" ways of raising
> this issue. For example, Stack Overflow would have been a suitable place to
> ask. Alternatively, emailing one of the triagers would have been just as
> appropriate: both @sigmavirus24 https://github.com/sigmavirus24 and I
> have our email addresses published very clearly.
> 
> My response was born in part from frustration at repeatedly having to
> follow up on issues opened or commented on that could have been resolved by
> more care. I'm sure you just made a mistake, and as I said, I'm sorry for
> not taking care with my language.
> 
> —
> Reply to this email directly or view it on GitHubhttps://github.com/kennethreitz/requests/pull/799#issuecomment-31767192
> .


I'm glad we could both step back and talk this out. =) Gives me a little more faith in humanity. I'm sorry you've been encountering SSL issues. Let me know if the linked solution helps you out: if it doesn't, I'll happily spend some time looking at your problem further (just, you know, email me first!).


I'm all for that. Thanks, Cory. That's what makes opensource work.

On Tue, Jan 7, 2014 at 2:36 PM, Cory Benfield notifications@github.comwrote:

> I'm glad we could both step back and talk this out. =) Gives me a little
> more faith in humanity. I'm sorry you've been encountering SSL issues. Let
> me know if the linked solution helps you out: if it doesn't, I'll happily
> spend some time looking at your problem further (just, you know, email me
> first!).
> 
> —
> Reply to this email directly or view it on GitHubhttps://github.com/kennethreitz/requests/pull/799#issuecomment-31771002
> .


@dsoprea My fork existed back when documentation concerning choosing SSL versions wasn't as easy to find. I still use my fork from time to time when I deal with scraping sites which exclusively deal with sslv3, because I'm lazy and don't feel like doing that mounting process :P

I'll make the update you provided anyway, so thanks for that. I also didn't think your initial comment was rude or inconsiderate at all, and I don't see how commenting on an issue similar to your own is "noisy".


He's a good guy. I was confused and annoyed by the presence of no seemingly
standard, staightforward solution, and he was just annoyed by something
being brought-up that seemed a bit more straightforward to him, and
resurrected an old thread.

I saw a reference by Ken to "transport adapters" on another thread, and
then, through more searches than I would've hoped, finally found my way to
the "transport adapters" section in the docs. I then just overrode
_init_poolmanager_, and added ssl_version as a parameter.

I think that HTTPAdapter should have this already, but I can't imagine it
wouldn't be there unless there was an exceptional reason.

I'll propose a PR that introduces an SSL example in the "transport
adapters" section of the documentation that I referred-to, above.

Dustin

On Wed, Jan 8, 2014 at 11:52 AM, Joseph McCullough <notifications@github.com

> wrote:
> 
> @dsoprea https://github.com/dsoprea My fork existed back before
> documentation concerning choosing SSL versions wasn't as easy to find. I
> still use my fork from time to time when I deal with scraping sites which
> exclusively deal with sslv3, because I'm lazy and don't feel like doing
> that mounting process :P
> 
> I'll make the update you provided anyway, so thanks for that. I also
> didn't think your initial comment was rude or inconsiderate at all, and I
> don't see how commenting on an issue similar to your own is "noisy".
> 
> —
> Reply to this email directly or view it on GitHubhttps://github.com/kennethreitz/requests/pull/799#issuecomment-31852884
> .


@joequery As @dsoprea just said, we both managed to get our wires crossed and weren't entirely our best selves. These things happen, apologies all round and everyone's friends again. =)

@dsoprea You mention that you're not sure why the SSL version isn't available on the default `HTTPAdapter`. This is a fair question. The short answer is that we don't want to provide options on the `HTTPAdapter` for _every single argument_ urllib3 takes on any of the functions we call. That will lead to a nightmare god-object, and worse, will lead to us duplicating the default values that are already in urllib3. That's a potential source of many many bugs.

With that in mind, we had to pick which attributes we thought were important enough to specify explicitly and which we thought weren't. This was an arbitrary decision, and Kenneth made it as he saw fit. In principle the `ssl_version` should never need to be set: it looks like the bug we're encountering here is related tangentially to buggy versions of OpenSSL (see a very recent discussion at #1847 and #1850, where the tone of the conversation provides an idea of how frustrating the maintainer + contributors find this SSL bugginess). This makes `ssl_version` a prime candidate to simply leave at its default urllib3 value.

This dovetails with the fact that the Transport Adapter interface is _intended_ to be an inheritance-based interface, not a function-parameters one. Again, [I've written briefly about this](https://lukasa.co.uk/2013/04/Requests_Two_APIs/) (though if you read the `SSLAdapter` post you'll find this retreads a lot of ground).

If you strongly disagree with this design decision, I can get Kenneth to weigh in on it, but we're strongly resisting changes to Requests' interfaces.

As for proposing an SSL Transport Adapter example in the documentation, I think we'd be happy to have it. =) I've documented it myself in a number of places that aren't the official documentation, and it's now present in what is likely to be a very popular companion library, but it also makes a good example.