Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
erp5
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Binh
erp5
Commits
f33ea934
Commit
f33ea934
authored
Apr 17, 2019
by
Bryton Lacquement
🚪
Committed by
Julien Muchembled
Jun 24, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
patches: make the WSGIPublisher backport work with Zope 2.13
Parts of ZPublisher.utils are also backported.
parent
81c8663f
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
158 additions
and
42 deletions
+158
-42
product/ERP5Type/ZopePatch.py
product/ERP5Type/ZopePatch.py
+1
-0
product/ERP5Type/patches/WSGIPublisher.py
product/ERP5Type/patches/WSGIPublisher.py
+157
-42
No files found.
product/ERP5Type/ZopePatch.py
View file @
f33ea934
...
@@ -21,6 +21,7 @@
...
@@ -21,6 +21,7 @@
##############################################################################
##############################################################################
# Load all monkey patches
# Load all monkey patches
from
Products.ERP5Type.patches
import
WSGIPublisher
from
Products.ERP5Type.patches
import
HTTPRequest
from
Products.ERP5Type.patches
import
HTTPRequest
from
Products.ERP5Type.patches
import
AccessControl_patch
from
Products.ERP5Type.patches
import
AccessControl_patch
from
Products.ERP5Type.patches
import
Restricted
from
Products.ERP5Type.patches
import
Restricted
...
...
product/ERP5Type/patches/WSGIPublisher.py
View file @
f33ea934
# Backport from Zope4
# Backport
(with modified code)
from Zope4
##############################################################################
##############################################################################
#
#
...
@@ -19,16 +19,22 @@ from contextlib import closing
...
@@ -19,16 +19,22 @@ from contextlib import closing
from
contextlib
import
contextmanager
from
contextlib
import
contextmanager
from
io
import
BytesIO
from
io
import
BytesIO
from
io
import
IOBase
from
io
import
IOBase
import
logging
from
six
import
binary_type
from
six
import
PY3
from
six
import
PY3
from
six
import
reraise
from
six
import
reraise
from
six
import
text_type
from
six.moves._thread
import
allocate_lock
from
six.moves._thread
import
allocate_lock
import
transaction
import
transaction
from
AccessControl.SecurityManagement
import
newSecurityManager
from
AccessControl.SecurityManagement
import
newSecurityManager
from
AccessControl.SecurityManagement
import
noSecurityManager
from
AccessControl.SecurityManagement
import
noSecurityManager
from
Acquisition
import
aq_acquire
from
Acquisition
import
aq_acquire
from
Acquisition
import
aq_inner
from
Acquisition
import
aq_parent
from
transaction.interfaces
import
TransientError
from
transaction.interfaces
import
TransientError
from
zExceptions
import
Redirect
from
zExceptions
import
Unauthorized
from
zExceptions
import
Unauthorized
from
zExceptions
import
upgradeException
from
zExceptions
import
upgradeException
from
zope.component
import
queryMultiAdapter
from
zope.component
import
queryMultiAdapter
...
@@ -38,12 +44,12 @@ from zope.globalrequest import setRequest
...
@@ -38,12 +44,12 @@ from zope.globalrequest import setRequest
from
zope.publisher.skinnable
import
setDefaultSkin
from
zope.publisher.skinnable
import
setDefaultSkin
from
zope.security.management
import
endInteraction
from
zope.security.management
import
endInteraction
from
zope.security.management
import
newInteraction
from
zope.security.management
import
newInteraction
from
Z
Publisher
import
pubevents
from
Z
ope2.App.startup
import
validated_hook
from
ZPublisher
.HTTPRequest
import
WSGIRequest
from
ZPublisher
import
pubevents
,
Retry
from
ZPublisher.HTTPRe
sponse
import
WSGIResponse
from
ZPublisher.HTTPRe
quest
import
HTTPRequest
from
ZPublisher.Iterators
import
IUnboundStreamIterator
from
ZPublisher.Iterators
import
IUnboundStreamIterator
from
ZPublisher.mapply
import
mapply
from
ZPublisher.mapply
import
mapply
from
ZPublisher.
utils
import
recordMetaData
from
ZPublisher.
WSGIPublisher
import
call_object
,
missing_name
,
WSGIResponse
if
sys
.
version_info
>=
(
3
,
):
if
sys
.
version_info
>=
(
3
,
):
...
@@ -57,32 +63,113 @@ _MODULE_LOCK = allocate_lock()
...
@@ -57,32 +63,113 @@ _MODULE_LOCK = allocate_lock()
_MODULES
=
{}
_MODULES
=
{}
def
call_object
(
obj
,
args
,
request
):
AC_LOGGER
=
logging
.
getLogger
(
'event.AccessControl'
)
return
obj
(
*
args
)
if
1
:
# upstream moved WSGIResponse to HTTPResponse.py
def
dont_publish_class
(
klass
,
request
):
# According to PEP 333, WSGI applications and middleware are forbidden from
request
.
response
.
forbiddenError
(
"class %s"
%
klass
.
__name__
)
# using HTTP/1.1 "hop-by-hop" features or headers. This patch prevents Zope
# from sending 'Connection' and 'Transfer-Encoding' headers.
def
finalize
(
self
):
headers
=
self
.
headers
body
=
self
.
body
# <patch>
# There's a bug in 'App.ImageFile.index_html': when it returns a 304 status
# code, 'Content-Length' is equal to a nonzero value.
if
self
.
status
==
304
:
headers
.
pop
(
'content-length'
,
None
)
# Force the removal of "hop-by-hop" headers
headers
.
pop
(
'Connection'
,
None
)
# </patch>
# set 204 (no content) status if 200 and response is empty
# and not streaming
if
(
'content-type'
not
in
headers
and
'content-length'
not
in
headers
and
not
self
.
_streaming
and
self
.
status
==
200
):
self
.
setStatus
(
'nocontent'
)
# add content length if not streaming
content_length
=
headers
.
get
(
'content-length'
)
if
content_length
is
None
and
not
self
.
_streaming
:
self
.
setHeader
(
'content-length'
,
len
(
body
))
# <patch>
# backport from Zope 4.0b1
# (see commit be5b14bd858da787c41a39e2533b0aabcd246fd5)
# </patch>
return
'%s %s'
%
(
self
.
status
,
self
.
errmsg
),
self
.
listHeaders
()
WSGIResponse
.
finalize
=
finalize
def
missing_name
(
name
,
request
):
if
name
==
'self'
:
return
request
[
'PARENTS'
][
0
]
request
.
response
.
badRequestError
(
name
)
# From ZPublisher.utils
def
recordMetaData
(
object
,
request
):
if
hasattr
(
object
,
'getPhysicalPath'
):
path
=
'/'
.
join
(
object
.
getPhysicalPath
())
else
:
# Try hard to get the physical path of the object,
# but there are many circumstances where that's not possible.
to_append
=
()
def
validate_user
(
request
,
user
):
if
hasattr
(
object
,
'__self__'
)
and
hasattr
(
object
,
'__name__'
):
newSecurityManager
(
request
,
user
)
# object is a Python method.
to_append
=
(
object
.
__name__
,)
object
=
object
.
__self__
while
object
is
not
None
and
not
hasattr
(
object
,
'getPhysicalPath'
):
if
getattr
(
object
,
'__name__'
,
None
)
is
None
:
object
=
None
break
to_append
=
(
object
.
__name__
,)
+
to_append
object
=
aq_parent
(
aq_inner
(
object
))
if
object
is
not
None
:
path
=
'/'
.
join
(
object
.
getPhysicalPath
()
+
to_append
)
else
:
# As Jim would say, "Waaaaaaaa!"
# This may cause problems with virtual hosts
# since the physical path is different from the path
# used to retrieve the object.
path
=
request
.
get
(
'PATH_INFO'
)
T
=
transaction
.
get
()
T
.
note
(
safe_unicode
(
path
))
auth_user
=
request
.
get
(
'AUTHENTICATED_USER'
,
None
)
if
auth_user
:
auth_folder
=
aq_parent
(
auth_user
)
if
auth_folder
is
None
:
AC_LOGGER
.
warning
(
'A user object of type %s has no aq_parent.'
,
type
(
auth_user
))
auth_path
=
request
.
get
(
'AUTHENTICATION_PATH'
)
else
:
auth_path
=
'/'
.
join
(
auth_folder
.
getPhysicalPath
()[
1
:
-
1
])
user_id
=
auth_user
.
getId
()
user_id
=
safe_unicode
(
user_id
)
if
user_id
else
u'None'
T
.
setUser
(
user_id
,
safe_unicode
(
auth_path
))
def
set_default_debug_mode
(
debug_mode
):
def
safe_unicode
(
value
):
global
_DEFAULT_DEBUG_MODE
if
isinstance
(
value
,
text_type
):
_DEFAULT_DEBUG_MODE
=
debug_mode
return
value
elif
isinstance
(
value
,
binary_type
):
try
:
value
=
text_type
(
value
,
'utf-8'
)
except
UnicodeDecodeError
:
value
=
value
.
decode
(
'utf-8'
,
'replace'
)
return
value
def
set_default_authentication_realm
(
realm
):
def
dont_publish_class
(
klass
,
request
):
global
_DEFAULT_REALM
request
.
response
.
forbiddenError
(
"class %s"
%
klass
.
__name__
)
_DEFAULT_REALM
=
realm
def
get_module_info
(
module_name
=
'Zope2'
):
def
get_module_info
(
module_name
=
'Zope2'
):
...
@@ -95,7 +182,8 @@ def get_module_info(module_name='Zope2'):
...
@@ -95,7 +182,8 @@ def get_module_info(module_name='Zope2'):
module
=
__import__
(
module_name
)
module
=
__import__
(
module_name
)
app
=
getattr
(
module
,
'bobo_application'
,
module
)
app
=
getattr
(
module
,
'bobo_application'
,
module
)
realm
=
_DEFAULT_REALM
if
_DEFAULT_REALM
is
not
None
else
module_name
realm
=
_DEFAULT_REALM
if
_DEFAULT_REALM
is
not
None
else
module_name
_MODULES
[
module_name
]
=
info
=
(
app
,
realm
,
_DEFAULT_DEBUG_MODE
)
error_hook
=
getattr
(
module
,
'zpublisher_exception_hook'
,
None
)
_MODULES
[
module_name
]
=
info
=
(
app
,
realm
,
_DEFAULT_DEBUG_MODE
,
error_hook
)
return
info
return
info
...
@@ -135,7 +223,7 @@ def _exc_view_created_response(exc, request, response):
...
@@ -135,7 +223,7 @@ def _exc_view_created_response(exc, request, response):
@
contextmanager
@
contextmanager
def
transaction_pubevents
(
request
,
response
,
tm
=
transaction
.
manager
):
def
transaction_pubevents
(
request
,
response
,
err_hook
,
tm
=
transaction
.
manager
):
try
:
try
:
setDefaultSkin
(
request
)
setDefaultSkin
(
request
)
newInteraction
()
newInteraction
()
...
@@ -166,21 +254,44 @@ def transaction_pubevents(request, response, tm=transaction.manager):
...
@@ -166,21 +254,44 @@ def transaction_pubevents(request, response, tm=transaction.manager):
if
request
.
environ
.
get
(
'x-wsgiorg.throw_errors'
,
False
):
if
request
.
environ
.
get
(
'x-wsgiorg.throw_errors'
,
False
):
reraise
(
*
exc_info
)
reraise
(
*
exc_info
)
# Handle exception view
if
err_hook
:
exc_view_created
=
_exc_view_created_response
(
parents
=
request
[
'PARENTS'
]
exc
,
request
,
response
)
if
parents
:
parents
=
parents
[
0
]
if
isinstance
(
exc
,
Unauthorized
):
retry
=
False
# _unauthorized modifies the response in-place. If this hook
try
:
# is used, an exception view for Unauthorized has to merge
try
:
# the state of the response and the exception instance.
r
=
err_hook
(
parents
,
request
,
*
exc_info
)
exc
.
setRealm
(
response
.
realm
)
assert
r
is
response
response
.
_unauthorized
()
exc_view_created
=
True
response
.
setStatus
(
exc
.
getStatus
())
except
Retry
:
if
request
.
supports_retry
():
retry
=
False
retry
=
True
if
isinstance
(
exc
,
TransientError
)
and
request
.
supports_retry
():
else
:
retry
=
True
r
=
err_hook
(
parents
,
request
,
*
sys
.
exc_info
())
assert
r
is
response
exc_view_created
=
True
except
(
Redirect
,
Unauthorized
):
response
.
exception
()
exc_view_created
=
True
except
BaseException
as
e
:
if
e
is
not
exc
:
raise
exc_view_created
=
False
else
:
# Handle exception view
exc_view_created
=
_exc_view_created_response
(
exc
,
request
,
response
)
if
isinstance
(
exc
,
Unauthorized
):
# _unauthorized modifies the response in-place. If this hook
# is used, an exception view for Unauthorized has to merge
# the state of the response and the exception instance.
exc
.
setRealm
(
response
.
realm
)
response
.
_unauthorized
()
response
.
setStatus
(
exc
.
getStatus
())
retry
=
isinstance
(
exc
,
TransientError
)
and
request
.
supports_retry
()
notify
(
pubevents
.
PubBeforeAbort
(
request
,
exc_info
,
retry
))
notify
(
pubevents
.
PubBeforeAbort
(
request
,
exc_info
,
retry
))
tm
.
abort
()
tm
.
abort
()
...
@@ -217,7 +328,7 @@ def publish(request, module_info):
...
@@ -217,7 +328,7 @@ def publish(request, module_info):
path
=
request
.
get
(
'PATH_INFO'
)
path
=
request
.
get
(
'PATH_INFO'
)
request
[
'PARENTS'
]
=
[
obj
]
request
[
'PARENTS'
]
=
[
obj
]
obj
=
request
.
traverse
(
path
,
validated_hook
=
validate
_user
)
obj
=
request
.
traverse
(
path
,
validated_hook
=
validate
d_hook
)
notify
(
pubevents
.
PubAfterTraversal
(
request
))
notify
(
pubevents
.
PubAfterTraversal
(
request
))
recordMetaData
(
obj
,
request
)
recordMetaData
(
obj
,
request
)
...
@@ -245,7 +356,7 @@ def load_app(module_info):
...
@@ -245,7 +356,7 @@ def load_app(module_info):
try
:
try
:
yield
(
app
,
realm
,
debug_mode
)
yield
(
app
,
realm
,
debug_mode
)
finally
:
finally
:
if
transaction
.
manager
.
manager
.
_txn
is
not
None
:
if
transaction
.
manager
.
_txn
is
not
None
:
# Only abort a transaction, if one exists. Otherwise the
# Only abort a transaction, if one exists. Otherwise the
# abort creates a new transaction just to abort it.
# abort creates a new transaction just to abort it.
transaction
.
abort
()
transaction
.
abort
()
...
@@ -257,9 +368,10 @@ def publish_module(environ, start_response,
...
@@ -257,9 +368,10 @@ def publish_module(environ, start_response,
_response
=
None
,
_response
=
None
,
_response_factory
=
WSGIResponse
,
_response_factory
=
WSGIResponse
,
_request
=
None
,
_request
=
None
,
_request_factory
=
WSGI
Request
,
_request_factory
=
HTTP
Request
,
_module_name
=
'Zope2'
):
_module_name
=
'Zope2'
):
module_info
=
get_module_info
(
_module_name
)
module_info
=
get_module_info
(
_module_name
)
module_info
,
err_hook
=
module_info
[:
3
],
module_info
[
3
]
result
=
()
result
=
()
path_info
=
environ
.
get
(
'PATH_INFO'
)
path_info
=
environ
.
get
(
'PATH_INFO'
)
...
@@ -294,7 +406,7 @@ def publish_module(environ, start_response,
...
@@ -294,7 +406,7 @@ def publish_module(environ, start_response,
setRequest
(
request
)
setRequest
(
request
)
try
:
try
:
with
load_app
(
module_info
)
as
new_mod_info
:
with
load_app
(
module_info
)
as
new_mod_info
:
with
transaction_pubevents
(
request
,
response
):
with
transaction_pubevents
(
request
,
response
,
err_hook
):
response
=
_publish
(
request
,
new_mod_info
)
response
=
_publish
(
request
,
new_mod_info
)
break
break
except
TransientError
:
except
TransientError
:
...
@@ -324,3 +436,6 @@ def publish_module(environ, start_response,
...
@@ -324,3 +436,6 @@ def publish_module(environ, start_response,
# Return the result body iterable.
# Return the result body iterable.
return
result
return
result
sys
.
modules
[
'ZPublisher.WSGIPublisher'
]
=
sys
.
modules
[
__name__
]
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment