We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
OpenSSL unsafe legacy renegotiation disabled error
<!--

Thanks for taking an interest in Scrapy!

If you have a question that starts with "How to...", please see the Scrapy Community page: https://scrapy.org/community/.
The GitHub issue tracker's purpose is to deal with bug reports and feature requests for the project itself.

Keep in mind that by filing an issue, you are expected to comply with Scrapy's Code of Conduct, including treating everyone with respect: https://github.com/scrapy/scrapy/blob/master/CODE_OF_CONDUCT.md

The following is a suggested template to structure your issue, you can find more guidelines at https://doc.scrapy.org/en/latest/contributing.html#reporting-bugs

-->

### Description

I get an SSL issue on a working [site ](https://dorotheum.com) 
`twisted.web._newclient.ResponseNeverReceived: [<twisted.python.failure.Failure OpenSSL.SSL.Error: [('SSL routines', '', 'unsafe legacy renegotiation disabled')]>]`

### Steps to Reproduce

1. `scrapy shell https://dorotheum.com`

**Expected behavior:** HTML page

**Actual behavior:** the error above

**Reproduces how often:** 100%

### Versions

```
Scrapy       : 2.6.1
lxml         : 4.8.0.0
libxml2      : 2.9.4
cssselect    : 1.1.0
parsel       : 1.6.0
w3lib        : 1.22.0
Twisted      : 22.4.0
Python       : 3.9.12 (main, Mar 26 2022, 15:44:31) - [Clang 13.1.6 (clang-1316.0.21.2)]
pyOpenSSL    : 22.0.0 (OpenSSL 3.0.3 3 May 2022)
cryptography : 37.0.2
Platform     : macOS-12.2.1-arm64-arm-64bit
```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `scrapy/utils/ssl.py`
Content:
```
1 import OpenSSL
2 import OpenSSL._util as pyOpenSSLutil
3 
4 from scrapy.utils.python import to_unicode
5 
6 
7 # The OpenSSL symbol is present since 1.1.1 but it's not currently supported in any version of pyOpenSSL.
8 # Using the binding directly, as this code does, requires cryptography 2.4.
9 SSL_OP_NO_TLSv1_3 = getattr(pyOpenSSLutil.lib, 'SSL_OP_NO_TLSv1_3', 0)
10 
11 
12 def ffi_buf_to_string(buf):
13     return to_unicode(pyOpenSSLutil.ffi.string(buf))
14 
15 
16 def x509name_to_string(x509name):
17     # from OpenSSL.crypto.X509Name.__repr__
18     result_buffer = pyOpenSSLutil.ffi.new("char[]", 512)
19     pyOpenSSLutil.lib.X509_NAME_oneline(x509name._name, result_buffer, len(result_buffer))
20 
21     return ffi_buf_to_string(result_buffer)
22 
23 
24 def get_temp_key_info(ssl_object):
25     if not hasattr(pyOpenSSLutil.lib, 'SSL_get_server_tmp_key'):  # requires OpenSSL 1.0.2
26         return None
27 
28     # adapted from OpenSSL apps/s_cb.c::ssl_print_tmp_key()
29     temp_key_p = pyOpenSSLutil.ffi.new("EVP_PKEY **")
30     if not pyOpenSSLutil.lib.SSL_get_server_tmp_key(ssl_object, temp_key_p):
31         return None
32     temp_key = temp_key_p[0]
33     if temp_key == pyOpenSSLutil.ffi.NULL:
34         return None
35     temp_key = pyOpenSSLutil.ffi.gc(temp_key, pyOpenSSLutil.lib.EVP_PKEY_free)
36     key_info = []
37     key_type = pyOpenSSLutil.lib.EVP_PKEY_id(temp_key)
38     if key_type == pyOpenSSLutil.lib.EVP_PKEY_RSA:
39         key_info.append('RSA')
40     elif key_type == pyOpenSSLutil.lib.EVP_PKEY_DH:
41         key_info.append('DH')
42     elif key_type == pyOpenSSLutil.lib.EVP_PKEY_EC:
43         key_info.append('ECDH')
44         ec_key = pyOpenSSLutil.lib.EVP_PKEY_get1_EC_KEY(temp_key)
45         ec_key = pyOpenSSLutil.ffi.gc(ec_key, pyOpenSSLutil.lib.EC_KEY_free)
46         nid = pyOpenSSLutil.lib.EC_GROUP_get_curve_name(pyOpenSSLutil.lib.EC_KEY_get0_group(ec_key))
47         cname = pyOpenSSLutil.lib.EC_curve_nid2nist(nid)
48         if cname == pyOpenSSLutil.ffi.NULL:
49             cname = pyOpenSSLutil.lib.OBJ_nid2sn(nid)
50         key_info.append(ffi_buf_to_string(cname))
51     else:
52         key_info.append(ffi_buf_to_string(pyOpenSSLutil.lib.OBJ_nid2sn(key_type)))
53     key_info.append(f'{pyOpenSSLutil.lib.EVP_PKEY_bits(temp_key)} bits')
54     return ', '.join(key_info)
55 
56 
57 def get_openssl_version():
58     system_openssl = OpenSSL.SSL.SSLeay_version(
59         OpenSSL.SSL.SSLEAY_VERSION
60     ).decode('ascii', errors='replace')
61     return f'{OpenSSL.version.__version__} ({system_openssl})'
62
```

Path: `scrapy/core/downloader/tls.py`
Content:
```
1 import logging
2 
3 from OpenSSL import SSL
4 from service_identity.exceptions import CertificateError
5 from twisted.internet._sslverify import ClientTLSOptions, verifyHostname, VerificationError
6 from twisted.internet.ssl import AcceptableCiphers
7 
8 from scrapy.utils.ssl import x509name_to_string, get_temp_key_info
9 
10 logger = logging.getLogger(__name__)
11 
12 
13 METHOD_TLS = 'TLS'
14 METHOD_TLSv10 = 'TLSv1.0'
15 METHOD_TLSv11 = 'TLSv1.1'
16 METHOD_TLSv12 = 'TLSv1.2'
17 
18 
19 openssl_methods = {
20     METHOD_TLS: SSL.SSLv23_METHOD,                      # protocol negotiation (recommended)
21     METHOD_TLSv10: SSL.TLSv1_METHOD,                    # TLS 1.0 only
22     METHOD_TLSv11: getattr(SSL, 'TLSv1_1_METHOD', 5),   # TLS 1.1 only
23     METHOD_TLSv12: getattr(SSL, 'TLSv1_2_METHOD', 6),   # TLS 1.2 only
24 }
25 
26 
27 class ScrapyClientTLSOptions(ClientTLSOptions):
28     """
29     SSL Client connection creator ignoring certificate verification errors
30     (for genuinely invalid certificates or bugs in verification code).
31 
32     Same as Twisted's private _sslverify.ClientTLSOptions,
33     except that VerificationError, CertificateError and ValueError
34     exceptions are caught, so that the connection is not closed, only
35     logging warnings. Also, HTTPS connection parameters logging is added.
36     """
37 
38     def __init__(self, hostname, ctx, verbose_logging=False):
39         super().__init__(hostname, ctx)
40         self.verbose_logging = verbose_logging
41 
42     def _identityVerifyingInfoCallback(self, connection, where, ret):
43         if where & SSL.SSL_CB_HANDSHAKE_START:
44             connection.set_tlsext_host_name(self._hostnameBytes)
45         elif where & SSL.SSL_CB_HANDSHAKE_DONE:
46             if self.verbose_logging:
47                 logger.debug('SSL connection to %s using protocol %s, cipher %s',
48                              self._hostnameASCII,
49                              connection.get_protocol_version_name(),
50                              connection.get_cipher_name(),
51                              )
52                 server_cert = connection.get_peer_certificate()
53                 logger.debug('SSL connection certificate: issuer "%s", subject "%s"',
54                              x509name_to_string(server_cert.get_issuer()),
55                              x509name_to_string(server_cert.get_subject()),
56                              )
57                 key_info = get_temp_key_info(connection._ssl)
58                 if key_info:
59                     logger.debug('SSL temp key: %s', key_info)
60 
61             try:
62                 verifyHostname(connection, self._hostnameASCII)
63             except (CertificateError, VerificationError) as e:
64                 logger.warning(
65                     'Remote certificate is not valid for hostname "%s"; %s',
66                     self._hostnameASCII, e)
67 
68             except ValueError as e:
69                 logger.warning(
70                     'Ignoring error while verifying certificate '
71                     'from host "%s" (exception: %r)',
72                     self._hostnameASCII, e)
73 
74 
75 DEFAULT_CIPHERS = AcceptableCiphers.fromOpenSSLCipherString('DEFAULT')
76
```

Path: `scrapy/core/downloader/contextfactory.py`
Content:
```
1 import warnings
2 
3 from OpenSSL import SSL
4 from twisted.internet._sslverify import _setAcceptableProtocols
5 from twisted.internet.ssl import optionsForClientTLS, CertificateOptions, platformTrust, AcceptableCiphers
6 from twisted.web.client import BrowserLikePolicyForHTTPS
7 from twisted.web.iweb import IPolicyForHTTPS
8 from zope.interface.declarations import implementer
9 from zope.interface.verify import verifyObject
10 
11 from scrapy.core.downloader.tls import DEFAULT_CIPHERS, openssl_methods, ScrapyClientTLSOptions
12 from scrapy.utils.misc import create_instance, load_object
13 
14 
15 @implementer(IPolicyForHTTPS)
16 class ScrapyClientContextFactory(BrowserLikePolicyForHTTPS):
17     """
18     Non-peer-certificate verifying HTTPS context factory
19 
20     Default OpenSSL method is TLS_METHOD (also called SSLv23_METHOD)
21     which allows TLS protocol negotiation
22 
23     'A TLS/SSL connection established with [this method] may
24      understand the TLSv1, TLSv1.1 and TLSv1.2 protocols.'
25     """
26 
27     def __init__(self, method=SSL.SSLv23_METHOD, tls_verbose_logging=False, tls_ciphers=None, *args, **kwargs):
28         super().__init__(*args, **kwargs)
29         self._ssl_method = method
30         self.tls_verbose_logging = tls_verbose_logging
31         if tls_ciphers:
32             self.tls_ciphers = AcceptableCiphers.fromOpenSSLCipherString(tls_ciphers)
33         else:
34             self.tls_ciphers = DEFAULT_CIPHERS
35 
36     @classmethod
37     def from_settings(cls, settings, method=SSL.SSLv23_METHOD, *args, **kwargs):
38         tls_verbose_logging = settings.getbool('DOWNLOADER_CLIENT_TLS_VERBOSE_LOGGING')
39         tls_ciphers = settings['DOWNLOADER_CLIENT_TLS_CIPHERS']
40         return cls(method=method, tls_verbose_logging=tls_verbose_logging, tls_ciphers=tls_ciphers, *args, **kwargs)
41 
42     def getCertificateOptions(self):
43         # setting verify=True will require you to provide CAs
44         # to verify against; in other words: it's not that simple
45 
46         # backward-compatible SSL/TLS method:
47         #
48         # * this will respect `method` attribute in often recommended
49         #   `ScrapyClientContextFactory` subclass
50         #   (https://github.com/scrapy/scrapy/issues/1429#issuecomment-131782133)
51         #
52         # * getattr() for `_ssl_method` attribute for context factories
53         #   not calling super().__init__
54         return CertificateOptions(
55             verify=False,
56             method=getattr(self, 'method', getattr(self, '_ssl_method', None)),
57             fixBrokenPeers=True,
58             acceptableCiphers=self.tls_ciphers,
59         )
60 
61     # kept for old-style HTTP/1.0 downloader context twisted calls,
62     # e.g. connectSSL()
63     def getContext(self, hostname=None, port=None):
64         return self.getCertificateOptions().getContext()
65 
66     def creatorForNetloc(self, hostname, port):
67         return ScrapyClientTLSOptions(hostname.decode("ascii"), self.getContext(),
68                                       verbose_logging=self.tls_verbose_logging)
69 
70 
71 @implementer(IPolicyForHTTPS)
72 class BrowserLikeContextFactory(ScrapyClientContextFactory):
73     """
74     Twisted-recommended context factory for web clients.
75 
76     Quoting the documentation of the :class:`~twisted.web.client.Agent` class:
77 
78         The default is to use a
79         :class:`~twisted.web.client.BrowserLikePolicyForHTTPS`, so unless you
80         have special requirements you can leave this as-is.
81 
82     :meth:`creatorForNetloc` is the same as
83     :class:`~twisted.web.client.BrowserLikePolicyForHTTPS` except this context
84     factory allows setting the TLS/SSL method to use.
85 
86     The default OpenSSL method is ``TLS_METHOD`` (also called
87     ``SSLv23_METHOD``) which allows TLS protocol negotiation.
88     """
89 
90     def creatorForNetloc(self, hostname, port):
91         # trustRoot set to platformTrust() will use the platform's root CAs.
92         #
93         # This means that a website like https://www.cacert.org will be rejected
94         # by default, since CAcert.org CA certificate is seldom shipped.
95         return optionsForClientTLS(
96             hostname=hostname.decode("ascii"),
97             trustRoot=platformTrust(),
98             extraCertificateOptions={'method': self._ssl_method},
99         )
100 
101 
102 @implementer(IPolicyForHTTPS)
103 class AcceptableProtocolsContextFactory:
104     """Context factory to used to override the acceptable protocols
105     to set up the [OpenSSL.SSL.Context] for doing NPN and/or ALPN
106     negotiation.
107     """
108 
109     def __init__(self, context_factory, acceptable_protocols):
110         verifyObject(IPolicyForHTTPS, context_factory)
111         self._wrapped_context_factory = context_factory
112         self._acceptable_protocols = acceptable_protocols
113 
114     def creatorForNetloc(self, hostname, port):
115         options = self._wrapped_context_factory.creatorForNetloc(hostname, port)
116         _setAcceptableProtocols(options._ctx, self._acceptable_protocols)
117         return options
118 
119 
120 def load_context_factory_from_settings(settings, crawler):
121     ssl_method = openssl_methods[settings.get('DOWNLOADER_CLIENT_TLS_METHOD')]
122     context_factory_cls = load_object(settings['DOWNLOADER_CLIENTCONTEXTFACTORY'])
123     # try method-aware context factory
124     try:
125         context_factory = create_instance(
126             objcls=context_factory_cls,
127             settings=settings,
128             crawler=crawler,
129             method=ssl_method,
130         )
131     except TypeError:
132         # use context factory defaults
133         context_factory = create_instance(
134             objcls=context_factory_cls,
135             settings=settings,
136             crawler=crawler,
137         )
138         msg = (
139             f"{settings['DOWNLOADER_CLIENTCONTEXTFACTORY']} does not accept "
140             "a `method` argument (type OpenSSL.SSL method, e.g. "
141             "OpenSSL.SSL.SSLv23_METHOD) and/or a `tls_verbose_logging` "
142             "argument and/or a `tls_ciphers` argument. Please, upgrade your "
143             "context factory class to handle them or ignore them."
144         )
145         warnings.warn(msg)
146 
147     return context_factory
148
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/scrapy/core/downloader/contextfactory.py b/scrapy/core/downloader/contextfactory.py
--- a/scrapy/core/downloader/contextfactory.py
+++ b/scrapy/core/downloader/contextfactory.py
@@ -61,7 +61,9 @@
     # kept for old-style HTTP/1.0 downloader context twisted calls,
     # e.g. connectSSL()
     def getContext(self, hostname=None, port=None):
-        return self.getCertificateOptions().getContext()
+        ctx = self.getCertificateOptions().getContext()
+        ctx.set_options(0x4)  # OP_LEGACY_SERVER_CONNECT
+        return ctx
 
     def creatorForNetloc(self, hostname, port):
         return ScrapyClientTLSOptions(hostname.decode("ascii"), self.getContext(),
diff --git a/scrapy/core/downloader/tls.py b/scrapy/core/downloader/tls.py
--- a/scrapy/core/downloader/tls.py
+++ b/scrapy/core/downloader/tls.py
@@ -17,10 +17,10 @@
 
 
 openssl_methods = {
-    METHOD_TLS: SSL.SSLv23_METHOD,                      # protocol negotiation (recommended)
-    METHOD_TLSv10: SSL.TLSv1_METHOD,                    # TLS 1.0 only
-    METHOD_TLSv11: getattr(SSL, 'TLSv1_1_METHOD', 5),   # TLS 1.1 only
-    METHOD_TLSv12: getattr(SSL, 'TLSv1_2_METHOD', 6),   # TLS 1.2 only
+    METHOD_TLS: SSL.SSLv23_METHOD,      # protocol negotiation (recommended)
+    METHOD_TLSv10: SSL.TLSv1_METHOD,    # TLS 1.0 only
+    METHOD_TLSv11: SSL.TLSv1_1_METHOD,  # TLS 1.1 only
+    METHOD_TLSv12: SSL.TLSv1_2_METHOD,  # TLS 1.2 only
 }
 
 
diff --git a/scrapy/utils/ssl.py b/scrapy/utils/ssl.py
--- a/scrapy/utils/ssl.py
+++ b/scrapy/utils/ssl.py
@@ -1,14 +1,9 @@
-import OpenSSL
+import OpenSSL.SSL
 import OpenSSL._util as pyOpenSSLutil
 
 from scrapy.utils.python import to_unicode
 
 
-# The OpenSSL symbol is present since 1.1.1 but it's not currently supported in any version of pyOpenSSL.
-# Using the binding directly, as this code does, requires cryptography 2.4.
-SSL_OP_NO_TLSv1_3 = getattr(pyOpenSSLutil.lib, 'SSL_OP_NO_TLSv1_3', 0)
-
-
 def ffi_buf_to_string(buf):
     return to_unicode(pyOpenSSLutil.ffi.string(buf))
 
@@ -22,9 +17,6 @@
 
 
 def get_temp_key_info(ssl_object):
-    if not hasattr(pyOpenSSLutil.lib, 'SSL_get_server_tmp_key'):  # requires OpenSSL 1.0.2
-        return None
-
     # adapted from OpenSSL apps/s_cb.c::ssl_print_tmp_key()
     temp_key_p = pyOpenSSLutil.ffi.new("EVP_PKEY **")
     if not pyOpenSSLutil.lib.SSL_get_server_tmp_key(ssl_object, temp_key_p):

{"golden_diff": "diff --git a/scrapy/core/downloader/contextfactory.py b/scrapy/core/downloader/contextfactory.py\n--- a/scrapy/core/downloader/contextfactory.py\n+++ b/scrapy/core/downloader/contextfactory.py\n@@ -61,7 +61,9 @@\n     # kept for old-style HTTP/1.0 downloader context twisted calls,\n     # e.g. connectSSL()\n     def getContext(self, hostname=None, port=None):\n-        return self.getCertificateOptions().getContext()\n+        ctx = self.getCertificateOptions().getContext()\n+        ctx.set_options(0x4)  # OP_LEGACY_SERVER_CONNECT\n+        return ctx\n \n     def creatorForNetloc(self, hostname, port):\n         return ScrapyClientTLSOptions(hostname.decode(\"ascii\"), self.getContext(),\ndiff --git a/scrapy/core/downloader/tls.py b/scrapy/core/downloader/tls.py\n--- a/scrapy/core/downloader/tls.py\n+++ b/scrapy/core/downloader/tls.py\n@@ -17,10 +17,10 @@\n \n \n openssl_methods = {\n-    METHOD_TLS: SSL.SSLv23_METHOD,                      # protocol negotiation (recommended)\n-    METHOD_TLSv10: SSL.TLSv1_METHOD,                    # TLS 1.0 only\n-    METHOD_TLSv11: getattr(SSL, 'TLSv1_1_METHOD', 5),   # TLS 1.1 only\n-    METHOD_TLSv12: getattr(SSL, 'TLSv1_2_METHOD', 6),   # TLS 1.2 only\n+    METHOD_TLS: SSL.SSLv23_METHOD,      # protocol negotiation (recommended)\n+    METHOD_TLSv10: SSL.TLSv1_METHOD,    # TLS 1.0 only\n+    METHOD_TLSv11: SSL.TLSv1_1_METHOD,  # TLS 1.1 only\n+    METHOD_TLSv12: SSL.TLSv1_2_METHOD,  # TLS 1.2 only\n }\n \n \ndiff --git a/scrapy/utils/ssl.py b/scrapy/utils/ssl.py\n--- a/scrapy/utils/ssl.py\n+++ b/scrapy/utils/ssl.py\n@@ -1,14 +1,9 @@\n-import OpenSSL\n+import OpenSSL.SSL\n import OpenSSL._util as pyOpenSSLutil\n \n from scrapy.utils.python import to_unicode\n \n \n-# The OpenSSL symbol is present since 1.1.1 but it's not currently supported in any version of pyOpenSSL.\n-# Using the binding directly, as this code does, requires cryptography 2.4.\n-SSL_OP_NO_TLSv1_3 = getattr(pyOpenSSLutil.lib, 'SSL_OP_NO_TLSv1_3', 0)\n-\n-\n def ffi_buf_to_string(buf):\n     return to_unicode(pyOpenSSLutil.ffi.string(buf))\n \n@@ -22,9 +17,6 @@\n \n \n def get_temp_key_info(ssl_object):\n-    if not hasattr(pyOpenSSLutil.lib, 'SSL_get_server_tmp_key'):  # requires OpenSSL 1.0.2\n-        return None\n-\n     # adapted from OpenSSL apps/s_cb.c::ssl_print_tmp_key()\n     temp_key_p = pyOpenSSLutil.ffi.new(\"EVP_PKEY **\")\n     if not pyOpenSSLutil.lib.SSL_get_server_tmp_key(ssl_object, temp_key_p):\n", "issue": "OpenSSL unsafe legacy renegotiation disabled error\n<!--\r\n\r\nThanks for taking an interest in Scrapy!\r\n\r\nIf you have a question that starts with \"How to...\", please see the Scrapy Community page: https://scrapy.org/community/.\r\nThe GitHub issue tracker's purpose is to deal with bug reports and feature requests for the project itself.\r\n\r\nKeep in mind that by filing an issue, you are expected to comply with Scrapy's Code of Conduct, including treating everyone with respect: https://github.com/scrapy/scrapy/blob/master/CODE_OF_CONDUCT.md\r\n\r\nThe following is a suggested template to structure your issue, you can find more guidelines at https://doc.scrapy.org/en/latest/contributing.html#reporting-bugs\r\n\r\n-->\r\n\r\n### Description\r\n\r\nI get an SSL issue on a working [site ](https://dorotheum.com) \r\n`twisted.web._newclient.ResponseNeverReceived: [<twisted.python.failure.Failure OpenSSL.SSL.Error: [('SSL routines', '', 'unsafe legacy renegotiation disabled')]>]`\r\n\r\n### Steps to Reproduce\r\n\r\n1. `scrapy shell https://dorotheum.com`\r\n\r\n**Expected behavior:** HTML page\r\n\r\n**Actual behavior:** the error above\r\n\r\n**Reproduces how often:** 100%\r\n\r\n### Versions\r\n\r\n```\r\nScrapy       : 2.6.1\r\nlxml         : 4.8.0.0\r\nlibxml2      : 2.9.4\r\ncssselect    : 1.1.0\r\nparsel       : 1.6.0\r\nw3lib        : 1.22.0\r\nTwisted      : 22.4.0\r\nPython       : 3.9.12 (main, Mar 26 2022, 15:44:31) - [Clang 13.1.6 (clang-1316.0.21.2)]\r\npyOpenSSL    : 22.0.0 (OpenSSL 3.0.3 3 May 2022)\r\ncryptography : 37.0.2\r\nPlatform     : macOS-12.2.1-arm64-arm-64bit\r\n```\r\n\n", "before_files": [{"content": "import OpenSSL\nimport OpenSSL._util as pyOpenSSLutil\n\nfrom scrapy.utils.python import to_unicode\n\n\n# The OpenSSL symbol is present since 1.1.1 but it's not currently supported in any version of pyOpenSSL.\n# Using the binding directly, as this code does, requires cryptography 2.4.\nSSL_OP_NO_TLSv1_3 = getattr(pyOpenSSLutil.lib, 'SSL_OP_NO_TLSv1_3', 0)\n\n\ndef ffi_buf_to_string(buf):\n    return to_unicode(pyOpenSSLutil.ffi.string(buf))\n\n\ndef x509name_to_string(x509name):\n    # from OpenSSL.crypto.X509Name.__repr__\n    result_buffer = pyOpenSSLutil.ffi.new(\"char[]\", 512)\n    pyOpenSSLutil.lib.X509_NAME_oneline(x509name._name, result_buffer, len(result_buffer))\n\n    return ffi_buf_to_string(result_buffer)\n\n\ndef get_temp_key_info(ssl_object):\n    if not hasattr(pyOpenSSLutil.lib, 'SSL_get_server_tmp_key'):  # requires OpenSSL 1.0.2\n        return None\n\n    # adapted from OpenSSL apps/s_cb.c::ssl_print_tmp_key()\n    temp_key_p = pyOpenSSLutil.ffi.new(\"EVP_PKEY **\")\n    if not pyOpenSSLutil.lib.SSL_get_server_tmp_key(ssl_object, temp_key_p):\n        return None\n    temp_key = temp_key_p[0]\n    if temp_key == pyOpenSSLutil.ffi.NULL:\n        return None\n    temp_key = pyOpenSSLutil.ffi.gc(temp_key, pyOpenSSLutil.lib.EVP_PKEY_free)\n    key_info = []\n    key_type = pyOpenSSLutil.lib.EVP_PKEY_id(temp_key)\n    if key_type == pyOpenSSLutil.lib.EVP_PKEY_RSA:\n        key_info.append('RSA')\n    elif key_type == pyOpenSSLutil.lib.EVP_PKEY_DH:\n        key_info.append('DH')\n    elif key_type == pyOpenSSLutil.lib.EVP_PKEY_EC:\n        key_info.append('ECDH')\n        ec_key = pyOpenSSLutil.lib.EVP_PKEY_get1_EC_KEY(temp_key)\n        ec_key = pyOpenSSLutil.ffi.gc(ec_key, pyOpenSSLutil.lib.EC_KEY_free)\n        nid = pyOpenSSLutil.lib.EC_GROUP_get_curve_name(pyOpenSSLutil.lib.EC_KEY_get0_group(ec_key))\n        cname = pyOpenSSLutil.lib.EC_curve_nid2nist(nid)\n        if cname == pyOpenSSLutil.ffi.NULL:\n            cname = pyOpenSSLutil.lib.OBJ_nid2sn(nid)\n        key_info.append(ffi_buf_to_string(cname))\n    else:\n        key_info.append(ffi_buf_to_string(pyOpenSSLutil.lib.OBJ_nid2sn(key_type)))\n    key_info.append(f'{pyOpenSSLutil.lib.EVP_PKEY_bits(temp_key)} bits')\n    return ', '.join(key_info)\n\n\ndef get_openssl_version():\n    system_openssl = OpenSSL.SSL.SSLeay_version(\n        OpenSSL.SSL.SSLEAY_VERSION\n    ).decode('ascii', errors='replace')\n    return f'{OpenSSL.version.__version__} ({system_openssl})'\n", "path": "scrapy/utils/ssl.py"}, {"content": "import logging\n\nfrom OpenSSL import SSL\nfrom service_identity.exceptions import CertificateError\nfrom twisted.internet._sslverify import ClientTLSOptions, verifyHostname, VerificationError\nfrom twisted.internet.ssl import AcceptableCiphers\n\nfrom scrapy.utils.ssl import x509name_to_string, get_temp_key_info\n\nlogger = logging.getLogger(__name__)\n\n\nMETHOD_TLS = 'TLS'\nMETHOD_TLSv10 = 'TLSv1.0'\nMETHOD_TLSv11 = 'TLSv1.1'\nMETHOD_TLSv12 = 'TLSv1.2'\n\n\nopenssl_methods = {\n    METHOD_TLS: SSL.SSLv23_METHOD,                      # protocol negotiation (recommended)\n    METHOD_TLSv10: SSL.TLSv1_METHOD,                    # TLS 1.0 only\n    METHOD_TLSv11: getattr(SSL, 'TLSv1_1_METHOD', 5),   # TLS 1.1 only\n    METHOD_TLSv12: getattr(SSL, 'TLSv1_2_METHOD', 6),   # TLS 1.2 only\n}\n\n\nclass ScrapyClientTLSOptions(ClientTLSOptions):\n    \"\"\"\n    SSL Client connection creator ignoring certificate verification errors\n    (for genuinely invalid certificates or bugs in verification code).\n\n    Same as Twisted's private _sslverify.ClientTLSOptions,\n    except that VerificationError, CertificateError and ValueError\n    exceptions are caught, so that the connection is not closed, only\n    logging warnings. Also, HTTPS connection parameters logging is added.\n    \"\"\"\n\n    def __init__(self, hostname, ctx, verbose_logging=False):\n        super().__init__(hostname, ctx)\n        self.verbose_logging = verbose_logging\n\n    def _identityVerifyingInfoCallback(self, connection, where, ret):\n        if where & SSL.SSL_CB_HANDSHAKE_START:\n            connection.set_tlsext_host_name(self._hostnameBytes)\n        elif where & SSL.SSL_CB_HANDSHAKE_DONE:\n            if self.verbose_logging:\n                logger.debug('SSL connection to %s using protocol %s, cipher %s',\n                             self._hostnameASCII,\n                             connection.get_protocol_version_name(),\n                             connection.get_cipher_name(),\n                             )\n                server_cert = connection.get_peer_certificate()\n                logger.debug('SSL connection certificate: issuer \"%s\", subject \"%s\"',\n                             x509name_to_string(server_cert.get_issuer()),\n                             x509name_to_string(server_cert.get_subject()),\n                             )\n                key_info = get_temp_key_info(connection._ssl)\n                if key_info:\n                    logger.debug('SSL temp key: %s', key_info)\n\n            try:\n                verifyHostname(connection, self._hostnameASCII)\n            except (CertificateError, VerificationError) as e:\n                logger.warning(\n                    'Remote certificate is not valid for hostname \"%s\"; %s',\n                    self._hostnameASCII, e)\n\n            except ValueError as e:\n                logger.warning(\n                    'Ignoring error while verifying certificate '\n                    'from host \"%s\" (exception: %r)',\n                    self._hostnameASCII, e)\n\n\nDEFAULT_CIPHERS = AcceptableCiphers.fromOpenSSLCipherString('DEFAULT')\n", "path": "scrapy/core/downloader/tls.py"}, {"content": "import warnings\n\nfrom OpenSSL import SSL\nfrom twisted.internet._sslverify import _setAcceptableProtocols\nfrom twisted.internet.ssl import optionsForClientTLS, CertificateOptions, platformTrust, AcceptableCiphers\nfrom twisted.web.client import BrowserLikePolicyForHTTPS\nfrom twisted.web.iweb import IPolicyForHTTPS\nfrom zope.interface.declarations import implementer\nfrom zope.interface.verify import verifyObject\n\nfrom scrapy.core.downloader.tls import DEFAULT_CIPHERS, openssl_methods, ScrapyClientTLSOptions\nfrom scrapy.utils.misc import create_instance, load_object\n\n\n@implementer(IPolicyForHTTPS)\nclass ScrapyClientContextFactory(BrowserLikePolicyForHTTPS):\n    \"\"\"\n    Non-peer-certificate verifying HTTPS context factory\n\n    Default OpenSSL method is TLS_METHOD (also called SSLv23_METHOD)\n    which allows TLS protocol negotiation\n\n    'A TLS/SSL connection established with [this method] may\n     understand the TLSv1, TLSv1.1 and TLSv1.2 protocols.'\n    \"\"\"\n\n    def __init__(self, method=SSL.SSLv23_METHOD, tls_verbose_logging=False, tls_ciphers=None, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._ssl_method = method\n        self.tls_verbose_logging = tls_verbose_logging\n        if tls_ciphers:\n            self.tls_ciphers = AcceptableCiphers.fromOpenSSLCipherString(tls_ciphers)\n        else:\n            self.tls_ciphers = DEFAULT_CIPHERS\n\n    @classmethod\n    def from_settings(cls, settings, method=SSL.SSLv23_METHOD, *args, **kwargs):\n        tls_verbose_logging = settings.getbool('DOWNLOADER_CLIENT_TLS_VERBOSE_LOGGING')\n        tls_ciphers = settings['DOWNLOADER_CLIENT_TLS_CIPHERS']\n        return cls(method=method, tls_verbose_logging=tls_verbose_logging, tls_ciphers=tls_ciphers, *args, **kwargs)\n\n    def getCertificateOptions(self):\n        # setting verify=True will require you to provide CAs\n        # to verify against; in other words: it's not that simple\n\n        # backward-compatible SSL/TLS method:\n        #\n        # * this will respect `method` attribute in often recommended\n        #   `ScrapyClientContextFactory` subclass\n        #   (https://github.com/scrapy/scrapy/issues/1429#issuecomment-131782133)\n        #\n        # * getattr() for `_ssl_method` attribute for context factories\n        #   not calling super().__init__\n        return CertificateOptions(\n            verify=False,\n            method=getattr(self, 'method', getattr(self, '_ssl_method', None)),\n            fixBrokenPeers=True,\n            acceptableCiphers=self.tls_ciphers,\n        )\n\n    # kept for old-style HTTP/1.0 downloader context twisted calls,\n    # e.g. connectSSL()\n    def getContext(self, hostname=None, port=None):\n        return self.getCertificateOptions().getContext()\n\n    def creatorForNetloc(self, hostname, port):\n        return ScrapyClientTLSOptions(hostname.decode(\"ascii\"), self.getContext(),\n                                      verbose_logging=self.tls_verbose_logging)\n\n\n@implementer(IPolicyForHTTPS)\nclass BrowserLikeContextFactory(ScrapyClientContextFactory):\n    \"\"\"\n    Twisted-recommended context factory for web clients.\n\n    Quoting the documentation of the :class:`~twisted.web.client.Agent` class:\n\n        The default is to use a\n        :class:`~twisted.web.client.BrowserLikePolicyForHTTPS`, so unless you\n        have special requirements you can leave this as-is.\n\n    :meth:`creatorForNetloc` is the same as\n    :class:`~twisted.web.client.BrowserLikePolicyForHTTPS` except this context\n    factory allows setting the TLS/SSL method to use.\n\n    The default OpenSSL method is ``TLS_METHOD`` (also called\n    ``SSLv23_METHOD``) which allows TLS protocol negotiation.\n    \"\"\"\n\n    def creatorForNetloc(self, hostname, port):\n        # trustRoot set to platformTrust() will use the platform's root CAs.\n        #\n        # This means that a website like https://www.cacert.org will be rejected\n        # by default, since CAcert.org CA certificate is seldom shipped.\n        return optionsForClientTLS(\n            hostname=hostname.decode(\"ascii\"),\n            trustRoot=platformTrust(),\n            extraCertificateOptions={'method': self._ssl_method},\n        )\n\n\n@implementer(IPolicyForHTTPS)\nclass AcceptableProtocolsContextFactory:\n    \"\"\"Context factory to used to override the acceptable protocols\n    to set up the [OpenSSL.SSL.Context] for doing NPN and/or ALPN\n    negotiation.\n    \"\"\"\n\n    def __init__(self, context_factory, acceptable_protocols):\n        verifyObject(IPolicyForHTTPS, context_factory)\n        self._wrapped_context_factory = context_factory\n        self._acceptable_protocols = acceptable_protocols\n\n    def creatorForNetloc(self, hostname, port):\n        options = self._wrapped_context_factory.creatorForNetloc(hostname, port)\n        _setAcceptableProtocols(options._ctx, self._acceptable_protocols)\n        return options\n\n\ndef load_context_factory_from_settings(settings, crawler):\n    ssl_method = openssl_methods[settings.get('DOWNLOADER_CLIENT_TLS_METHOD')]\n    context_factory_cls = load_object(settings['DOWNLOADER_CLIENTCONTEXTFACTORY'])\n    # try method-aware context factory\n    try:\n        context_factory = create_instance(\n            objcls=context_factory_cls,\n            settings=settings,\n            crawler=crawler,\n            method=ssl_method,\n        )\n    except TypeError:\n        # use context factory defaults\n        context_factory = create_instance(\n            objcls=context_factory_cls,\n            settings=settings,\n            crawler=crawler,\n        )\n        msg = (\n            f\"{settings['DOWNLOADER_CLIENTCONTEXTFACTORY']} does not accept \"\n            \"a `method` argument (type OpenSSL.SSL method, e.g. \"\n            \"OpenSSL.SSL.SSLv23_METHOD) and/or a `tls_verbose_logging` \"\n            \"argument and/or a `tls_ciphers` argument. Please, upgrade your \"\n            \"context factory class to handle them or ignore them.\"\n        )\n        warnings.warn(msg)\n\n    return context_factory\n", "path": "scrapy/core/downloader/contextfactory.py"}], "after_files": [{"content": "import OpenSSL.SSL\nimport OpenSSL._util as pyOpenSSLutil\n\nfrom scrapy.utils.python import to_unicode\n\n\ndef ffi_buf_to_string(buf):\n    return to_unicode(pyOpenSSLutil.ffi.string(buf))\n\n\ndef x509name_to_string(x509name):\n    # from OpenSSL.crypto.X509Name.__repr__\n    result_buffer = pyOpenSSLutil.ffi.new(\"char[]\", 512)\n    pyOpenSSLutil.lib.X509_NAME_oneline(x509name._name, result_buffer, len(result_buffer))\n\n    return ffi_buf_to_string(result_buffer)\n\n\ndef get_temp_key_info(ssl_object):\n    # adapted from OpenSSL apps/s_cb.c::ssl_print_tmp_key()\n    temp_key_p = pyOpenSSLutil.ffi.new(\"EVP_PKEY **\")\n    if not pyOpenSSLutil.lib.SSL_get_server_tmp_key(ssl_object, temp_key_p):\n        return None\n    temp_key = temp_key_p[0]\n    if temp_key == pyOpenSSLutil.ffi.NULL:\n        return None\n    temp_key = pyOpenSSLutil.ffi.gc(temp_key, pyOpenSSLutil.lib.EVP_PKEY_free)\n    key_info = []\n    key_type = pyOpenSSLutil.lib.EVP_PKEY_id(temp_key)\n    if key_type == pyOpenSSLutil.lib.EVP_PKEY_RSA:\n        key_info.append('RSA')\n    elif key_type == pyOpenSSLutil.lib.EVP_PKEY_DH:\n        key_info.append('DH')\n    elif key_type == pyOpenSSLutil.lib.EVP_PKEY_EC:\n        key_info.append('ECDH')\n        ec_key = pyOpenSSLutil.lib.EVP_PKEY_get1_EC_KEY(temp_key)\n        ec_key = pyOpenSSLutil.ffi.gc(ec_key, pyOpenSSLutil.lib.EC_KEY_free)\n        nid = pyOpenSSLutil.lib.EC_GROUP_get_curve_name(pyOpenSSLutil.lib.EC_KEY_get0_group(ec_key))\n        cname = pyOpenSSLutil.lib.EC_curve_nid2nist(nid)\n        if cname == pyOpenSSLutil.ffi.NULL:\n            cname = pyOpenSSLutil.lib.OBJ_nid2sn(nid)\n        key_info.append(ffi_buf_to_string(cname))\n    else:\n        key_info.append(ffi_buf_to_string(pyOpenSSLutil.lib.OBJ_nid2sn(key_type)))\n    key_info.append(f'{pyOpenSSLutil.lib.EVP_PKEY_bits(temp_key)} bits')\n    return ', '.join(key_info)\n\n\ndef get_openssl_version():\n    system_openssl = OpenSSL.SSL.SSLeay_version(\n        OpenSSL.SSL.SSLEAY_VERSION\n    ).decode('ascii', errors='replace')\n    return f'{OpenSSL.version.__version__} ({system_openssl})'\n", "path": "scrapy/utils/ssl.py"}, {"content": "import logging\n\nfrom OpenSSL import SSL\nfrom service_identity.exceptions import CertificateError\nfrom twisted.internet._sslverify import ClientTLSOptions, verifyHostname, VerificationError\nfrom twisted.internet.ssl import AcceptableCiphers\n\nfrom scrapy.utils.ssl import x509name_to_string, get_temp_key_info\n\nlogger = logging.getLogger(__name__)\n\n\nMETHOD_TLS = 'TLS'\nMETHOD_TLSv10 = 'TLSv1.0'\nMETHOD_TLSv11 = 'TLSv1.1'\nMETHOD_TLSv12 = 'TLSv1.2'\n\n\nopenssl_methods = {\n    METHOD_TLS: SSL.SSLv23_METHOD,      # protocol negotiation (recommended)\n    METHOD_TLSv10: SSL.TLSv1_METHOD,    # TLS 1.0 only\n    METHOD_TLSv11: SSL.TLSv1_1_METHOD,  # TLS 1.1 only\n    METHOD_TLSv12: SSL.TLSv1_2_METHOD,  # TLS 1.2 only\n}\n\n\nclass ScrapyClientTLSOptions(ClientTLSOptions):\n    \"\"\"\n    SSL Client connection creator ignoring certificate verification errors\n    (for genuinely invalid certificates or bugs in verification code).\n\n    Same as Twisted's private _sslverify.ClientTLSOptions,\n    except that VerificationError, CertificateError and ValueError\n    exceptions are caught, so that the connection is not closed, only\n    logging warnings. Also, HTTPS connection parameters logging is added.\n    \"\"\"\n\n    def __init__(self, hostname, ctx, verbose_logging=False):\n        super().__init__(hostname, ctx)\n        self.verbose_logging = verbose_logging\n\n    def _identityVerifyingInfoCallback(self, connection, where, ret):\n        if where & SSL.SSL_CB_HANDSHAKE_START:\n            connection.set_tlsext_host_name(self._hostnameBytes)\n        elif where & SSL.SSL_CB_HANDSHAKE_DONE:\n            if self.verbose_logging:\n                logger.debug('SSL connection to %s using protocol %s, cipher %s',\n                             self._hostnameASCII,\n                             connection.get_protocol_version_name(),\n                             connection.get_cipher_name(),\n                             )\n                server_cert = connection.get_peer_certificate()\n                logger.debug('SSL connection certificate: issuer \"%s\", subject \"%s\"',\n                             x509name_to_string(server_cert.get_issuer()),\n                             x509name_to_string(server_cert.get_subject()),\n                             )\n                key_info = get_temp_key_info(connection._ssl)\n                if key_info:\n                    logger.debug('SSL temp key: %s', key_info)\n\n            try:\n                verifyHostname(connection, self._hostnameASCII)\n            except (CertificateError, VerificationError) as e:\n                logger.warning(\n                    'Remote certificate is not valid for hostname \"%s\"; %s',\n                    self._hostnameASCII, e)\n\n            except ValueError as e:\n                logger.warning(\n                    'Ignoring error while verifying certificate '\n                    'from host \"%s\" (exception: %r)',\n                    self._hostnameASCII, e)\n\n\nDEFAULT_CIPHERS = AcceptableCiphers.fromOpenSSLCipherString('DEFAULT')\n", "path": "scrapy/core/downloader/tls.py"}, {"content": "import warnings\n\nfrom OpenSSL import SSL\nfrom twisted.internet._sslverify import _setAcceptableProtocols\nfrom twisted.internet.ssl import optionsForClientTLS, CertificateOptions, platformTrust, AcceptableCiphers\nfrom twisted.web.client import BrowserLikePolicyForHTTPS\nfrom twisted.web.iweb import IPolicyForHTTPS\nfrom zope.interface.declarations import implementer\nfrom zope.interface.verify import verifyObject\n\nfrom scrapy.core.downloader.tls import DEFAULT_CIPHERS, openssl_methods, ScrapyClientTLSOptions\nfrom scrapy.utils.misc import create_instance, load_object\n\n\n@implementer(IPolicyForHTTPS)\nclass ScrapyClientContextFactory(BrowserLikePolicyForHTTPS):\n    \"\"\"\n    Non-peer-certificate verifying HTTPS context factory\n\n    Default OpenSSL method is TLS_METHOD (also called SSLv23_METHOD)\n    which allows TLS protocol negotiation\n\n    'A TLS/SSL connection established with [this method] may\n     understand the TLSv1, TLSv1.1 and TLSv1.2 protocols.'\n    \"\"\"\n\n    def __init__(self, method=SSL.SSLv23_METHOD, tls_verbose_logging=False, tls_ciphers=None, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self._ssl_method = method\n        self.tls_verbose_logging = tls_verbose_logging\n        if tls_ciphers:\n            self.tls_ciphers = AcceptableCiphers.fromOpenSSLCipherString(tls_ciphers)\n        else:\n            self.tls_ciphers = DEFAULT_CIPHERS\n\n    @classmethod\n    def from_settings(cls, settings, method=SSL.SSLv23_METHOD, *args, **kwargs):\n        tls_verbose_logging = settings.getbool('DOWNLOADER_CLIENT_TLS_VERBOSE_LOGGING')\n        tls_ciphers = settings['DOWNLOADER_CLIENT_TLS_CIPHERS']\n        return cls(method=method, tls_verbose_logging=tls_verbose_logging, tls_ciphers=tls_ciphers, *args, **kwargs)\n\n    def getCertificateOptions(self):\n        # setting verify=True will require you to provide CAs\n        # to verify against; in other words: it's not that simple\n\n        # backward-compatible SSL/TLS method:\n        #\n        # * this will respect `method` attribute in often recommended\n        #   `ScrapyClientContextFactory` subclass\n        #   (https://github.com/scrapy/scrapy/issues/1429#issuecomment-131782133)\n        #\n        # * getattr() for `_ssl_method` attribute for context factories\n        #   not calling super().__init__\n        return CertificateOptions(\n            verify=False,\n            method=getattr(self, 'method', getattr(self, '_ssl_method', None)),\n            fixBrokenPeers=True,\n            acceptableCiphers=self.tls_ciphers,\n        )\n\n    # kept for old-style HTTP/1.0 downloader context twisted calls,\n    # e.g. connectSSL()\n    def getContext(self, hostname=None, port=None):\n        ctx = self.getCertificateOptions().getContext()\n        ctx.set_options(0x4)  # OP_LEGACY_SERVER_CONNECT\n        return ctx\n\n    def creatorForNetloc(self, hostname, port):\n        return ScrapyClientTLSOptions(hostname.decode(\"ascii\"), self.getContext(),\n                                      verbose_logging=self.tls_verbose_logging)\n\n\n@implementer(IPolicyForHTTPS)\nclass BrowserLikeContextFactory(ScrapyClientContextFactory):\n    \"\"\"\n    Twisted-recommended context factory for web clients.\n\n    Quoting the documentation of the :class:`~twisted.web.client.Agent` class:\n\n        The default is to use a\n        :class:`~twisted.web.client.BrowserLikePolicyForHTTPS`, so unless you\n        have special requirements you can leave this as-is.\n\n    :meth:`creatorForNetloc` is the same as\n    :class:`~twisted.web.client.BrowserLikePolicyForHTTPS` except this context\n    factory allows setting the TLS/SSL method to use.\n\n    The default OpenSSL method is ``TLS_METHOD`` (also called\n    ``SSLv23_METHOD``) which allows TLS protocol negotiation.\n    \"\"\"\n\n    def creatorForNetloc(self, hostname, port):\n        # trustRoot set to platformTrust() will use the platform's root CAs.\n        #\n        # This means that a website like https://www.cacert.org will be rejected\n        # by default, since CAcert.org CA certificate is seldom shipped.\n        return optionsForClientTLS(\n            hostname=hostname.decode(\"ascii\"),\n            trustRoot=platformTrust(),\n            extraCertificateOptions={'method': self._ssl_method},\n        )\n\n\n@implementer(IPolicyForHTTPS)\nclass AcceptableProtocolsContextFactory:\n    \"\"\"Context factory to used to override the acceptable protocols\n    to set up the [OpenSSL.SSL.Context] for doing NPN and/or ALPN\n    negotiation.\n    \"\"\"\n\n    def __init__(self, context_factory, acceptable_protocols):\n        verifyObject(IPolicyForHTTPS, context_factory)\n        self._wrapped_context_factory = context_factory\n        self._acceptable_protocols = acceptable_protocols\n\n    def creatorForNetloc(self, hostname, port):\n        options = self._wrapped_context_factory.creatorForNetloc(hostname, port)\n        _setAcceptableProtocols(options._ctx, self._acceptable_protocols)\n        return options\n\n\ndef load_context_factory_from_settings(settings, crawler):\n    ssl_method = openssl_methods[settings.get('DOWNLOADER_CLIENT_TLS_METHOD')]\n    context_factory_cls = load_object(settings['DOWNLOADER_CLIENTCONTEXTFACTORY'])\n    # try method-aware context factory\n    try:\n        context_factory = create_instance(\n            objcls=context_factory_cls,\n            settings=settings,\n            crawler=crawler,\n            method=ssl_method,\n        )\n    except TypeError:\n        # use context factory defaults\n        context_factory = create_instance(\n            objcls=context_factory_cls,\n            settings=settings,\n            crawler=crawler,\n        )\n        msg = (\n            f\"{settings['DOWNLOADER_CLIENTCONTEXTFACTORY']} does not accept \"\n            \"a `method` argument (type OpenSSL.SSL method, e.g. \"\n            \"OpenSSL.SSL.SSLv23_METHOD) and/or a `tls_verbose_logging` \"\n            \"argument and/or a `tls_ciphers` argument. Please, upgrade your \"\n            \"context factory class to handle them or ignore them.\"\n        )\n        warnings.warn(msg)\n\n    return context_factory\n", "path": "scrapy/core/downloader/contextfactory.py"}]}