request.get(url, proxies=proxies) is possibly sending CONNECT as two TCP transmission, breaking custom readers and TLS handshakes. 

Hey there, I have been experiencing something strange when using python to send requests to proxies. The python library is either slow(unlikely) or is sending the last two \r\n of the CONNECT request as a seperate transmission somehow. 

# Expected Result
❯ python test.py
{
  "ip": "82.76.235.76",
  "hostname": "82-76-235-76.rdsnet.ro",
  "city": "Bucharest",
  "region": "Bucureşti",
  "country": "RO",
  "loc": "44.4323,26.1063",
  "org": "AS8708 RCS & RDS SA",
  "postal": "020011",
  "timezone": "Europe/Bucharest",
  "readme": "https://ipinfo.io/missingauth"
}



# Actual Result

❯ python test.py
Traceback (most recent call last):
  File "/home/zkynet/.local/lib/python3.7/site-packages/requests/packages/urllib3/contrib/pyopenssl.py", line 348, in ssl_wrap_socket
    cnx.do_handshake()
  File "/home/zkynet/.local/lib/python3.7/site-packages/OpenSSL/SSL.py", line 1934, in do_handshake
    self._raise_ssl_error(self._ssl, result)
  File "/home/zkynet/.local/lib/python3.7/site-packages/OpenSSL/SSL.py", line 1671, in _raise_ssl_error
    _raise_current_error()
  File "/home/zkynet/.local/lib/python3.7/site-packages/OpenSSL/_util.py", line 54, in exception_from_error_queue
    raise exception_type(errors)
OpenSSL.SSL.Error: [('SSL routines', 'ssl3_read_bytes', 'tlsv1 alert protocol version')]

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/zkynet/.local/lib/python3.7/site-packages/requests/packages/urllib3/connectionpool.py", line 589, in urlopen
    self._prepare_proxy(conn)
  File "/home/zkynet/.local/lib/python3.7/site-packages/requests/packages/urllib3/connectionpool.py", line 797, in _prepare_proxy
    conn.connect()
  File "/home/zkynet/.local/lib/python3.7/site-packages/requests/packages/urllib3/connection.py", line 289, in connect
    ssl_version=resolved_ssl_version)
  File "/home/zkynet/.local/lib/python3.7/site-packages/requests/packages/urllib3/contrib/pyopenssl.py", line 355, in ssl_wrap_socket
    raise ssl.SSLError('bad handshake: %r' % e)
ssl.SSLError: ("bad handshake: Error([('SSL routines', 'ssl3_read_bytes', 'tlsv1 alert protocol version')])",)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/zkynet/.local/lib/python3.7/site-packages/requests/adapters.py", line 423, in send
    timeout=timeout
  File "/home/zkynet/.local/lib/python3.7/site-packages/requests/packages/urllib3/connectionpool.py", line 621, in urlopen
    raise SSLError(e)
requests.packages.urllib3.exceptions.SSLError: ("bad handshake: Error([('SSL routines', 'ssl3_read_bytes', 'tlsv1 alert protocol version')])",)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "test.py", line 8, in <module>
    response = requests.get("https://ipinfo.io/json", proxies=proxies)
  File "/home/zkynet/.local/lib/python3.7/site-packages/requests/api.py", line 70, in get
    return request('get', url, params=params, **kwargs)
  File "/home/zkynet/.local/lib/python3.7/site-packages/requests/api.py", line 56, in request
    return session.request(method=method, url=url, **kwargs)
  File "/home/zkynet/.local/lib/python3.7/site-packages/requests/sessions.py", line 475, in request
    resp = self.send(prep, **send_kwargs)
  File "/home/zkynet/.local/lib/python3.7/site-packages/requests/sessions.py", line 596, in send
    r = adapter.send(request, **kwargs)
  File "/home/zkynet/.local/lib/python3.7/site-packages/requests/adapters.py", line 497, in send
    raise SSLError(e, request=request)
requests.exceptions.SSLError: ("bad handshake: Error([('SSL routines', 'ssl3_read_bytes', 'tlsv1 alert protocol version')])",)



# Reproduction Steps
```python
import requests
proxies = {"https": "http://IP:PORT"}
response = requests.get("https://ipinfo.io/json", proxies=proxies)
print(response.text)
```
# What request sends to the proxy server:
1. Transmission: 
CONNECT ipinfo.io:443 HTTP/1.0\r\n
 **67 79 78 78 69 67 84 32 105 112 105 110 102 111 46 105 111 58 52 52 51 32 72 84 84 80 47 49 46 48 13 10**
2. Transmission:
\r\n
**13 10**

# What should have been sent to the proxy server in a single transmission:
 **67 79 78 78 69 67 84 32 105 112 105 110 102 111 46 105 111 58 52 52 51 32 72 84 84 80 47 49 46 48 13 10 13 10**
CONNECT ipinfo.io:443 HTTP/1.0\r\n\r\n




## System Information

$ python -m requests.help ( I could not execute this command for some reason)

**here is my version info:** 
```
❯ pip install requests
Defaulting to user installation because normal site-packages is not writeable
Requirement already satisfied: requests in /home/zkynet/.local/lib/python3.7/site-packages (2.11.1)

❯ python
Python 3.7.6 (default, Jan 30 2020, 09:44:41) 
[GCC 9.2.1 20190827 (Red Hat 9.2.1-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 
 
```

