We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
BrowserLikeContextFactory not available in some conditions
While tracing the error that lead to #2555 I tried the workaround [mentioned in the documentation](https://doc.scrapy.org/en/latest/topics/settings.html#downloader-clientcontextfactory) without success.

This code lives [incontextfactory.py](https://github.com/scrapy/scrapy/blob/c3411373e8a8ee2786588bdad7be469c69a25e2a/scrapy/core/downloader/contextfactory.py#L63) but was not reachable as the import was failing on my system due to #2555.

This file is a large `try/except` block with many potential points of failure and it's likely to trip other users in the future.
That said, could this be refactored to provide a fallback for `BrowserLikeContextFactory` or otherwise reduce the scope of the `try/except` to avoid breaking the API?

--- 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/core/downloader/contextfactory.py`
Content:
```
1 from OpenSSL import SSL
2 from twisted.internet.ssl import ClientContextFactory
3 
4 try:
5 
6     from zope.interface.declarations import implementer
7 
8     # the following should be available from Twisted 14.0.0
9     from twisted.internet.ssl import (optionsForClientTLS,
10                                       CertificateOptions,
11                                       platformTrust)
12 
13     from twisted.web.client import BrowserLikePolicyForHTTPS
14     from twisted.web.iweb import IPolicyForHTTPS
15 
16     from scrapy.core.downloader.tls import ScrapyClientTLSOptions, DEFAULT_CIPHERS
17 
18 
19     @implementer(IPolicyForHTTPS)
20     class ScrapyClientContextFactory(BrowserLikePolicyForHTTPS):
21         """
22         Non-peer-certificate verifying HTTPS context factory
23 
24         Default OpenSSL method is TLS_METHOD (also called SSLv23_METHOD)
25         which allows TLS protocol negotiation
26 
27         'A TLS/SSL connection established with [this method] may
28          understand the SSLv3, TLSv1, TLSv1.1 and TLSv1.2 protocols.'
29         """
30 
31         def __init__(self, method=SSL.SSLv23_METHOD, *args, **kwargs):
32             super(ScrapyClientContextFactory, self).__init__(*args, **kwargs)
33             self._ssl_method = method
34 
35         def getCertificateOptions(self):
36             # setting verify=True will require you to provide CAs
37             # to verify against; in other words: it's not that simple
38 
39             # backward-compatible SSL/TLS method:
40             #
41             # * this will respect `method` attribute in often recommended
42             #   `ScrapyClientContextFactory` subclass
43             #   (https://github.com/scrapy/scrapy/issues/1429#issuecomment-131782133)
44             #
45             # * getattr() for `_ssl_method` attribute for context factories
46             #   not calling super(..., self).__init__
47             return CertificateOptions(verify=False,
48                         method=getattr(self, 'method',
49                                        getattr(self, '_ssl_method', None)),
50                         fixBrokenPeers=True,
51                         acceptableCiphers=DEFAULT_CIPHERS)
52 
53         # kept for old-style HTTP/1.0 downloader context twisted calls,
54         # e.g. connectSSL()
55         def getContext(self, hostname=None, port=None):
56             return self.getCertificateOptions().getContext()
57 
58         def creatorForNetloc(self, hostname, port):
59             return ScrapyClientTLSOptions(hostname.decode("ascii"), self.getContext())
60 
61 
62     @implementer(IPolicyForHTTPS)
63     class BrowserLikeContextFactory(ScrapyClientContextFactory):
64         """
65         Twisted-recommended context factory for web clients.
66 
67         Quoting http://twistedmatrix.com/documents/current/api/twisted.web.client.Agent.html:
68         "The default is to use a BrowserLikePolicyForHTTPS,
69         so unless you have special requirements you can leave this as-is."
70 
71         creatorForNetloc() is the same as BrowserLikePolicyForHTTPS
72         except this context factory allows setting the TLS/SSL method to use.
73 
74         Default OpenSSL method is TLS_METHOD (also called SSLv23_METHOD)
75         which allows TLS protocol negotiation.
76         """
77         def creatorForNetloc(self, hostname, port):
78 
79             # trustRoot set to platformTrust() will use the platform's root CAs.
80             #
81             # This means that a website like https://www.cacert.org will be rejected
82             # by default, since CAcert.org CA certificate is seldom shipped.
83             return optionsForClientTLS(hostname.decode("ascii"),
84                                        trustRoot=platformTrust(),
85                                        extraCertificateOptions={
86                                             'method': self._ssl_method,
87                                        })
88 
89 except ImportError:
90 
91     class ScrapyClientContextFactory(ClientContextFactory):
92         "A SSL context factory which is more permissive against SSL bugs."
93         # see https://github.com/scrapy/scrapy/issues/82
94         # and https://github.com/scrapy/scrapy/issues/26
95         # and https://github.com/scrapy/scrapy/issues/981
96 
97         def __init__(self, method=SSL.SSLv23_METHOD):
98             self.method = method
99 
100         def getContext(self, hostname=None, port=None):
101             ctx = ClientContextFactory.getContext(self)
102             # Enable all workarounds to SSL bugs as documented by
103             # http://www.openssl.org/docs/ssl/SSL_CTX_set_options.html
104             ctx.set_options(SSL.OP_ALL)
105             return ctx
106
```
--- 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
@@ -1,15 +1,15 @@
 from OpenSSL import SSL
 from twisted.internet.ssl import ClientContextFactory
 
-try:
+from scrapy import twisted_version
+
+if twisted_version >= (14, 0, 0):
 
     from zope.interface.declarations import implementer
 
-    # the following should be available from Twisted 14.0.0
     from twisted.internet.ssl import (optionsForClientTLS,
                                       CertificateOptions,
                                       platformTrust)
-
     from twisted.web.client import BrowserLikePolicyForHTTPS
     from twisted.web.iweb import IPolicyForHTTPS
 
@@ -86,7 +86,7 @@
                                             'method': self._ssl_method,
                                        })
 
-except ImportError:
+else:
 
     class ScrapyClientContextFactory(ClientContextFactory):
         "A SSL context factory which is more permissive against SSL bugs."

{"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@@ -1,15 +1,15 @@\n from OpenSSL import SSL\n from twisted.internet.ssl import ClientContextFactory\n \n-try:\n+from scrapy import twisted_version\n+\n+if twisted_version >= (14, 0, 0):\n \n     from zope.interface.declarations import implementer\n \n-    # the following should be available from Twisted 14.0.0\n     from twisted.internet.ssl import (optionsForClientTLS,\n                                       CertificateOptions,\n                                       platformTrust)\n-\n     from twisted.web.client import BrowserLikePolicyForHTTPS\n     from twisted.web.iweb import IPolicyForHTTPS\n \n@@ -86,7 +86,7 @@\n                                             'method': self._ssl_method,\n                                        })\n \n-except ImportError:\n+else:\n \n     class ScrapyClientContextFactory(ClientContextFactory):\n         \"A SSL context factory which is more permissive against SSL bugs.\"\n", "issue": "BrowserLikeContextFactory not available in some conditions\nWhile tracing the error that lead to #2555 I tried the workaround [mentioned in the documentation](https://doc.scrapy.org/en/latest/topics/settings.html#downloader-clientcontextfactory) without success.\r\n\r\nThis code lives [incontextfactory.py](https://github.com/scrapy/scrapy/blob/c3411373e8a8ee2786588bdad7be469c69a25e2a/scrapy/core/downloader/contextfactory.py#L63) but was not reachable as the import was failing on my system due to #2555.\r\n\r\nThis file is a large `try/except` block with many potential points of failure and it's likely to trip other users in the future.\r\nThat said, could this be refactored to provide a fallback for `BrowserLikeContextFactory` or otherwise reduce the scope of the `try/except` to avoid breaking the API?\n", "before_files": [{"content": "from OpenSSL import SSL\nfrom twisted.internet.ssl import ClientContextFactory\n\ntry:\n\n    from zope.interface.declarations import implementer\n\n    # the following should be available from Twisted 14.0.0\n    from twisted.internet.ssl import (optionsForClientTLS,\n                                      CertificateOptions,\n                                      platformTrust)\n\n    from twisted.web.client import BrowserLikePolicyForHTTPS\n    from twisted.web.iweb import IPolicyForHTTPS\n\n    from scrapy.core.downloader.tls import ScrapyClientTLSOptions, DEFAULT_CIPHERS\n\n\n    @implementer(IPolicyForHTTPS)\n    class 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 SSLv3, TLSv1, TLSv1.1 and TLSv1.2 protocols.'\n        \"\"\"\n\n        def __init__(self, method=SSL.SSLv23_METHOD, *args, **kwargs):\n            super(ScrapyClientContextFactory, self).__init__(*args, **kwargs)\n            self._ssl_method = method\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(..., self).__init__\n            return CertificateOptions(verify=False,\n                        method=getattr(self, 'method',\n                                       getattr(self, '_ssl_method', None)),\n                        fixBrokenPeers=True,\n                        acceptableCiphers=DEFAULT_CIPHERS)\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\n\n    @implementer(IPolicyForHTTPS)\n    class BrowserLikeContextFactory(ScrapyClientContextFactory):\n        \"\"\"\n        Twisted-recommended context factory for web clients.\n\n        Quoting http://twistedmatrix.com/documents/current/api/twisted.web.client.Agent.html:\n        \"The default is to use a BrowserLikePolicyForHTTPS,\n        so unless you have special requirements you can leave this as-is.\"\n\n        creatorForNetloc() is the same as BrowserLikePolicyForHTTPS\n        except this context factory allows setting the TLS/SSL method to use.\n\n        Default OpenSSL method is TLS_METHOD (also called SSLv23_METHOD)\n        which allows TLS protocol negotiation.\n        \"\"\"\n        def creatorForNetloc(self, hostname, port):\n\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(hostname.decode(\"ascii\"),\n                                       trustRoot=platformTrust(),\n                                       extraCertificateOptions={\n                                            'method': self._ssl_method,\n                                       })\n\nexcept ImportError:\n\n    class ScrapyClientContextFactory(ClientContextFactory):\n        \"A SSL context factory which is more permissive against SSL bugs.\"\n        # see https://github.com/scrapy/scrapy/issues/82\n        # and https://github.com/scrapy/scrapy/issues/26\n        # and https://github.com/scrapy/scrapy/issues/981\n\n        def __init__(self, method=SSL.SSLv23_METHOD):\n            self.method = method\n\n        def getContext(self, hostname=None, port=None):\n            ctx = ClientContextFactory.getContext(self)\n            # Enable all workarounds to SSL bugs as documented by\n            # http://www.openssl.org/docs/ssl/SSL_CTX_set_options.html\n            ctx.set_options(SSL.OP_ALL)\n            return ctx\n", "path": "scrapy/core/downloader/contextfactory.py"}], "after_files": [{"content": "from OpenSSL import SSL\nfrom twisted.internet.ssl import ClientContextFactory\n\nfrom scrapy import twisted_version\n\nif twisted_version >= (14, 0, 0):\n\n    from zope.interface.declarations import implementer\n\n    from twisted.internet.ssl import (optionsForClientTLS,\n                                      CertificateOptions,\n                                      platformTrust)\n    from twisted.web.client import BrowserLikePolicyForHTTPS\n    from twisted.web.iweb import IPolicyForHTTPS\n\n    from scrapy.core.downloader.tls import ScrapyClientTLSOptions, DEFAULT_CIPHERS\n\n\n    @implementer(IPolicyForHTTPS)\n    class 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 SSLv3, TLSv1, TLSv1.1 and TLSv1.2 protocols.'\n        \"\"\"\n\n        def __init__(self, method=SSL.SSLv23_METHOD, *args, **kwargs):\n            super(ScrapyClientContextFactory, self).__init__(*args, **kwargs)\n            self._ssl_method = method\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(..., self).__init__\n            return CertificateOptions(verify=False,\n                        method=getattr(self, 'method',\n                                       getattr(self, '_ssl_method', None)),\n                        fixBrokenPeers=True,\n                        acceptableCiphers=DEFAULT_CIPHERS)\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\n\n    @implementer(IPolicyForHTTPS)\n    class BrowserLikeContextFactory(ScrapyClientContextFactory):\n        \"\"\"\n        Twisted-recommended context factory for web clients.\n\n        Quoting http://twistedmatrix.com/documents/current/api/twisted.web.client.Agent.html:\n        \"The default is to use a BrowserLikePolicyForHTTPS,\n        so unless you have special requirements you can leave this as-is.\"\n\n        creatorForNetloc() is the same as BrowserLikePolicyForHTTPS\n        except this context factory allows setting the TLS/SSL method to use.\n\n        Default OpenSSL method is TLS_METHOD (also called SSLv23_METHOD)\n        which allows TLS protocol negotiation.\n        \"\"\"\n        def creatorForNetloc(self, hostname, port):\n\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(hostname.decode(\"ascii\"),\n                                       trustRoot=platformTrust(),\n                                       extraCertificateOptions={\n                                            'method': self._ssl_method,\n                                       })\n\nelse:\n\n    class ScrapyClientContextFactory(ClientContextFactory):\n        \"A SSL context factory which is more permissive against SSL bugs.\"\n        # see https://github.com/scrapy/scrapy/issues/82\n        # and https://github.com/scrapy/scrapy/issues/26\n        # and https://github.com/scrapy/scrapy/issues/981\n\n        def __init__(self, method=SSL.SSLv23_METHOD):\n            self.method = method\n\n        def getContext(self, hostname=None, port=None):\n            ctx = ClientContextFactory.getContext(self)\n            # Enable all workarounds to SSL bugs as documented by\n            # http://www.openssl.org/docs/ssl/SSL_CTX_set_options.html\n            ctx.set_options(SSL.OP_ALL)\n            return ctx\n", "path": "scrapy/core/downloader/contextfactory.py"}]}