Issue 1:
Giving the malformed URL http://.com should lead to InvalidURL but results in a misleading UnicodeError.

Expected Result

Should raise InvalidURL.

Actual Result

Raises UnicodeError.

Reproduction Steps

import requests
requests.get("https://.com")

results in:

---------------------------------------------------------------------------
UnicodeError Traceback (most recent call last)
~/miniconda3/lib/python3.7/encodings/idna.py in encode(self, input, errors)
164 if not (0 < len(label) < 64):
--> 165 raise UnicodeError("label empty or too long")
166 if len(labels[-1]) >= 64:

UnicodeError: label empty or too long

The above exception was the direct cause of the following exception:

UnicodeError Traceback (most recent call last)
<ipython-input-33-45504cf090ae> in <module>
----> 1 requests.get('http://.com')

~/miniconda3/lib/python3.7/site-packages/requests/api.py in get(url, params, **kwargs)
73
74 kwargs.setdefault('allow_redirects', True)
---> 75 return request('get', url, params=params, **kwargs)
76
77

~/miniconda3/lib/python3.7/site-packages/requests/api.py in request(method, url, **kwargs)
58 # cases, and look like a memory leak in others.
59 with sessions.Session() as session:
---> 60 return session.request(method=method, url=url, **kwargs)
61
62

~/miniconda3/lib/python3.7/site-packages/requests/sessions.py in request(self, method, url, params, data, headers, cookies, files, auth, timeout, allow_redirects, proxies, hooks, stream, verify, cert, json)
531 }
532 send_kwargs.update(settings)
--> 533 resp = self.send(prep, **send_kwargs)
534
535 return resp

~/miniconda3/lib/python3.7/site-packages/requests/sessions.py in send(self, request, **kwargs)
644
645 # Send the request
--> 646 r = adapter.send(request, **kwargs)
647
648 # Total elapsed time of the request (approximately)

~/miniconda3/lib/python3.7/site-packages/requests/adapters.py in send(self, request, stream, timeout, verify, cert, proxies)
447 decode_content=False,
448 retries=self.max_retries,
--> 449 timeout=timeout
450 )
451

~/miniconda3/lib/python3.7/site-packages/urllib3/connectionpool.py in urlopen(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, **response_kw)
598 timeout=timeout_obj,
599 body=body, headers=headers,
--> 600 chunked=chunked)
601
602 # If we're going to release the connection in ``finally:``, then

~/miniconda3/lib/python3.7/site-packages/urllib3/connectionpool.py in _make_request(self, conn, method, url, timeout, chunked, **httplib_request_kw)
352 conn.request_chunked(method, url, **httplib_request_kw)
353 else:
--> 354 conn.request(method, url, **httplib_request_kw)
355
356 # Reset the timeout for the recv() on the socket

~/miniconda3/lib/python3.7/http/client.py in request(self, method, url, body, headers, encode_chunked)
1227 encode_chunked=False):
1228 """Send a complete request to the server."""
-> 1229 self._send_request(method, url, body, headers, encode_chunked)
1230
1231 def _send_request(self, method, url, body, headers, encode_chunked):

~/miniconda3/lib/python3.7/http/client.py in _send_request(self, method, url, body, headers, encode_chunked)
1273 # default charset of iso-8859-1.
1274 body = _encode(body, 'body')
-> 1275 self.endheaders(body, encode_chunked=encode_chunked)
1276
1277 def getresponse(self):

~/miniconda3/lib/python3.7/http/client.py in endheaders(self, message_body, encode_chunked)
1222 else:
1223 raise CannotSendHeader()
-> 1224 self._send_output(message_body, encode_chunked=encode_chunked)
1225
1226 def request(self, method, url, body=None, headers={}, *,

~/miniconda3/lib/python3.7/http/client.py in _send_output(self, message_body, encode_chunked)
1014 msg = b"\r\n".join(self._buffer)
1015 del self._buffer[:]
-> 1016 self.send(msg)
1017
1018 if message_body is not None:

~/miniconda3/lib/python3.7/http/client.py in send(self, data)
954 if self.sock is None:
955 if self.auto_open:
--> 956 self.connect()
957 else:
958 raise NotConnected()

~/miniconda3/lib/python3.7/site-packages/urllib3/connection.py in connect(self)
179
180 def connect(self):
--> 181 conn = self._new_conn()
182 self._prepare_conn(conn)
183

~/miniconda3/lib/python3.7/site-packages/urllib3/connection.py in _new_conn(self)
157 try:
158 conn = connection.create_connection(
--> 159 (self._dns_host, self.port), self.timeout, **extra_kw)
160
161 except SocketTimeout:

~/miniconda3/lib/python3.7/site-packages/urllib3/util/connection.py in create_connection(address, timeout, source_address, socket_options)
55 family = allowed_gai_family()
56
---> 57 for res in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM):
58 af, socktype, proto, canonname, sa = res
59 sock = None

~/miniconda3/lib/python3.7/socket.py in getaddrinfo(host, port, family, type, proto, flags)
746 # and socket type values to enum constants.
747 addrlist = []
--> 748 for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
749 af, socktype, proto, canonname, sa = res
750 addrlist.append((_intenum_converter(af, AddressFamily),

UnicodeError: encoding with 'idna' codec failed (UnicodeError: label empty or too long)

System Information

$ python -m requests.help

➔ python -m requests.help
{
"chardet": {
"version": "3.0.4"
},
"cryptography": {
"version": "2.7"
},
"idna": {
"version": "2.7"
},
"implementation": {
"name": "CPython",
"version": "3.7.3"
},
"platform": {
"release": "19.4.0",
"system": "Darwin"
},
"pyOpenSSL": {
"openssl_version": "1010103f",
"version": "19.0.0"
},
"requests": {
"version": "2.20.1"
},
"system_ssl": {
"version": "1010103f"
},
"urllib3": {
"version": "1.24.3"
},
"using_pyopenssl": true
}

Issue 2:
Trying to use a Session object to have a common TLS verify option for a bunch of calls in a CI environment for test with self signed certificates.

This works all right when no environment variable is set, but once REQUESTS_CA_BUNDLE or the equivalent curl var is set up, it fails.

This probably happens due to the logic in merge_environment_settings() and the merge logic for settings.

Expected Result

Verify works, the explicitly configured ca path on the Session object is used.

<Response [200]>

Actual Result

Verify fails, the implicitly configured environment setting overrides the explicit setting on the Session.

SSLError: HTTPSConnectionPool(host='example.org', port=8443): Max retries exceeded with url: /login (Caused by SSLError(SSLError(1, u'[SSL: CERTIFICATE_VERIFY_FAILED]

Reproduction Steps

import requests, os
# One of the many linux default locations for a ca bundle
os.environ['REQUESTS_CA_BUNDLE'] = '/etc/ssl/certs/ca-bundle.crt'
ca = "/home/schlenk/sqlite/certs/ca.crt"
print requests.get('https://myhost.example.org:8443/', verify=ca)
# This gives a <Response [200]>
# Now try with Session
s = requests.Session()
s.verify = ca
s.get('https://myhost.example.org:8443/')
# This throws an SSLError exception
# SSLError: HTTPSConnectionPool(host='myhost.example.org', port=8443): Max retries exceeded with url: / (Caused by SSLError(SSLError(1, u'[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:726)'),))
# But this works just fine
s.get('https://myhost.example.org:8443/', verify=ca)
<Response [200]>

System Information

$ python -m requests.help

d:\code\trunk64>win32\debug\img\python.exe -m requests.help
{
"chardet": {
"version": "3.0.4"
},
"cryptography": {
"version": "2.2.2"
},
"idna": {
"version": "2.6"
},
"implementation": {
"name": "CPython",
"version": "2.7.15"
},
"platform": {
"release": "2012ServerR2",
"system": "Windows"
},
"pyOpenSSL": {
"openssl_version": "100020df",
"version": "18.0.0"
},
"requests": {
"version": "2.18.4"
},
"system_ssl": {
"version": "100020ff"
},
"urllib3": {
"version": "1.22"
},
"using_pyopenssl": true
}

Same issue happens on Linux with identical versions.