]>
git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/cherrypy_backports.py
1 # -*- coding: utf-8 -*-
3 Copyright © 2004-2019, CherryPy Team (team@cherrypy.org)
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions are met:
12 * Redistributions of source code must retain the above copyright notice, this
13 list of conditions and the following disclaimer.
15 * Redistributions in binary form must reproduce the above copyright notice,
16 this list of conditions and the following disclaimer in the documentation
17 and/or other materials provided with the distribution.
19 * Neither the name of CherryPy nor the names of its
20 contributors may be used to endorse or promote products derived from
21 this software without specific prior written permission.
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
27 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 from distutils
.version
import StrictVersion
37 # The SSL code in CherryPy 3.5.0 is buggy. It was fixed long ago,
38 # but 3.5.0 is still shipping in major linux distributions
39 # (Fedora 27, Ubuntu Xenial), so we must monkey patch it to get SSL working.
42 def patch_http_connection_init(v
):
43 # It was fixed in 3.7.0. Exact lower bound version is probably earlier,
44 # but 3.5.0 is what this monkey patch is tested on.
45 if StrictVersion("3.5.0") <= v
< StrictVersion("3.7.0"):
46 from cherrypy
.wsgiserver
.wsgiserver2
import \
47 HTTPConnection
, CP_fileobject
49 def fixed_init(hc_self
, server
, sock
, makefile
=CP_fileobject
):
50 hc_self
.server
= server
52 hc_self
.rfile
= makefile(sock
, "rb", hc_self
.rbufsize
)
53 hc_self
.wfile
= makefile(sock
, "wb", hc_self
.wbufsize
)
54 hc_self
.requests_seen
= 0
56 HTTPConnection
.__init
__ = fixed_init
59 # When the CherryPy server in 3.2.2 (and later) starts it attempts to verify
60 # that the ports its listening on are in fact bound. When using the any address
61 # "::" it tries both ipv4 and ipv6, and in some environments (e.g. kubernetes)
62 # ipv6 isn't yet configured / supported and CherryPy throws an uncaught
64 def skip_wait_for_occupied_port(v
):
65 # the issue was fixed in 3.2.3. it's present in 3.2.2 (current version on
66 # centos:7) and back to at least 3.0.0.
67 if StrictVersion("3.1.2") <= v
< StrictVersion("3.2.3"):
68 # https://github.com/cherrypy/cherrypy/issues/1100
69 from cherrypy
.process
import servers
70 servers
.wait_for_occupied_port
= lambda host
, port
: None
73 # cherrypy.wsgiserver was extracted wsgiserver into cheroot in cherrypy v9.0.0
74 def patch_builtin_ssl_wrap(v
, new_wrap
):
75 if v
< StrictVersion("9.0.0"):
76 from cherrypy
.wsgiserver
.ssl_builtin
import BuiltinSSLAdapter
as builtin_ssl
78 from cheroot
.ssl
.builtin
import BuiltinSSLAdapter
as builtin_ssl
79 builtin_ssl
.wrap
= new_wrap(builtin_ssl
.wrap
)
82 def accept_exceptions_from_builtin_ssl(v
):
83 # the fix was included by cheroot v5.2.0, which was included by cherrypy
85 if v
< StrictVersion("10.2.0"):
86 # see https://github.com/cherrypy/cheroot/pull/4
89 def accept_ssl_errors(func
):
90 def wrapper(self
, sock
):
92 return func(self
, sock
)
93 except ssl
.SSLError
as e
:
94 if e
.errno
== ssl
.SSL_ERROR_SSL
:
95 # Check if it's one of the known errors
96 # Errors that are caught by PyOpenSSL, but thrown by
98 _block_errors
= ('unknown protocol', 'unknown ca',
99 'unknown_ca', 'inappropriate fallback',
100 'wrong version number',
101 'no shared cipher', 'certificate unknown',
102 'ccs received early')
103 for error_text
in _block_errors
:
104 if error_text
in e
.args
[1].lower():
105 # Accepted error, let's pass
109 patch_builtin_ssl_wrap(v
, accept_ssl_errors
)
112 def accept_socket_error_0(v
):
113 # see https://github.com/cherrypy/cherrypy/issues/1618
116 cheroot_version
= cheroot
.__version
__
120 if v
< StrictVersion("9.0.0") or cheroot_version
< StrictVersion("6.5.5"):
123 generic_socket_error
= OSError
126 generic_socket_error
= socket
.error
128 def accept_socket_error_0(func
):
129 def wrapper(self
, sock
):
131 return func(self
, sock
)
132 except generic_socket_error
as e
:
133 """It is unclear why exactly this happens.
135 It's reproducible only with openssl>1.0 and stdlib ``ssl`` wrapper.
136 In CherryPy it's triggered by Checker plugin, which connects
137 to the app listening to the socket port in TLS mode via plain
138 HTTP during startup (from the same process).
140 Ref: https://github.com/cherrypy/cherrypy/issues/1618
143 is_error0
= e
.args
== (0, 'Error')
144 IS_ABOVE_OPENSSL10
= ssl
.OPENSSL_VERSION_INFO
>= (1, 1)
146 if is_error0
and IS_ABOVE_OPENSSL10
:
150 patch_builtin_ssl_wrap(v
, accept_socket_error_0
)
153 def patch_request_unique_id(v
):
155 Older versions of cherrypy don't include request.unique_id field (a lazily
158 Monkey-patching is preferred over alternatives as inheritance, as it'd break
159 type checks (cherrypy/lib/cgtools.py: `isinstance(obj, _cprequest.Request)`)
161 if v
< StrictVersion('11.1.0'):
163 from functools
import update_wrapper
164 from cherrypy
._cprequest
import Request
166 class LazyUUID4(object):
168 """Return UUID4 and keep it for future calls."""
169 return str(self
.uuid4
)
173 """Provide unique id on per-request basis using UUID4.
174 It's evaluated lazily on render.
177 self
._uuid
4 # type: ignore
178 except AttributeError:
179 # evaluate on first access
180 self
._uuid
4 = uuid
.uuid4()
184 old_init
= Request
.__init
__
186 def init_with_unique_id(self
, *args
, **kwargs
):
187 old_init(self
, *args
, **kwargs
)
188 self
.unique_id
= LazyUUID4()
190 Request
.__init
__ = update_wrapper(init_with_unique_id
, old_init
)
193 def patch_cherrypy(v
):
194 patch_http_connection_init(v
)
195 skip_wait_for_occupied_port(v
)
196 accept_exceptions_from_builtin_ssl(v
)
197 accept_socket_error_0(v
)
198 patch_request_unique_id(v
)