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
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Xiaowu Zhang
erp5
Commits
92e81dd4
Commit
92e81dd4
authored
Feb 04, 2020
by
Vincent Pelletier
1
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ERP5Type.patches.Publish: Patch higher in the call stack.
Also covers traversal (and a lot more).
parent
c1deaaed
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
244 additions
and
86 deletions
+244
-86
product/ERP5Type/Timeout.py
product/ERP5Type/Timeout.py
+8
-18
product/ERP5Type/patches/Publish.py
product/ERP5Type/patches/Publish.py
+198
-30
product/ERP5Type/patches/WSGIPublisher.py
product/ERP5Type/patches/WSGIPublisher.py
+38
-38
No files found.
product/ERP5Type/Timeout.py
View file @
92e81dd4
##############################################################################
##############################################################################
# Copyright (c) 2019 Nexedi SA and Contributors. All Rights Reserved.
# Copyright (c) 2019
-2020
Nexedi SA and Contributors. All Rights Reserved.
# Kazuhiko <kazuhiko@nexedi.com>
# Kazuhiko <kazuhiko@nexedi.com>
# Vincent Pelletier <vincent@nexedi.com>
#
#
# WARNING: This program as such is intended to be used by professional
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# programmers who take the whole responsability of assessing all potential
...
@@ -33,7 +34,7 @@ from Products.TimerService.timerserver.TimerServer import TimerRequest
...
@@ -33,7 +34,7 @@ from Products.TimerService.timerserver.TimerServer import TimerRequest
__all__
=
(
__all__
=
(
'TimeoutReachedError'
,
'Deadline'
,
'getDeadline'
,
'getTimeLeft'
,
'TimeoutReachedError'
,
'Deadline'
,
'getDeadline'
,
'getTimeLeft'
,
'
wrap_call_object
'
,
'
getPublisherDeadlineValue
'
,
)
)
class
TimeoutReachedError
(
Exception
):
class
TimeoutReachedError
(
Exception
):
...
@@ -101,21 +102,10 @@ def getTimeLeft():
...
@@ -101,21 +102,10 @@ def getTimeLeft():
deadline
=
getattr
(
_site_local
,
'deadline'
,
None
)
deadline
=
getattr
(
_site_local
,
'deadline'
,
None
)
return
None
if
deadline
is
None
else
max
(
deadline
-
time
.
time
(),
0.000001
)
return
None
if
deadline
is
None
else
max
(
deadline
-
time
.
time
(),
0.000001
)
def
wrap_call_object
(
call_objec
t
):
def
getPublisherDeadlineValue
(
reques
t
):
"""
"""
Return argument wrapped so it is executed in a timeout context using
Return an instance of Deadline class suitable for publication.
publisher_timeout.
call_object (callable (object, args, request) -> any)
call_object-like function, which should be executed under a deadline based
on publisher_timeout value at call-time.
Dedline will not be applied if request is a TimerRequest instance, as these
requests are not strictly published, and hence do not fall under control of
the same setting.
"""
"""
def
deadlined_call_object
(
object
,
args
,
request
):
return
Deadline
(
with
Deadline
(
None
if
isinstance
(
request
,
TimerRequest
)
else
publisher_timeout
,
None
if
isinstance
(
request
,
TimerRequest
)
else
publisher_timeout
,
)
):
return
call_object
(
object
,
args
,
request
)
return
deadlined_call_object
product/ERP5Type/patches/Publish.py
View file @
92e81dd4
##############################################################################
##############################################################################
# Copyright (c) 2019 Nexedi SA and Contributors. All Rights Reserved.
# Kazuhiko <kazuhiko@nexedi.com>
#
#
# WARNING: This program as such is intended to be used by professional
# Copyright (c) 2002 Zope Foundation and Contributors.
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
#
# This program is Free Software; you can redistribute it and/or
# This software is subject to the provisions of the Zope Public License,
# modify it under the terms of the GNU General Public License
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# as published by the Free Software Foundation; either version 2
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# of the License, or (at your option) any later version.
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
#
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# This program is distributed in the hope that it will be useful,
# FOR A PARTICULAR PURPOSE
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
#
##############################################################################
##############################################################################
from
Products.ERP5Type.Timeout
import
wrap_call_object
from
Products.ERP5Type.Timeout
import
getPublisherDeadlineValue
from
ZPublisher
import
Publish
from
ZPublisher
import
Publish
from
ZPublisher.Publish
import
(
# Produced using:
# dis.dis(
# compile(open(<this_file>, 'r').read(), 'foo', 'exec').co_consts[
# <index of publish code object in co_consts>
# ]
# )
# and checking all uniques LOAD_GLOBAL names, excluding builtins and
# getPublisherDeadlineValue, and including publish parameter default
# values.
ISkinnable
,
PubAfterTraversal
,
PubBeforeAbort
,
PubBeforeCommit
,
PubFailure
,
PubStart
,
PubSuccess
,
Redirect
,
Retry
,
call_object
,
dont_publish_class
,
endInteraction
,
get_module_info
,
mapply
,
missing_name
,
newInteraction
,
notify
,
publish
,
setDefaultSkin
,
sys
,
urlparse
,
)
def
publish
(
request
,
module_name
,
after_list
,
debug
=
0
,
# Optimize:
call_object
=
call_object
,
missing_name
=
missing_name
,
dont_publish_class
=
dont_publish_class
,
mapply
=
mapply
,
):
(
bobo_before
,
bobo_after
,
object
,
realm
,
debug_mode
,
err_hook
,
validated_hook
,
transactions_manager
)
=
get_module_info
(
module_name
)
parents
=
None
response
=
None
try
:
with
getPublisherDeadlineValue
(
request
):
notify
(
PubStart
(
request
))
# TODO pass request here once BaseRequest implements IParticipation
newInteraction
()
request
.
processInputs
()
request_get
=
request
.
get
response
=
request
.
response
# First check for "cancel" redirect:
if
request_get
(
'SUBMIT'
,
''
).
strip
().
lower
()
==
'cancel'
:
cancel
=
request_get
(
'CANCEL_ACTION'
,
''
)
if
cancel
:
# Relative URLs aren't part of the spec, but are accepted by
# some browsers.
for
part
,
base
in
zip
(
urlparse
(
cancel
)[:
3
],
urlparse
(
request
[
'BASE1'
])[:
3
]):
if
not
part
:
continue
if
not
part
.
startswith
(
base
):
cancel
=
''
break
if
cancel
:
raise
Redirect
,
cancel
after_list
[
0
]
=
bobo_after
if
debug_mode
:
response
.
debug_mode
=
debug_mode
if
realm
and
not
request
.
get
(
'REMOTE_USER'
,
None
):
response
.
realm
=
realm
if
bobo_before
is
not
None
:
bobo_before
()
# Get the path list.
# According to RFC1738 a trailing space in the path is valid.
path
=
request_get
(
'PATH_INFO'
)
request
[
'PARENTS'
]
=
parents
=
[
object
]
if
transactions_manager
:
transactions_manager
.
begin
()
object
=
request
.
traverse
(
path
,
validated_hook
=
validated_hook
)
notify
(
PubAfterTraversal
(
request
))
if
transactions_manager
:
transactions_manager
.
recordMetaData
(
object
,
request
)
result
=
mapply
(
object
,
request
.
args
,
request
,
call_object
,
1
,
missing_name
,
dont_publish_class
,
request
,
bind
=
1
)
if
result
is
not
response
:
response
.
setBody
(
result
)
notify
(
PubBeforeCommit
(
request
))
if
transactions_manager
:
transactions_manager
.
commit
()
endInteraction
()
notify
(
PubSuccess
(
request
))
return
response
except
:
# save in order to give 'PubFailure' the original exception info
exc_info
=
sys
.
exc_info
()
# DM: provide nicer error message for FTP
sm
=
None
if
response
is
not
None
:
sm
=
getattr
(
response
,
"setMessage"
,
None
)
if
sm
is
not
None
:
from
asyncore
import
compact_traceback
cl
,
val
=
sys
.
exc_info
()[:
2
]
sm
(
'%s: %s %s'
%
(
getattr
(
cl
,
'__name__'
,
cl
),
val
,
debug_mode
and
compact_traceback
()[
-
1
]
or
''
))
# debug is just used by tests (has nothing to do with debug_mode!)
if
not
debug
and
err_hook
is
not
None
:
retry
=
False
if
parents
:
parents
=
parents
[
0
]
try
:
try
:
with
getPublisherDeadlineValue
(
request
):
return
err_hook
(
parents
,
request
,
sys
.
exc_info
()[
0
],
sys
.
exc_info
()[
1
],
sys
.
exc_info
()[
2
],
)
except
Retry
:
if
not
request
.
supports_retry
(
request
):
with
getPublisherDeadlineValue
():
return
err_hook
(
parents
,
request
,
sys
.
exc_info
()[
0
],
sys
.
exc_info
()[
1
],
sys
.
exc_info
()[
2
],
)
retry
=
True
finally
:
# Note: 'abort's can fail. Nevertheless, we want end request handling
try
:
try
:
notify
(
PubBeforeAbort
(
request
,
exc_info
,
retry
))
finally
:
if
transactions_manager
:
transactions_manager
.
abort
()
finally
:
endInteraction
()
notify
(
PubFailure
(
request
,
exc_info
,
retry
))
# Only reachable if Retry is raised and request supports retry.
newrequest
=
request
.
retry
()
request
.
close
()
# Free resources held by the request.
# Set the default layer/skin on the newly generated request
if
ISkinnable
.
providedBy
(
newrequest
):
setDefaultSkin
(
newrequest
)
try
:
return
publish
(
newrequest
,
module_name
,
after_list
,
debug
)
finally
:
newrequest
.
close
()
call_object_orig
=
Publish
.
call_object
else
:
call_object
=
wrap_call_object
(
call_object_orig
)
# Note: 'abort's can fail. Nevertheless, we want end request handling
Publish
.
call_object
=
call_object
try
:
try
:
notify
(
PubBeforeAbort
(
request
,
exc_info
,
False
))
finally
:
if
transactions_manager
:
transactions_manager
.
abort
()
finally
:
endInteraction
()
notify
(
PubFailure
(
request
,
exc_info
,
False
))
raise
publish
=
Publish
.
__dict__
[
'publish'
]
Publish
.
publish
=
publish
assert
publish
.
__module__
==
'ZPublisher.Publish'
,
repr
(
publish
.
__module__
)
if
publish
.
__name__
==
'new_publish'
:
# already patched by Localizer/patches.py
publish
=
publish
.
__defaults__
[
1
]
publish
.
__defaults__
=
tuple
(
call_object
if
x
is
call_object_orig
else
x
for
x
in
publish
.
__defaults__
)
product/ERP5Type/patches/WSGIPublisher.py
View file @
92e81dd4
...
@@ -33,7 +33,7 @@ from AccessControl.SecurityManagement import noSecurityManager
...
@@ -33,7 +33,7 @@ from AccessControl.SecurityManagement import noSecurityManager
from
Acquisition
import
aq_acquire
from
Acquisition
import
aq_acquire
from
Acquisition
import
aq_inner
from
Acquisition
import
aq_inner
from
Acquisition
import
aq_parent
from
Acquisition
import
aq_parent
from
Products.ERP5Type.Timeout
import
wrap_call_object
from
Products.ERP5Type.Timeout
import
getPublisherDeadlineValue
from
transaction.interfaces
import
TransientError
from
transaction.interfaces
import
TransientError
from
zExceptions
import
Redirect
from
zExceptions
import
Redirect
from
zExceptions
import
Unauthorized
from
zExceptions
import
Unauthorized
...
@@ -51,7 +51,7 @@ from ZPublisher.HTTPResponse import HTTPResponse
...
@@ -51,7 +51,7 @@ from ZPublisher.HTTPResponse import HTTPResponse
from
ZPublisher.HTTPRequest
import
HTTPRequest
from
ZPublisher.HTTPRequest
import
HTTPRequest
from
ZPublisher.Iterators
import
IStreamIterator
,
IUnboundStreamIterator
from
ZPublisher.Iterators
import
IStreamIterator
,
IUnboundStreamIterator
from
ZPublisher.mapply
import
mapply
from
ZPublisher.mapply
import
mapply
from
ZPublisher.WSGIPublisher
import
call_object
as
call_object_orig
from
ZPublisher.WSGIPublisher
import
call_object
from
ZPublisher.WSGIPublisher
import
missing_name
,
WSGIResponse
from
ZPublisher.WSGIPublisher
import
missing_name
,
WSGIResponse
...
@@ -64,7 +64,6 @@ _DEFAULT_DEBUG_MODE = False
...
@@ -64,7 +64,6 @@ _DEFAULT_DEBUG_MODE = False
_DEFAULT_REALM
=
None
_DEFAULT_REALM
=
None
_MODULE_LOCK
=
allocate_lock
()
_MODULE_LOCK
=
allocate_lock
()
_MODULES
=
{}
_MODULES
=
{}
call_object
=
wrap_call_object
(
call_object_orig
)
AC_LOGGER
=
logging
.
getLogger
(
'event.AccessControl'
)
AC_LOGGER
=
logging
.
getLogger
(
'event.AccessControl'
)
...
@@ -342,41 +341,42 @@ def transaction_pubevents(request, response, err_hook, tm=transaction.manager):
...
@@ -342,41 +341,42 @@ def transaction_pubevents(request, response, err_hook, tm=transaction.manager):
def
publish
(
request
,
module_info
):
def
publish
(
request
,
module_info
):
obj
,
realm
,
debug_mode
=
module_info
with
getPublisherDeadlineValue
(
request
):
obj
,
realm
,
debug_mode
=
module_info
request
.
processInputs
()
response
=
request
.
response
request
.
processInputs
()
response
=
request
.
response
if
debug_mode
:
response
.
debug_mode
=
debug_mode
if
debug_mode
:
response
.
debug_mode
=
debug_mode
if
realm
and
not
request
.
get
(
'REMOTE_USER'
,
None
):
response
.
realm
=
realm
if
realm
and
not
request
.
get
(
'REMOTE_USER'
,
None
):
response
.
realm
=
realm
noSecurityManager
()
noSecurityManager
()
# Get the path list.
# According to RFC1738 a trailing space in the path is valid.
# Get the path list.
path
=
request
.
get
(
'PATH_INFO'
)
# According to RFC1738 a trailing space in the path is valid.
request
[
'PARENTS'
]
=
[
obj
]
path
=
request
.
get
(
'PATH_INFO'
)
request
[
'PARENTS'
]
=
[
obj
]
obj
=
request
.
traverse
(
path
,
validated_hook
=
validated_hook
)
notify
(
pubevents
.
PubAfterTraversal
(
request
))
obj
=
request
.
traverse
(
path
,
validated_hook
=
validated_hook
)
recordMetaData
(
obj
,
request
)
notify
(
pubevents
.
PubAfterTraversal
(
request
))
recordMetaData
(
obj
,
request
)
result
=
mapply
(
obj
,
request
.
args
,
result
=
mapply
(
obj
,
request
,
request
.
args
,
call_object
,
request
,
1
,
call_object
,
missing_name
,
1
,
dont_publish_class
,
missing_name
,
request
,
dont_publish_class
,
bind
=
1
)
request
,
if
result
is
not
response
:
bind
=
1
)
response
.
setBody
(
result
)
if
result
is
not
response
:
response
.
setBody
(
result
)
return
response
return
response
@
contextmanager
@
contextmanager
...
...
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