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
Joshua
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 @@
##############################################################################
# Load all monkey patches
from
Products.ERP5Type.patches
import
WSGIPublisher
from
Products.ERP5Type.patches
import
HTTPRequest
from
Products.ERP5Type.patches
import
AccessControl_patch
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
from
contextlib
import
contextmanager
from
io
import
BytesIO
from
io
import
IOBase
import
logging
from
six
import
binary_type
from
six
import
PY3
from
six
import
reraise
from
six
import
text_type
from
six.moves._thread
import
allocate_lock
import
transaction
from
AccessControl.SecurityManagement
import
newSecurityManager
from
AccessControl.SecurityManagement
import
noSecurityManager
from
Acquisition
import
aq_acquire
from
Acquisition
import
aq_inner
from
Acquisition
import
aq_parent
from
transaction.interfaces
import
TransientError
from
zExceptions
import
Redirect
from
zExceptions
import
Unauthorized
from
zExceptions
import
upgradeException
from
zope.component
import
queryMultiAdapter
...
...
@@ -38,12 +44,12 @@ from zope.globalrequest import setRequest
from
zope.publisher.skinnable
import
setDefaultSkin
from
zope.security.management
import
endInteraction
from
zope.security.management
import
newInteraction
from
Z
Publisher
import
pubevents
from
ZPublisher
.HTTPRequest
import
WSGIRequest
from
ZPublisher.HTTPRe
sponse
import
WSGIResponse
from
Z
ope2.App.startup
import
validated_hook
from
ZPublisher
import
pubevents
,
Retry
from
ZPublisher.HTTPRe
quest
import
HTTPRequest
from
ZPublisher.Iterators
import
IUnboundStreamIterator
from
ZPublisher.mapply
import
mapply
from
ZPublisher.
utils
import
recordMetaData
from
ZPublisher.
WSGIPublisher
import
call_object
,
missing_name
,
WSGIResponse
if
sys
.
version_info
>=
(
3
,
):
...
...
@@ -57,32 +63,113 @@ _MODULE_LOCK = allocate_lock()
_MODULES
=
{}
def
call_object
(
obj
,
args
,
request
):
return
obj
(
*
args
)
AC_LOGGER
=
logging
.
getLogger
(
'event.AccessControl'
)
if
1
:
# upstream moved WSGIResponse to HTTPResponse.py
def
dont_publish_class
(
klass
,
request
):
request
.
response
.
forbiddenError
(
"class %s"
%
klass
.
__name__
)
# According to PEP 333, WSGI applications and middleware are forbidden from
# 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
):
newSecurityManager
(
request
,
user
)
if
hasattr
(
object
,
'__self__'
)
and
hasattr
(
object
,
'__name__'
):
# 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
):
global
_DEFAULT_DEBUG_MODE
_DEFAULT_DEBUG_MODE
=
debug_mode
def
safe_unicode
(
value
):
if
isinstance
(
value
,
text_type
):
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
):
global
_DEFAULT_REALM
_DEFAULT_REALM
=
realm
def
dont_publish_class
(
klass
,
request
):
request
.
response
.
forbiddenError
(
"class %s"
%
klass
.
__name__
)
def
get_module_info
(
module_name
=
'Zope2'
):
...
...
@@ -95,7 +182,8 @@ def get_module_info(module_name='Zope2'):
module
=
__import__
(
module_name
)
app
=
getattr
(
module
,
'bobo_application'
,
module
)
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
...
...
@@ -135,7 +223,7 @@ def _exc_view_created_response(exc, request, response):
@
contextmanager
def
transaction_pubevents
(
request
,
response
,
tm
=
transaction
.
manager
):
def
transaction_pubevents
(
request
,
response
,
err_hook
,
tm
=
transaction
.
manager
):
try
:
setDefaultSkin
(
request
)
newInteraction
()
...
...
@@ -166,21 +254,44 @@ def transaction_pubevents(request, response, tm=transaction.manager):
if
request
.
environ
.
get
(
'x-wsgiorg.throw_errors'
,
False
):
reraise
(
*
exc_info
)
# 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
=
False
if
isinstance
(
exc
,
TransientError
)
and
request
.
supports_retry
():
retry
=
True
if
err_hook
:
parents
=
request
[
'PARENTS'
]
if
parents
:
parents
=
parents
[
0
]
retry
=
False
try
:
try
:
r
=
err_hook
(
parents
,
request
,
*
exc_info
)
assert
r
is
response
exc_view_created
=
True
except
Retry
:
if
request
.
supports_retry
():
retry
=
True
else
:
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
))
tm
.
abort
()
...
...
@@ -217,7 +328,7 @@ def publish(request, module_info):
path
=
request
.
get
(
'PATH_INFO'
)
request
[
'PARENTS'
]
=
[
obj
]
obj
=
request
.
traverse
(
path
,
validated_hook
=
validate
_user
)
obj
=
request
.
traverse
(
path
,
validated_hook
=
validate
d_hook
)
notify
(
pubevents
.
PubAfterTraversal
(
request
))
recordMetaData
(
obj
,
request
)
...
...
@@ -245,7 +356,7 @@ def load_app(module_info):
try
:
yield
(
app
,
realm
,
debug_mode
)
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
# abort creates a new transaction just to abort it.
transaction
.
abort
()
...
...
@@ -257,9 +368,10 @@ def publish_module(environ, start_response,
_response
=
None
,
_response_factory
=
WSGIResponse
,
_request
=
None
,
_request_factory
=
WSGI
Request
,
_request_factory
=
HTTP
Request
,
_module_name
=
'Zope2'
):
module_info
=
get_module_info
(
_module_name
)
module_info
,
err_hook
=
module_info
[:
3
],
module_info
[
3
]
result
=
()
path_info
=
environ
.
get
(
'PATH_INFO'
)
...
...
@@ -294,7 +406,7 @@ def publish_module(environ, start_response,
setRequest
(
request
)
try
:
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
)
break
except
TransientError
:
...
...
@@ -324,3 +436,6 @@ def publish_module(environ, start_response,
# Return the result body iterable.
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