@@ -223,10 +223,17 @@ class TCPConnector(BaseConnector):
223
223
"""
224
224
225
225
def __init__ (self , * args , verify_ssl = True ,
226
- resolve = False , family = socket .AF_INET , ** kwargs ):
226
+ resolve = False , family = socket .AF_INET , ssl_context = None ,
227
+ ** kwargs ):
228
+ if not verify_ssl and ssl_context is not None :
229
+ raise ValueError (
230
+ "Either disable ssl certificate validation by "
231
+ "verify_ssl=False or specify ssl_context, not both." )
232
+
227
233
super ().__init__ (* args , ** kwargs )
228
234
229
235
self ._verify_ssl = verify_ssl
236
+ self ._ssl_context = ssl_context
230
237
self ._family = family
231
238
self ._resolve = resolve
232
239
self ._resolved_hosts = {}
@@ -236,6 +243,33 @@ def verify_ssl(self):
236
243
"""Do check for ssl certifications?"""
237
244
return self ._verify_ssl
238
245
246
+ @property
247
+ def ssl_context (self ):
248
+ """SSLContext instance for https requests.
249
+
250
+ Lazy property, creates context on demand.
251
+ """
252
+ if self ._ssl_context is None :
253
+ if not self ._verify_ssl :
254
+ sslcontext = ssl .SSLContext (ssl .PROTOCOL_SSLv23 )
255
+ sslcontext .options |= ssl .OP_NO_SSLv2
256
+ sslcontext .options |= ssl .OP_NO_SSLv3
257
+ sslcontext .options |= getattr (ssl , "OP_NO_COMPRESSION" , 0 )
258
+ sslcontext .set_default_verify_paths ()
259
+ elif hasattr (ssl , 'create_default_context' ):
260
+ # Python 3.4+
261
+ sslcontext = ssl .create_default_context ()
262
+ else : # pragma: no cover
263
+ # Fallback for Python 3.3.
264
+ sslcontext = ssl .SSLContext (ssl .PROTOCOL_SSLv23 )
265
+ sslcontext .options |= ssl .OP_NO_SSLv2
266
+ sslcontext .options |= ssl .OP_NO_SSLv3
267
+ sslcontext .options |= getattr (ssl , "OP_NO_COMPRESSION" , 0 )
268
+ sslcontext .set_default_verify_paths ()
269
+ sslcontext .verify_mode = ssl .CERT_REQUIRED
270
+ self ._ssl_context = sslcontext
271
+ return self ._ssl_context
272
+
239
273
@property
240
274
def family (self ):
241
275
"""Socket family like AF_INET."""
@@ -288,11 +322,10 @@ def _create_connection(self, req, **kwargs):
288
322
289
323
Has same keyword arguments as BaseEventLoop.create_connection.
290
324
"""
291
- sslcontext = req .ssl
292
- if req .ssl and not self ._verify_ssl :
293
- sslcontext = ssl .SSLContext (ssl .PROTOCOL_SSLv23 )
294
- sslcontext .options |= ssl .OP_NO_SSLv2
295
- sslcontext .set_default_verify_paths ()
325
+ if req .ssl :
326
+ sslcontext = self .ssl_context
327
+ else :
328
+ sslcontext = None
296
329
297
330
hosts = yield from self ._resolve_host (req .host , req .port )
298
331
0 commit comments