# Note on version
I did upgrade to 2.16.4 a bit later and found the same behaviour
`
 pip3.7 install  'requests==2.16.4'
Defaulting to user installation because normal site-packages is not writeable
Collecting requests==2.16.4
  Downloading requests-2.16.4-py2.py3-none-any.whl (87 kB)
     |████████████████████████████████| 87 kB 603 kB/s 
Collecting idna<2.6,>=2.5
  Downloading idna-2.5-py2.py3-none-any.whl (55 kB)
     |████████████████████████████████| 55 kB 2.9 MB/s 
Requirement already satisfied: certifi>=2017.4.17 in ./.local/lib/python3.7/site-packages (from requests==2.16.4) (2019.11.28)
Requirement already satisfied: chardet<3.1.0,>=3.0.2 in /usr/lib/python3.7/site-packages (from requests==2.16.4) (3.0.4)
Collecting urllib3<1.22,>=1.21.1
  Downloading urllib3-1.21.1-py2.py3-none-any.whl (131 kB)
     |████████████████████████████████| 131 kB 5.5 MB/s 
Installing collected packages: idna, urllib3, requests
Successfully installed idna-2.5 requests-2.16.4 urllib3-1.21.1
`

# So let's disect this 
What is happening is that this library is first sending the connect request and then somehow in a seperate transmission you are sending the last \r\n (13 10) and it's breaking the TLS handshake because the receiving end thinks it's the start of the handshake. 

## Possible reasons why this could be happening
1. You might be parsing/trying to inject something inn between the CONNECT and the closing tag ? maybe headers, cookies .. something like that. It could be causing a delay in the seinding of the closing tag. This forces TCP to split your transmission into two parts. 
2. Python might simple be slow at putting these bytes on the wire, causing my app to think the last 13 10 are a part of another series ( highly unlikely )
3. You might be putting some kind of 0 bytes in between the first \r\n and the last \r\n. Many TCP readers consider the 0 byte an EOF or a delimiter between messages. ( I am too lazy to open wireshark and dig through the packets to verify this one since I also think it's highly unlikely )

I personally suspect you might be doing 2x writes to the connection. The reason why I think so is because NO OTHER tools exhibits this behaviour. I've tested browsers, proxy plugins, golang, nodejs, bash, curl, wget.. to name a few. 

**Disclaimer: I know I can easily work around this bit either waiting for the second \r\n or just dismissing it when it arrives as the second transmission. But making special cases is something that shakes me to the bone.** 

# Where to go from here
I would love it if someone could look into this a little more. I don't know python and it would take me forever to try to understand this library. 

# What I (and possibly others) would LOVE to see happen
If you could compose your full CONNECT method and send it in a single transmission over the wire, you would save a lot of people a lot of time in the future. Not only that but make sure any developer making their own custom TCP listener/proxy service could easily integrade with your package without having to do some special cases. 

Please let me know if I can help in any way, Peace and Love. 


# Some follow up
It seems that your request is being sent as a single networking frame. The plot thickens..

Here is a CONNECT request made in golang using the http library:

![image](https://user-images.githubusercontent.com/20964930/76468441-a040e900-63f4-11ea-9f55-a38c92b1677b.png)

here is one with this library:

![image](https://user-images.githubusercontent.com/20964930/76468586-fca40880-63f4-11ea-8faf-dc05ffe79fbe.png)

# Side node on the host header
 [The mozila developer forums seem to suggest that the Host header is a part of the Connect request](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/CONNECT)
Additionally: [The IETF seems to lay out the specs like this](https://www.ietf.org/rfc/rfc2817.txt)
```
 5.2 Requesting a Tunnel with CONNECT

   A CONNECT method requests that a proxy establish a tunnel connection
   on its behalf. The Request-URI portion of the Request-Line is always
   an 'authority' as defined by URI Generic Syntax [2], which is to say
   the host name and port number destination of the requested connection
   separated by a colon:

      CONNECT server.example.com:80 HTTP/1.1
      Host: server.example.com:80

```

I don't know if the missing Host header has anything to do with the split reads though... 

But for fun I tried to add it manually...

```
import requests

proxies = {
    "https": "http://127.0.0.1:10010",
}

response = requests.get("https://ipinfo.io/json",headers={"Host":"ipinfo.io:443"}, proxies=proxies)
print(response.text)
```

But it does not get delivered. Prehapse I am doing something wrong, i'm not that good at python :S



Have you tested this with a different proxy server? It's possible your proxy was blacklisted by IPinfo.io

This has been tested on multiple proxy server AND on localhost. It is harder to reproduce this on localhost since the two seperate writes are really fast. You need to create a bit of latency on your loopback interface in order to see it.

Hello. I am seeing the same behavior with a squid server in my lab. In this case, client --> squid is encrypted in a TLS session and squid is NOT performing man-in-the-middle or bump. 
Everything seems to work until the CONNECT is sent. This is sent outside of the TLS tunnel in clear text! I did a capture of my cURL, which works, and I do not see any additional connections spun up and certainly not in clear text. [Here is a screen shot](https://i.stack.imgur.com/3hLx3.png) of the specific transaction. After the 3-way handshake, request sends a push, squid responds with an ack, and then requests sends the connect message but the message is not encrypted in the TLS tunnel. After which, squid acknowledges receipt of the CONNECT and immediately follows with a TCP RESET.
The squid logs show this:  `NONE/000 0 NONE error:transaction-end-before-headers - HIER_NONE/- -`

@aaronhackney I'm not sure if it's the same problem .. you should try logging the bytes being sent back and forth and check in which order they are sent. 

Also, bump ..

@zkynet Did you find any workaround to make this work? i've extactly the same problem

@zkynet The tone is unwarranted here. Keep in mind that the two people maintaining this project are volunteers.

This issue actually resides within Python's [`http.client.HTTPConnection._tunnel()`](https://github.com/python/cpython/blob/master/Lib/http/client.py#L903) method, there isn't much that Requests or urllib3 can do to resolve this problem. Perhaps you can try raising this issue on the Python issue tracker.