Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Z
Zope
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
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
Zope
Commits
efe61189
Commit
efe61189
authored
Aug 07, 2016
by
Hanno Schlichting
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
flake8 ZPublisher/Testing
parent
2e9d01ea
Changes
43
Hide whitespace changes
Inline
Side-by-side
Showing
43 changed files
with
1240 additions
and
2009 deletions
+1240
-2009
src/Testing/README.txt
src/Testing/README.txt
+0
-35
src/Testing/ZODButil.py
src/Testing/ZODButil.py
+2
-0
src/Testing/ZopeTestCase/functional.py
src/Testing/ZopeTestCase/functional.py
+7
-7
src/Testing/ZopeTestCase/zopedoctest/functional.py
src/Testing/ZopeTestCase/zopedoctest/functional.py
+25
-16
src/Testing/common.py
src/Testing/common.py
+0
-35
src/Testing/custom_zodb.py
src/Testing/custom_zodb.py
+4
-5
src/Testing/dispatcher.py
src/Testing/dispatcher.py
+0
-188
src/Testing/makerequest.py
src/Testing/makerequest.py
+8
-9
src/Testing/tests/__init__.py
src/Testing/tests/__init__.py
+0
-1
src/Testing/tests/test_makerequest.py
src/Testing/tests/test_makerequest.py
+2
-6
src/Testing/tests/test_testbrowser.py
src/Testing/tests/test_testbrowser.py
+5
-2
src/ZPublisher/BaseRequest.py
src/ZPublisher/BaseRequest.py
+232
-201
src/ZPublisher/BaseResponse.py
src/ZPublisher/BaseResponse.py
+10
-11
src/ZPublisher/BeforeTraverse.py
src/ZPublisher/BeforeTraverse.py
+9
-11
src/ZPublisher/Client.py
src/ZPublisher/Client.py
+0
-564
src/ZPublisher/Converters.py
src/ZPublisher/Converters.py
+91
-63
src/ZPublisher/HTTPRangeSupport.py
src/ZPublisher/HTTPRangeSupport.py
+25
-14
src/ZPublisher/HTTPResponse.py
src/ZPublisher/HTTPResponse.py
+73
-82
src/ZPublisher/Iterators.py
src/ZPublisher/Iterators.py
+4
-3
src/ZPublisher/Publish.py
src/ZPublisher/Publish.py
+112
-85
src/ZPublisher/Request.py
src/ZPublisher/Request.py
+8
-3
src/ZPublisher/Response.py
src/ZPublisher/Response.py
+8
-3
src/ZPublisher/__init__.py
src/ZPublisher/__init__.py
+2
-14
src/ZPublisher/interfaces.py
src/ZPublisher/interfaces.py
+11
-6
src/ZPublisher/mapply.py
src/ZPublisher/mapply.py
+33
-24
src/ZPublisher/maybe_lock.py
src/ZPublisher/maybe_lock.py
+1
-6
src/ZPublisher/pubevents.py
src/ZPublisher/pubevents.py
+14
-6
src/ZPublisher/tests/__init__.py
src/ZPublisher/tests/__init__.py
+0
-1
src/ZPublisher/tests/generate_conflicts.py
src/ZPublisher/tests/generate_conflicts.py
+0
-90
src/ZPublisher/tests/testBaseRequest.py
src/ZPublisher/tests/testBaseRequest.py
+56
-50
src/ZPublisher/tests/testBeforeTraverse.py
src/ZPublisher/tests/testBeforeTraverse.py
+25
-22
src/ZPublisher/tests/testHTTPRangeSupport.py
src/ZPublisher/tests/testHTTPRangeSupport.py
+20
-28
src/ZPublisher/tests/testHTTPRequest.py
src/ZPublisher/tests/testHTTPRequest.py
+198
-180
src/ZPublisher/tests/testHTTPResponse.py
src/ZPublisher/tests/testHTTPResponse.py
+69
-78
src/ZPublisher/tests/testIterators.py
src/ZPublisher/tests/testIterators.py
+2
-5
src/ZPublisher/tests/testPostTraversal.py
src/ZPublisher/tests/testPostTraversal.py
+41
-35
src/ZPublisher/tests/testPublish.py
src/ZPublisher/tests/testPublish.py
+14
-7
src/ZPublisher/tests/test_Converters.py
src/ZPublisher/tests/test_Converters.py
+2
-27
src/ZPublisher/tests/test_exception_handling.py
src/ZPublisher/tests/test_exception_handling.py
+8
-5
src/ZPublisher/tests/test_mapply.py
src/ZPublisher/tests/test_mapply.py
+12
-11
src/ZPublisher/tests/test_xmlrpc.py
src/ZPublisher/tests/test_xmlrpc.py
+11
-7
src/ZPublisher/tests/testpubevents.py
src/ZPublisher/tests/testpubevents.py
+73
-48
src/ZPublisher/xmlrpc.py
src/ZPublisher/xmlrpc.py
+23
-15
No files found.
src/Testing/README.txt
deleted
100644 → 0
View file @
2e9d01ea
The Testing package is a set of shared routines for the Zope unit
testing framework. From Zope 2.8 these are more easily accessed
by using the ZopeTestCase package. See ZopeTestCase/doc for more
information.
To use Testing without ZopeTestCase:
1. Make a 'tests' subdirectory.
2. Copy 'framework.py' into 'tests' from any other package's 'tests'.
Once a test suite has been set up, you can add test modules:
1. Create a file with a name matching 'test*.py'.
2. Define one or more subclasses of 'unittest.TestCase'. The unittest
module is imported by the framework.
3. Define methods for the test classes. Each method's name must start
with 'test'. It should test one small case, using a Python
'assert' statement. Here's a minimal example:
class testClass1(unittest.TestCase):
def testAddition(self):
assert 1 + 1 == 2, 'Addition failed!'
4. You can add 'setUp' and 'tearDown' methods that are automatically
called at the start and end of the test suite.
5. Follow the instructions in 'framework.py' about adding lines to the
top and bottom of the file.
Now you can run the test as "python path/to/tests/testName.py", or
simply go to the 'tests' directory and type "python testName.py".
src/Testing/ZODButil.py
View file @
efe61189
...
...
@@ -3,10 +3,12 @@ from glob import glob
import
ZODB
from
ZODB.FileStorage
import
FileStorage
def
makeDB
():
s
=
FileStorage
(
'fs_tmp__%s'
%
os
.
getpid
())
return
ZODB
.
DB
(
s
)
def
cleanDB
():
for
fn
in
glob
(
'fs_tmp__*'
):
os
.
remove
(
fn
)
src/Testing/ZopeTestCase/functional.py
View file @
efe61189
...
...
@@ -15,7 +15,9 @@
After Marius Gedminas' functional.py module for Zope3.
"""
import
sys
,
re
,
base64
import
base64
import
re
import
sys
import
transaction
import
sandbox
import
interfaces
...
...
@@ -58,8 +60,8 @@ class Functional(sandbox.Sandboxed):
'''Publishes the object at 'path' returning a response object.'''
from
StringIO
import
StringIO
from
ZPublisher.
Request
import
Request
from
ZPublisher.
Response
import
Response
from
ZPublisher.
HTTPRequest
import
HTTPRequest
as
Request
from
ZPublisher.
HTTPResponse
import
HTTPResponse
as
Response
from
ZPublisher.Publish
import
publish_module
# Commit the sandbox for good measure
...
...
@@ -82,7 +84,7 @@ class Functional(sandbox.Sandboxed):
elif
len
(
p
)
==
2
:
[
env
[
'PATH_INFO'
],
env
[
'QUERY_STRING'
]]
=
p
else
:
raise
TypeError
,
''
raise
TypeError
(
''
)
if
basic
:
env
[
'HTTP_AUTHORIZATION'
]
=
"Basic %s"
%
base64
.
encodestring
(
basic
)
...
...
@@ -99,8 +101,7 @@ class Functional(sandbox.Sandboxed):
publish_module
(
'Zope2'
,
debug
=
not
handle_errors
,
request
=
request
,
response
=
response
,
)
response
=
response
)
return
ResponseWrapper
(
response
,
outstream
,
path
)
...
...
@@ -140,4 +141,3 @@ class ResponseWrapper:
def
getCookie
(
self
,
name
):
'''Returns a response cookie.'''
return
self
.
cookies
.
get
(
name
)
src/Testing/ZopeTestCase/zopedoctest/functional.py
View file @
efe61189
...
...
@@ -90,11 +90,14 @@ class DocResponseWrapper(ResponseWrapper):
return
"%s
\
n
"
%
(
self
.
header_output
)
basicre
=
re
.
compile
(
'Basic (.+)?:(.+)?$'
)
headerre
=
re
.
compile
(
'(
\
S+): (.+)$
'
)
def split_header(header):
return headerre.match(header).group(1, 2)
basicre = re.compile('
Basic
(.
+
)
?
:(.
+
)
?$
')
def auth_header(header):
match = basicre.match(header)
if match:
...
...
@@ -111,6 +114,7 @@ def auth_header(header):
def getRootFolder():
return AppZapper().app()
def sync():
getRootFolder()._p_jar.sync()
...
...
@@ -124,7 +128,7 @@ def http(request_string, handle_errors=True):
import urllib
import rfc822
from cStringIO import StringIO
from ZPublisher.
Response import
Response
from ZPublisher.
HTTPResponse import HTTPResponse as
Response
from ZPublisher.Publish import publish_module
# Commit work done by previous python code.
...
...
@@ -136,7 +140,7 @@ def http(request_string, handle_errors=True):
# Split off and parse the command line
l = request_string.find('
\
n
')
command_line = request_string[:l].rstrip()
request_string = request_string[l
+
1:]
request_string = request_string[l
+
1:]
method, path, protocol = command_line.split()
path = urllib.unquote(path)
...
...
@@ -154,7 +158,7 @@ def http(request_string, handle_errors=True):
elif len(p) == 2:
[env['
PATH_INFO
'], env['
QUERY_STRING
']] = p
else:
raise TypeError
, ''
raise TypeError
('')
header_output = HTTPHeaderOutput(
protocol, ('
x
-
content
-
type
-
warning
', '
x
-
powered
-
by
',
...
...
@@ -173,7 +177,7 @@ def http(request_string, handle_errors=True):
name = '
HTTP_
' + name
env[name] = value.rstrip()
if
env.has_key('
HTTP_AUTHORIZATION
')
:
if
'
HTTP_AUTHORIZATION
' in env
:
env['
HTTP_AUTHORIZATION
'] = auth_header(env['
HTTP_AUTHORIZATION
'])
outstream = StringIO()
...
...
@@ -183,8 +187,8 @@ def http(request_string, handle_errors=True):
response=response,
stdin=instream,
environ=env,
debug=not handle_errors
,
)
debug=not handle_errors
)
header_output.setResponseStatus(response.getStatus(), response.errmsg)
header_output.setResponseHeaders(response.headers)
header_output.headersl.extend(response._cookie_list())
...
...
@@ -246,6 +250,7 @@ class ZopeSuiteFactory:
test_instance = test_class()
kwsetUp = self._kw.get('
setUp
')
def setUp(test):
test_instance.setUp()
test.globs['
test
'] = test
...
...
@@ -264,6 +269,7 @@ class ZopeSuiteFactory:
self._kw['
setUp
'] = setUp
kwtearDown = self._kw.get('
tearDown
')
def tearDown(test):
if kwtearDown is not None:
kwtearDown(test_instance)
...
...
@@ -273,8 +279,8 @@ class ZopeSuiteFactory:
def setup_optionflags(self):
if '
optionflags
' not in self._kw:
self._kw['
optionflags
'] = (
doctest.ELLIPSIS
| doctest.NORMALIZE_WHITESPACE)
self._kw['
optionflags
'] = (
doctest.ELLIPSIS
| doctest.NORMALIZE_WHITESPACE)
class FunctionalSuiteFactory(ZopeSuiteFactory):
...
...
@@ -285,7 +291,8 @@ class FunctionalSuiteFactory(ZopeSuiteFactory):
globs['
http
'] = http
globs['
getRootFolder
'] = getRootFolder
globs['
sync
'] = sync
globs['
user_auth
'] = base64.encodestring('
%
s
:
%
s
' % (user_name, user_password))
globs['
user_auth
'] = base64.encodestring(
'
%
s
:
%
s
' % (user_name, user_password))
def setup_test_class(self):
test_class = self._kw.get('
test_class
', FunctionalTestCase)
...
...
@@ -297,7 +304,7 @@ class FunctionalSuiteFactory(ZopeSuiteFactory):
warnings
.
warn
((
"The test_class you are using doesn't "
"subclass from ZopeTestCase.Functional. "
"Please fix that."
),
UserWarning
,
4
)
if
not
'Functional'
in
name
:
if
'Functional'
not
in
name
:
name
=
'Functional%s'
%
name
test_class
=
type
(
name
,
(
Functional
,
test_class
),
{})
...
...
@@ -306,24 +313,27 @@ class FunctionalSuiteFactory(ZopeSuiteFactory):
def
setup_optionflags
(
self
):
if
'optionflags'
not
in
self
.
_kw
:
self
.
_kw
[
'optionflags'
]
=
(
doctest
.
ELLIPSIS
|
doctest
.
REPORT_NDIFF
|
doctest
.
NORMALIZE_WHITESPACE
)
self
.
_kw
[
'optionflags'
]
=
(
doctest
.
ELLIPSIS
|
doctest
.
REPORT_NDIFF
|
doctest
.
NORMALIZE_WHITESPACE
)
def
ZopeDocTestSuite
(
module
=
None
,
**
kw
):
module
=
doctest
.
_normalize_module
(
module
)
return
ZopeSuiteFactory
(
module
,
**
kw
).
doctestsuite
()
def
ZopeDocFileSuite
(
*
paths
,
**
kw
):
if
kw
.
get
(
'module_relative'
,
True
):
kw
[
'package'
]
=
doctest
.
_normalize_module
(
kw
.
get
(
'package'
))
return
ZopeSuiteFactory
(
*
paths
,
**
kw
).
docfilesuite
()
def
FunctionalDocTestSuite
(
module
=
None
,
**
kw
):
module
=
doctest
.
_normalize_module
(
module
)
return
FunctionalSuiteFactory
(
module
,
**
kw
).
doctestsuite
()
def
FunctionalDocFileSuite
(
*
paths
,
**
kw
):
if
kw
.
get
(
'module_relative'
,
True
):
kw
[
'package'
]
=
doctest
.
_normalize_module
(
kw
.
get
(
'package'
))
...
...
@@ -335,5 +345,4 @@ __all__ = [
'ZopeDocFileSuite'
,
'FunctionalDocTestSuite'
,
'FunctionalDocFileSuite'
,
]
]
src/Testing/common.py
deleted
100644 → 0
View file @
2e9d01ea
# Default test runner
import
unittest
TestRunner
=
unittest
.
TextTestRunner
def
debug
():
test_suite
().
debug
()
def
pdebug
():
import
pdb
pdb
.
run
(
'debug()'
)
def
test_suite
():
# The default test suite includes every subclass of TestCase in
# the module, with 'test' as the test method prefix.
ClassType
=
type
(
unittest
.
TestCase
)
tests
=
[]
for
v
in
globals
().
values
():
if
isinstance
(
v
,
ClassType
)
and
issubclass
(
v
,
unittest
.
TestCase
):
tests
.
append
(
unittest
.
makeSuite
(
v
))
if
len
(
tests
)
>
1
:
return
unittest
.
TestSuite
(
tests
)
if
len
(
tests
)
==
1
:
return
tests
[
0
]
return
class
Dummy
:
'''Utility class for quick & dirty instances'''
def
__init__
(
self
,
**
kw
):
self
.
__dict__
.
update
(
kw
)
def
__str__
(
self
):
return
'Dummy(%s)'
%
`self.__dict__`
__repr__
=
__str__
src/Testing/custom_zodb.py
View file @
efe61189
import
os
import
logging
import
ZODB
LOG
=
logging
.
getLogger
(
'Testing'
)
def
getStorage
():
""" Return a storage instance for running ZopeTestCase based
""" Return a storage instance for running ZopeTestCase based
tests. By default a DemoStorage is used. Setting
$TEST_ZEO_HOST/TEST_ZEO_PORT environment variables allows you
to use a ZEO server instead. A file storage can be configured
...
...
@@ -15,14 +14,14 @@ def getStorage():
get
=
os
.
environ
.
get
if
os
.
environ
.
has_key
(
'TEST_ZEO_HOST'
)
and
os
.
environ
.
has_key
(
'TEST_ZEO_PORT'
)
:
if
'TEST_ZEO_HOST'
in
os
.
environ
and
'TEST_ZEO_PORT'
in
os
.
environ
:
from
ZEO.ClientStorage
import
ClientStorage
zeo_host
=
get
(
'TEST_ZEO_HOST'
)
zeo_port
=
int
(
get
(
'TEST_ZEO_PORT'
))
LOG
.
info
(
'Using ZEO server (%s:%d)'
%
(
zeo_host
,
zeo_port
))
return
ClientStorage
((
zeo_host
,
zeo_port
))
elif
os
.
environ
.
has_key
(
'TEST_FILESTORAGE'
)
:
elif
'TEST_FILESTORAGE'
in
os
.
environ
:
import
ZODB.FileStorage
datafs
=
get
(
'TEST_FILESTORAGE'
)
LOG
.
info
(
'Using Filestorage at (%s)'
%
datafs
)
...
...
src/Testing/dispatcher.py
deleted
100644 → 0
View file @
2e9d01ea
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
# Dispatcher for usage inside Zope test environment
# Andreas Jung, andreas@digicool.com 03/24/2001
import
os
,
sys
,
re
,
string
import
threading
,
time
,
commands
,
profile
class
Dispatcher
:
"""
a multi-purpose thread dispatcher
"""
def
__init__
(
self
,
func
=
''
):
self
.
fp
=
sys
.
stderr
self
.
f_startup
=
[]
self
.
f_teardown
=
[]
self
.
lastlog
=
""
self
.
lock
=
threading
.
Lock
()
self
.
func
=
func
self
.
profiling
=
0
self
.
doc
=
getattr
(
self
,
self
.
func
).
__doc__
def
setlog
(
self
,
fp
):
self
.
fp
=
fp
def
log
(
self
,
s
):
if
s
==
self
.
lastlog
:
return
self
.
fp
.
write
(
s
)
self
.
fp
.
flush
()
self
.
lastlog
=
s
def
logn
(
self
,
s
):
if
s
==
self
.
lastlog
:
return
self
.
fp
.
write
(
s
+
'
\
n
'
)
self
.
fp
.
flush
()
self
.
lastlog
=
s
def
profiling_on
():
self
.
profiling
=
1
def
profiling_off
():
self
.
profiling
=
0
def
dispatcher
(
self
,
name
=
''
,
*
params
):
""" dispatcher for threads
The dispatcher expects one or several tupels:
(functionname, number of threads to start , args, keyword args)
"""
self
.
mem_usage
=
[
-
1
]
mem_watcher
=
threading
.
Thread
(
None
,
self
.
mem_watcher
,
name
=
'memwatcher'
)
mem_watcher
.
start
()
self
.
start_test
=
time
.
time
()
self
.
name
=
name
self
.
th_data
=
{}
self
.
runtime
=
{}
self
.
_threads
=
[]
s2s
=
self
.
s2s
for
func
,
numthreads
,
args
,
kw
in
params
:
f
=
getattr
(
self
,
func
)
for
i
in
range
(
0
,
numthreads
):
kw
[
't_func'
]
=
func
th
=
threading
.
Thread
(
None
,
self
.
worker
,
name
=
"TH_%s_%03d"
%
(
func
,
i
)
,
args
=
args
,
kwargs
=
kw
)
self
.
_threads
.
append
(
th
)
for
th
in
self
.
_threads
:
th
.
start
()
while
threading
.
activeCount
()
>
1
:
time
.
sleep
(
1
)
self
.
logn
(
'ID: %s '
%
self
.
name
)
self
.
logn
(
'FUNC: %s '
%
self
.
func
)
self
.
logn
(
'DOC: %s '
%
self
.
doc
)
self
.
logn
(
'Args: %s'
%
params
)
for
th
in
self
.
_threads
:
self
.
logn
(
'%-30s ........................ %9.3f sec'
%
(
th
.
getName
(),
self
.
runtime
[
th
.
getName
()])
)
for
k
,
v
in
self
.
th_data
[
th
.
getName
()].
items
():
self
.
logn
(
'%-30s %-15s = %s'
%
(
' '
,
k
,
v
)
)
self
.
logn
(
""
)
self
.
logn
(
'Complete running time: %9.3f sec'
%
(
time
.
time
()
-
self
.
start_test
)
)
if
len
(
self
.
mem_usage
)
>
1
:
self
.
mem_usage
.
remove
(
-
1
)
self
.
logn
(
"Memory: start: %s, end: %s, low: %s, high: %s"
%
\
(
s2s
(
self
.
mem_usage
[
0
]),
s2s
(
self
.
mem_usage
[
-
1
]),
s2s
(
min
(
self
.
mem_usage
)),
s2s
(
max
(
self
.
mem_usage
))))
self
.
logn
(
''
)
def
worker
(
self
,
*
args
,
**
kw
):
for
func
in
self
.
f_startup
:
f
=
getattr
(
self
,
func
)()
t_func
=
getattr
(
self
,
kw
[
't_func'
])
del
kw
[
't_func'
]
ts
=
time
.
time
()
apply
(
t_func
,
args
,
kw
)
te
=
time
.
time
()
for
func
in
self
.
f_teardown
:
getattr
(
self
,
func
)()
def
th_setup
(
self
):
""" initalize thread with some environment data """
env
=
{
'start'
:
time
.
time
()
}
return
env
def
th_teardown
(
self
,
env
,
**
kw
):
""" famous last actions of thread """
self
.
lock
.
acquire
()
self
.
th_data
[
threading
.
currentThread
().
getName
()
]
=
kw
self
.
runtime
[
threading
.
currentThread
().
getName
()
]
=
time
.
time
()
-
env
[
'start'
]
self
.
lock
.
release
()
def
getmem
(
self
):
""" try to determine the current memory usage """
if
not
sys
.
platform
in
[
'linux2'
]:
return
None
cmd
=
'/bin/ps --no-headers -o pid,vsize --pid %s'
%
os
.
getpid
()
outp
=
commands
.
getoutput
(
cmd
)
pid
,
vsize
=
filter
(
lambda
x
:
x
!=
""
,
string
.
split
(
outp
,
" "
)
)
data
=
open
(
"/proc/%d/statm"
%
os
.
getpid
()).
read
()
fields
=
re
.
split
(
" "
,
data
)
mem
=
string
.
atoi
(
fields
[
0
])
*
4096
return
mem
def
mem_watcher
(
self
):
""" thread for watching memory usage """
running
=
1
while
running
==
1
:
self
.
mem_usage
.
append
(
self
.
getmem
()
)
time
.
sleep
(
1
)
if
threading
.
activeCount
()
==
2
:
running
=
0
def
register_startup
(
self
,
func
):
self
.
f_startup
.
append
(
func
)
def
register_teardown
(
self
,
func
):
self
.
f_teardown
.
append
(
func
)
def
s2s
(
self
,
n
):
import
math
if
n
<
1024.0
:
return
"%8.3lf Bytes"
%
n
if
n
<
1024.0
*
1024.0
:
return
"%8.3lf KB"
%
(
1.0
*
n
/
1024.0
)
if
n
<
1024.0
*
1024.0
*
1024.0
:
return
"%8.3lf MB"
%
(
1.0
*
n
/
1024.0
/
1024.0
)
else
:
return
n
if
__name__
==
"__main__"
:
d
=
Dispatcher
()
print
d
.
getmem
()
pass
src/Testing/makerequest.py
View file @
efe61189
...
...
@@ -15,24 +15,24 @@ Facilitates unit tests which requires an acquirable REQUEST from
ZODB objects
"""
import
os
from
sys
import
stdin
,
stdout
from
ZPublisher.HTTPRequest
import
HTTPRequest
from
ZPublisher.HTTPResponse
import
HTTPResponse
from
ZPublisher.BaseRequest
import
RequestContainer
def
makerequest
(
app
,
stdout
=
stdout
,
environ
=
None
):
"""
Adds an HTTPRequest at app.REQUEST, and returns
app.__of__(app.REQUEST). Useful for tests that need to acquire
REQUEST.
Usage:
import makerequest
app = makerequest.makerequest(app)
You should only wrap the object used as 'root' in your tests.
app is commonly a Zope2.app(), but that's not strictly necessary
and frequently may be overkill; you can wrap other objects as long
as they support acquisition and provide enough of the features of
...
...
@@ -52,15 +52,14 @@ def makerequest(app, stdout=stdout, environ=None):
resp
=
HTTPResponse
(
stdout
=
stdout
)
environ
.
setdefault
(
'SERVER_NAME'
,
'foo'
)
environ
.
setdefault
(
'SERVER_PORT'
,
'80'
)
environ
.
setdefault
(
'REQUEST_METHOD'
,
'GET'
)
environ
.
setdefault
(
'REQUEST_METHOD'
,
'GET'
)
req
=
HTTPRequest
(
stdin
,
environ
,
resp
)
req
.
_steps
=
[
'noobject'
]
# Fake a published object.
req
[
'ACTUAL_URL'
]
=
req
.
get
(
'URL'
)
# Zope 2.7.4
# set Zope3-style default skin so that the request is usable for
# Zope3-style view look-ups.
req
[
'ACTUAL_URL'
]
=
req
.
get
(
'URL'
)
# Zope 2.7.4
# Set default skin so that the request is usable for view look-ups.
from
zope.publisher.browser
import
setDefaultSkin
setDefaultSkin
(
req
)
requestcontainer
=
RequestContainer
(
REQUEST
=
req
)
requestcontainer
=
RequestContainer
(
REQUEST
=
req
)
return
app
.
__of__
(
requestcontainer
)
src/Testing/tests/__init__.py
View file @
efe61189
#
src/Testing/tests/test_makerequest.py
View file @
efe61189
...
...
@@ -19,6 +19,7 @@ from Acquisition import Implicit
from
Testing.makerequest
import
makerequest
from
OFS.SimpleItem
import
SimpleItem
class
MakerequestTests
(
unittest
.
TestCase
):
def
test_makerequest
(
self
):
...
...
@@ -29,7 +30,7 @@ class MakerequestTests(unittest.TestCase):
self
.
assertFalse
(
hasattr
(
item
,
'REQUEST'
))
item
=
makerequest
(
item
)
self
.
assertTrue
(
hasattr
(
item
,
'REQUEST'
))
def
test_dont_break_getPhysicalPath
(
self
):
# see http://www.zope.org/Collectors/Zope/2057. If you want
# to call getPhysicalPath() on the wrapped object, be sure
...
...
@@ -57,8 +58,3 @@ class MakerequestTests(unittest.TestCase):
environ
=
{
'foofoo'
:
'barbar'
}
item
=
makerequest
(
SimpleItem
(),
environ
=
environ
)
self
.
assertEqual
(
item
.
REQUEST
.
environ
[
'foofoo'
],
'barbar'
)
def
test_suite
():
suite
=
unittest
.
TestSuite
()
suite
.
addTest
(
unittest
.
makeSuite
(
MakerequestTests
))
return
suite
src/Testing/tests/test_testbrowser.py
View file @
efe61189
...
...
@@ -18,6 +18,7 @@ import unittest
from
Testing.ZopeTestCase
import
FunctionalDocTestSuite
from
OFS.SimpleItem
import
Item
class
CookieStub
(
Item
):
"""This is a cookie stub."""
...
...
@@ -25,6 +26,7 @@ class CookieStub(Item):
REQUEST
.
RESPONSE
.
setCookie
(
'evil'
,
'cookie'
)
return
'Stub'
def
doctest_cookies
():
"""
We want to make sure that our testbrowser correctly understands
...
...
@@ -52,6 +54,7 @@ def doctest_cookies():
True
"""
def
doctest_camel_case_headers
():
"""Make sure that the headers come out in camel case.
...
...
@@ -76,5 +79,5 @@ def doctest_camel_case_headers():
def
test_suite
():
return
unittest
.
TestSuite
((
FunctionalDocTestSuite
(),
))
FunctionalDocTestSuite
(),
))
src/ZPublisher/BaseRequest.py
View file @
efe61189
...
...
@@ -14,11 +14,13 @@
"""
from
urllib
import
quote
as
urllib_quote
import
types
import
xmlrpc
from
AccessControl.ZopeSecurityPolicy
import
getRoles
from
Acquisition
import
aq_base
from
Acquisition.interfaces
import
IAcquirer
from
ZPublisher.interfaces
import
UseTraversalDefault
from
ExtensionClass
import
Base
from
zExceptions
import
Forbidden
from
zExceptions
import
NotFound
from
zope.component
import
queryMultiAdapter
...
...
@@ -34,6 +36,10 @@ from zope.publisher.interfaces.browser import IBrowserPublisher
from
zope.traversing.namespace
import
namespaceLookup
from
zope.traversing.namespace
import
nsParse
from
ZPublisher.Converters
import
type_converters
from
ZPublisher.interfaces
import
UseTraversalDefault
_marker
=
[]
UNSPECIFIED_ROLES
=
''
...
...
@@ -41,28 +47,17 @@ def quote(text):
# quote url path segments, but leave + and @ intact
return
urllib_quote
(
text
,
'/+@'
)
try
:
from
ExtensionClass
import
Base
from
ZPublisher.Converters
import
type_converters
class
RequestContainer
(
Base
):
__roles__
=
None
def
__init__
(
self
,
**
kw
):
for
k
,
v
in
kw
.
items
():
self
.
__dict__
[
k
]
=
v
def
manage_property_types
(
self
):
return
type_converters
.
keys
()
except
ImportError
:
class
RequestContainer
:
__roles__
=
None
def
__init__
(
self
,
**
kw
):
for
k
,
v
in
kw
.
items
():
self
.
__dict__
[
k
]
=
v
try
:
from
AccessControl.ZopeSecurityPolicy
import
getRoles
except
ImportError
:
def
getRoles
(
container
,
name
,
value
,
default
):
return
getattr
(
value
,
'__roles__'
,
default
)
class
RequestContainer
(
Base
):
__roles__
=
None
def
__init__
(
self
,
**
kw
):
for
k
,
v
in
kw
.
items
():
self
.
__dict__
[
k
]
=
v
def
manage_property_types
(
self
):
return
type_converters
.
keys
()
class
DefaultPublishTraverse
(
object
):
...
...
@@ -74,35 +69,39 @@ class DefaultPublishTraverse(object):
def
publishTraverse
(
self
,
request
,
name
):
object
=
self
.
context
URL
=
request
[
'URL'
]
URL
=
request
[
'URL'
]
if
name
[:
1
]
==
'_'
:
raise
Forbidden
(
"Object name begins with an underscore at: %s"
%
URL
)
if
name
[:
1
]
==
'_'
:
raise
Forbidden
(
"Object name begins with an underscore at: %s"
%
URL
)
subobject
=
UseTraversalDefault
# indicator
try
:
if
hasattr
(
object
,
'__bobo_traverse__'
):
if
hasattr
(
object
,
'__bobo_traverse__'
):
try
:
subobject
=
object
.
__bobo_traverse__
(
request
,
name
)
if
type
(
subobject
)
is
type
(()
)
and
len
(
subobject
)
>
1
:
subobject
=
object
.
__bobo_traverse__
(
request
,
name
)
if
isinstance
(
subobject
,
tuple
)
and
len
(
subobject
)
>
1
:
# Add additional parents into the path
# XXX There are no tests for this:
request
[
'PARENTS'
][
-
1
:]
=
list
(
subobject
[:
-
1
])
object
,
subobject
=
subobject
[
-
2
:]
except
(
AttributeError
,
KeyError
,
NotFound
)
,
e
:
except
(
AttributeError
,
KeyError
,
NotFound
)
as
e
:
# Try to find a view
subobject
=
queryMultiAdapter
((
object
,
request
),
Interface
,
name
)
subobject
=
queryMultiAdapter
(
(
object
,
request
),
Interface
,
name
)
if
subobject
is
not
None
:
# OFS.Application.__bobo_traverse__ calls
# REQUEST.RESPONSE.notFoundError which sets the HTTP
# status code to 404
request
.
response
.
setStatus
(
200
)
# We don't need to do the docstring security check
# for views, so lets skip it and return the object here.
# for views, so lets skip it and
# return the object here.
if
IAcquirer
.
providedBy
(
subobject
):
subobject
=
subobject
.
__of__
(
object
)
return
subobject
# No view found. Reraise the error raised by __bobo_traverse__
# No view found. Reraise the error
# raised by __bobo_traverse__
raise
e
except
UseTraversalDefault
:
pass
...
...
@@ -123,9 +122,9 @@ class DefaultPublishTraverse(object):
# And lastly, of there is no view, try acquired attributes, but
# only if there is no __bobo_traverse__:
try
:
subobject
=
getattr
(
object
,
name
)
# Again, clear any error status created by
__bobo_traverse__
# because we actually found something:
subobject
=
getattr
(
object
,
name
)
# Again, clear any error status created by
#
__bobo_traverse__
because we actually found something:
request
.
response
.
setStatus
(
200
)
except
AttributeError
:
pass
...
...
@@ -134,7 +133,7 @@ class DefaultPublishTraverse(object):
if
subobject
is
None
:
try
:
subobject
=
object
[
name
]
except
TypeError
:
# unsubscriptable
except
TypeError
:
# unsubscriptable
raise
KeyError
(
name
)
# Ensure that the object has a docstring, or that the parent
...
...
@@ -143,21 +142,15 @@ class DefaultPublishTraverse(object):
doc
=
getattr
(
subobject
,
'__doc__'
,
None
)
if
not
doc
:
raise
Forbidden
(
"The object at %s has an empty or missing "
\
"docstring. Objects must have a docstring to be "
\
"The object at %s has an empty or missing "
"docstring. Objects must have a docstring to be "
"published."
%
URL
)
# Hack for security: in Python 2.2.2, most built-in types
# gained docstrings that they didn't have before. That caused
# certain mutable types (dicts, lists) to become publishable
# when they shouldn't be. The following check makes sure that
# the right thing happens in both 2.2.2+ and earlier versions.
)
# Check that built-in types aren't publishable.
if
not
typeCheck
(
subobject
):
raise
Forbidden
(
"The object at %s is not publishable."
%
URL
)
"The object at %s is not publishable."
%
URL
)
return
subobject
...
...
@@ -175,7 +168,6 @@ class DefaultPublishTraverse(object):
return
self
.
context
,
()
_marker
=
[]
class
BaseRequest
:
"""Provide basic ZPublisher request management
...
...
@@ -196,25 +188,27 @@ class BaseRequest:
# acquisition of REQUEST is disallowed, which penalizes access
# in DTML with tags.
__roles__
=
None
_file
=
None
common
=
{}
# Common request data
_auth
=
None
_held
=
()
_file
=
None
common
=
{}
# Common request data
_auth
=
None
_held
=
()
# Allow (reluctantly) access to unprotected attributes
__allow_access_to_unprotected_subobjects__
=
1
__allow_access_to_unprotected_subobjects__
=
1
def
__init__
(
self
,
other
=
None
,
**
kw
):
"""The constructor is not allowed to raise errors
"""
self
.
__doc__
=
None
# Make BaseRequest objects unpublishable
if
other
is
None
:
other
=
kw
else
:
other
.
update
(
kw
)
self
.
other
=
other
if
other
is
None
:
other
=
kw
else
:
other
.
update
(
kw
)
self
.
other
=
other
def
clear
(
self
):
self
.
other
.
clear
()
self
.
_held
=
None
self
.
_held
=
None
def
close
(
self
):
try
:
...
...
@@ -231,15 +225,15 @@ class BaseRequest:
def
__len__
(
self
):
return
1
def
__setitem__
(
self
,
key
,
value
):
def
__setitem__
(
self
,
key
,
value
):
"""Set application variables
This method is used to set a variable in the requests "other"
category.
"""
self
.
other
[
key
]
=
value
self
.
other
[
key
]
=
value
set
=
__setitem__
set
=
__setitem__
def
get
(
self
,
key
,
default
=
None
):
"""Get a variable value
...
...
@@ -250,24 +244,27 @@ class BaseRequest:
other variables, form data, and then cookies.
"""
if
key
==
'REQUEST'
:
return
self
if
key
==
'REQUEST'
:
return
self
v
=
self
.
other
.
get
(
key
,
_marker
)
if
v
is
not
_marker
:
return
v
v
=
self
.
common
.
get
(
key
,
default
)
if
v
is
not
_marker
:
return
v
v
=
self
.
other
.
get
(
key
,
_marker
)
if
v
is
not
_marker
:
return
v
v
=
self
.
common
.
get
(
key
,
default
)
if
v
is
not
_marker
:
return
v
if
key
==
'BODY'
and
self
.
_file
is
not
None
:
p
=
self
.
_file
.
tell
()
if
key
==
'BODY'
and
self
.
_file
is
not
None
:
p
=
self
.
_file
.
tell
()
self
.
_file
.
seek
(
0
)
v
=
self
.
_file
.
read
()
v
=
self
.
_file
.
read
()
self
.
_file
.
seek
(
p
)
self
.
other
[
key
]
=
v
self
.
other
[
key
]
=
v
return
v
if
key
==
'BODYFILE'
and
self
.
_file
is
not
None
:
v
=
self
.
_file
self
.
other
[
key
]
=
v
if
key
==
'BODYFILE'
and
self
.
_file
is
not
None
:
v
=
self
.
_file
self
.
other
[
key
]
=
v
return
v
return
default
...
...
@@ -275,7 +272,7 @@ class BaseRequest:
def
__getitem__
(
self
,
key
,
default
=
_marker
):
v
=
self
.
get
(
key
,
default
)
if
v
is
_marker
:
raise
KeyError
,
key
raise
KeyError
(
key
)
return
v
def
__bobo_traverse__
(
self
,
name
):
...
...
@@ -284,17 +281,17 @@ class BaseRequest:
def
__getattr__
(
self
,
key
,
default
=
_marker
):
v
=
self
.
get
(
key
,
default
)
if
v
is
_marker
:
raise
AttributeError
,
key
raise
AttributeError
(
key
)
return
v
def
set_lazy
(
self
,
key
,
callable
):
pass
# MAYBE, we could do more, but let HTTPRequest do it
def
has_key
(
self
,
key
):
return
self
.
get
(
key
,
_marker
)
is
not
_marker
def
has_key
(
self
,
key
):
return
key
in
self
def
__contains__
(
self
,
key
):
return
self
.
has_key
(
key
)
return
self
.
get
(
key
,
_marker
)
is
not
_marker
def
keys
(
self
):
keys
=
{}
...
...
@@ -304,16 +301,14 @@ class BaseRequest:
def
items
(
self
):
result
=
[]
get
=
self
.
get
for
k
in
self
.
keys
():
result
.
append
((
k
,
get
(
k
)))
result
.
append
((
k
,
self
.
get
(
k
)))
return
result
def
values
(
self
):
result
=
[]
get
=
self
.
get
for
k
in
self
.
keys
():
result
.
append
(
get
(
k
))
result
.
append
(
self
.
get
(
k
))
return
result
def
__str__
(
self
):
...
...
@@ -321,7 +316,7 @@ class BaseRequest:
L1
.
sort
()
return
'
\
n
'
.
join
(
"%s:
\
t
%s"
%
item
for
item
in
L1
)
__repr__
=
__str__
__repr__
=
__str__
# Original version: see zope.traversing.publicationtraverse
def
traverseName
(
self
,
ob
,
name
):
...
...
@@ -346,8 +341,8 @@ class BaseRequest:
else
:
adapter
=
queryMultiAdapter
((
ob
,
self
),
IPublishTraverse
)
if
adapter
is
None
:
#
#
Zope2 doesn't set up its own adapters in a lot of cases
#
#
so we will just use a default adapter.
# Zope2 doesn't set up its own adapters in a lot of cases
# so we will just use a default adapter.
adapter
=
DefaultPublishTraverse
(
ob
,
self
)
ob2
=
adapter
.
publishTraverse
(
self
,
name
)
...
...
@@ -361,59 +356,64 @@ class BaseRequest:
The REQUEST must already have a PARENTS item with at least one
object in it. This is typically the root object.
"""
request
=
self
request_get
=
request
.
get
if
response
is
None
:
response
=
self
.
response
request
=
self
request_get
=
request
.
get
if
response
is
None
:
response
=
self
.
response
# remember path for later use
browser_path
=
path
# Cleanup the path list
if
path
[:
1
]
==
'/'
:
path
=
path
[
1
:]
if
path
[
-
1
:]
==
'/'
:
path
=
path
[:
-
1
]
clean
=
[]
if
path
[:
1
]
==
'/'
:
path
=
path
[
1
:]
if
path
[
-
1
:]
==
'/'
:
path
=
path
[:
-
1
]
clean
=
[]
for
item
in
path
.
split
(
'/'
):
# Make sure that certain things that dont make sense
# cannot be traversed.
if
item
in
(
'REQUEST'
,
'aq_self'
,
'aq_base'
):
return
response
.
notFoundError
(
path
)
if
not
item
or
item
==
'.'
:
if
not
item
or
item
==
'.'
:
continue
elif
item
==
'..'
:
del
clean
[
-
1
]
else
:
clean
.
append
(
item
)
path
=
clean
else
:
clean
.
append
(
item
)
path
=
clean
# How did this request come in? (HTTP GET, PUT, POST, etc.)
method
=
request_get
(
'REQUEST_METHOD'
,
'GET'
).
upper
()
if
method
in
[
"GET"
,
"POST"
,
"PURGE"
]
and
not
isinstance
(
response
,
xmlrpc
.
Response
):
if
(
method
in
[
"GET"
,
"POST"
,
"PURGE"
]
and
not
isinstance
(
response
,
xmlrpc
.
Response
)
):
# Probably a browser
no_acquire_flag
=
0
no_acquire_flag
=
0
# index_html is still the default method, only any object can
# override it by implementing its own __browser_default__ method
method
=
'index_html'
elif
self
.
maybe_webdav_client
:
# Probably a WebDAV client.
no_acquire_flag
=
1
no_acquire_flag
=
1
else
:
no_acquire_flag
=
0
no_acquire_flag
=
0
URL
=
request
[
'URL'
]
parents
=
request
[
'PARENTS'
]
object
=
parents
[
-
1
]
URL
=
request
[
'URL'
]
parents
=
request
[
'PARENTS'
]
object
=
parents
[
-
1
]
del
parents
[:]
self
.
roles
=
getRoles
(
None
,
None
,
object
,
UNSPECIFIED_ROLES
)
# if the top object has a __bobo_traverse__ method, then use it
# to possibly traverse to an alternate top-level object.
if
hasattr
(
object
,
'__bobo_traverse__'
):
if
hasattr
(
object
,
'__bobo_traverse__'
):
try
:
object
=
object
.
__bobo_traverse__
(
request
)
object
=
object
.
__bobo_traverse__
(
request
)
self
.
roles
=
getRoles
(
None
,
None
,
object
,
UNSPECIFIED_ROLES
)
except
:
pass
except
Exception
:
pass
if
not
path
and
not
method
:
return
response
.
forbiddenError
(
self
[
'URL'
])
...
...
@@ -422,10 +422,10 @@ class BaseRequest:
if
hasattr
(
object
,
'__of__'
):
# Try to bind the top-level object to the request
# This is how you get 'self.REQUEST'
object
=
object
.
__of__
(
RequestContainer
(
REQUEST
=
request
))
object
=
object
.
__of__
(
RequestContainer
(
REQUEST
=
request
))
parents
.
append
(
object
)
steps
=
self
.
steps
steps
=
self
.
steps
self
.
_steps
=
_steps
=
map
(
quote
,
steps
)
path
.
reverse
()
...
...
@@ -485,7 +485,7 @@ class BaseRequest:
object
,
default_path
=
adapter
.
browserDefault
(
self
)
if
default_path
:
request
.
_hacked_path
=
1
request
.
_hacked_path
=
1
if
len
(
default_path
)
>
1
:
path
=
list
(
default_path
)
method
=
path
.
pop
()
...
...
@@ -493,19 +493,21 @@ class BaseRequest:
continue
else
:
entry_name
=
default_path
[
0
]
elif
(
method
and
hasattr
(
object
,
method
)
and
entry_name
!=
metho
d
and
getattr
(
object
,
method
)
is
not
None
):
request
.
_hacked_path
=
1
elif
(
method
and
hasattr
(
object
,
method
)
and
entry_name
!=
method
an
d
getattr
(
object
,
method
)
is
not
None
):
request
.
_hacked_path
=
1
entry_name
=
method
method
=
'index_html'
else
:
if
hasattr
(
object
,
'__call__'
):
self
.
roles
=
getRoles
(
object
,
'__call__'
,
object
.
__call__
,
self
.
roles
)
self
.
roles
=
getRoles
(
object
,
'__call__'
,
object
.
__call__
,
self
.
roles
)
if
request
.
_hacked_path
:
i
=
URL
.
rfind
(
'/'
)
if
i
>
0
:
response
.
setBase
(
URL
[:
i
])
i
=
URL
.
rfind
(
'/'
)
if
i
>
0
:
response
.
setBase
(
URL
[:
i
])
break
step
=
quote
(
entry_name
)
_steps
.
append
(
step
)
...
...
@@ -513,8 +515,8 @@ class BaseRequest:
try
:
subobject
=
self
.
traverseName
(
object
,
entry_name
)
if
(
hasattr
(
object
,
'__bobo_traverse__'
)
or
hasattr
(
object
,
entry_name
)):
if
(
hasattr
(
object
,
'__bobo_traverse__'
)
or
hasattr
(
object
,
entry_name
)):
check_name
=
entry_name
else
:
check_name
=
None
...
...
@@ -530,7 +532,7 @@ class BaseRequest:
"Cannot locate object at: %s"
%
URL
)
else
:
return
response
.
notFoundError
(
URL
)
except
Forbidden
,
e
:
except
Forbidden
as
e
:
if
self
.
response
.
debug_mode
:
return
response
.
debugError
(
e
.
args
)
else
:
...
...
@@ -552,12 +554,12 @@ class BaseRequest:
# heirarchy -- you'd always get the
# existing object :(
if
(
no_acquire_flag
and
hasattr
(
parents
[
1
],
'aq_base'
)
and
not
hasattr
(
parents
[
1
],
'__bobo_traverse__'
)):
hasattr
(
parents
[
1
],
'aq_base'
)
and
not
hasattr
(
parents
[
1
],
'__bobo_traverse__'
)):
base
=
parents
[
1
].
aq_base
if
not
hasattr
(
base
,
entry_name
):
try
:
if
not
entry_name
in
base
:
if
entry_name
not
in
base
:
raise
AttributeError
(
entry_name
)
except
TypeError
:
raise
AttributeError
(
entry_name
)
...
...
@@ -568,74 +570,90 @@ class BaseRequest:
request
[
'PUBLISHED'
]
=
parents
.
pop
(
0
)
# Do authorization checks
user
=
groups
=
None
i
=
0
user
=
groups
=
None
i
=
0
if
1
:
# Always perform authentication.
last_parent_index
=
len
(
parents
)
last_parent_index
=
len
(
parents
)
if
hasattr
(
object
,
'__allow_groups__'
):
groups
=
object
.
__allow_groups__
inext
=
0
groups
=
object
.
__allow_groups__
inext
=
0
else
:
inext
=
None
inext
=
None
for
i
in
range
(
last_parent_index
):
if
hasattr
(
parents
[
i
],
'__allow_groups__'
):
groups
=
parents
[
i
].
__allow_groups__
inext
=
i
+
1
if
hasattr
(
parents
[
i
],
'__allow_groups__'
):
groups
=
parents
[
i
].
__allow_groups__
inext
=
i
+
1
break
if
inext
is
not
None
:
i
=
inext
i
=
inext
if
hasattr
(
groups
,
'validate'
):
v
=
groups
.
validate
else
:
v
=
old_validation
if
hasattr
(
groups
,
'validate'
):
v
=
groups
.
validate
else
:
v
=
old_validation
auth
=
request
.
_auth
auth
=
request
.
_auth
if
v
is
old_validation
and
self
.
roles
is
UNSPECIFIED_ROLES
:
# No roles, so if we have a named group, get roles from
# group keys
if
hasattr
(
groups
,
'keys'
):
self
.
roles
=
groups
.
keys
()
if
hasattr
(
groups
,
'keys'
):
self
.
roles
=
groups
.
keys
()
else
:
try
:
groups
=
groups
()
except
:
pass
try
:
self
.
roles
=
groups
.
keys
()
except
:
pass
try
:
groups
=
groups
()
except
Exception
:
pass
try
:
self
.
roles
=
groups
.
keys
()
except
Exception
:
pass
if
groups
is
None
:
# Public group, hack structures to get it to validate
self
.
roles
=
None
auth
=
''
self
.
roles
=
None
auth
=
''
if
v
is
old_validation
:
user
=
old_validation
(
groups
,
request
,
auth
,
self
.
roles
)
elif
self
.
roles
is
UNSPECIFIED_ROLES
:
user
=
v
(
request
,
auth
)
else
:
user
=
v
(
request
,
auth
,
self
.
roles
)
user
=
old_validation
(
groups
,
request
,
auth
,
self
.
roles
)
elif
self
.
roles
is
UNSPECIFIED_ROLES
:
user
=
v
(
request
,
auth
)
else
:
user
=
v
(
request
,
auth
,
self
.
roles
)
while
user
is
None
and
i
<
last_parent_index
:
parent
=
parents
[
i
]
i
=
i
+
1
parent
=
parents
[
i
]
i
=
i
+
1
if
hasattr
(
parent
,
'__allow_groups__'
):
groups
=
parent
.
__allow_groups__
else
:
continue
if
hasattr
(
groups
,
'validate'
):
v
=
groups
.
validate
else
:
v
=
old_validation
groups
=
parent
.
__allow_groups__
else
:
continue
if
hasattr
(
groups
,
'validate'
):
v
=
groups
.
validate
else
:
v
=
old_validation
if
v
is
old_validation
:
user
=
old_validation
(
groups
,
request
,
auth
,
self
.
roles
)
elif
self
.
roles
is
UNSPECIFIED_ROLES
:
user
=
v
(
request
,
auth
)
else
:
user
=
v
(
request
,
auth
,
self
.
roles
)
user
=
old_validation
(
groups
,
request
,
auth
,
self
.
roles
)
elif
self
.
roles
is
UNSPECIFIED_ROLES
:
user
=
v
(
request
,
auth
)
else
:
user
=
v
(
request
,
auth
,
self
.
roles
)
if
user
is
None
and
self
.
roles
!=
UNSPECIFIED_ROLES
:
response
.
unauthorized
()
if
user
is
not
None
:
if
validated_hook
is
not
None
:
validated_hook
(
self
,
user
)
request
[
'AUTHENTICATED_USER'
]
=
user
request
[
'AUTHENTICATION_PATH'
]
=
'/'
.
join
(
steps
[:
-
i
])
if
validated_hook
is
not
None
:
validated_hook
(
self
,
user
)
request
[
'AUTHENTICATED_USER'
]
=
user
request
[
'AUTHENTICATION_PATH'
]
=
'/'
.
join
(
steps
[:
-
i
])
# Remove http request method from the URL.
request
[
'URL'
]
=
URL
request
[
'URL'
]
=
URL
# Run post traversal hooks
if
post_traverse
:
...
...
@@ -657,19 +675,22 @@ class BaseRequest:
try
:
pairs
=
self
.
_post_traverse
except
AttributeError
:
raise
RuntimeError
,
(
'post_traverse() may only be called '
'during publishing traversal.'
)
raise
RuntimeError
(
'post_traverse() may only be called '
'during publishing traversal.'
)
else
:
pairs
.
append
((
f
,
tuple
(
args
)))
retry_count
=
0
def
supports_retry
(
self
):
return
0
retry_count
=
0
def
supports_retry
(
self
):
return
0
def
_hold
(
self
,
object
):
"""Hold a reference to an object to delay it's destruction until mine
"""
if
self
.
_held
is
not
None
:
self
.
_held
=
self
.
_held
+
(
object
,)
self
.
_held
=
self
.
_held
+
(
object
,
)
def
exec_callables
(
callables
):
result
=
None
...
...
@@ -679,74 +700,84 @@ def exec_callables(callables):
if
result
is
not
None
:
return
result
def
old_validation
(
groups
,
request
,
auth
,
roles
=
UNSPECIFIED_ROLES
):
if
auth
:
auth
=
request
.
_authUserPW
()
if
auth
:
name
,
password
=
auth
elif
roles
is
None
:
return
''
else
:
return
None
auth
=
request
.
_authUserPW
()
if
auth
:
name
,
password
=
auth
elif
roles
is
None
:
return
''
else
:
return
None
elif
'REMOTE_USER'
in
request
.
environ
:
name
=
request
.
environ
[
'REMOTE_USER'
]
password
=
None
name
=
request
.
environ
[
'REMOTE_USER'
]
password
=
None
else
:
if
roles
is
None
:
return
''
if
roles
is
None
:
return
''
return
None
if
roles
is
None
:
return
name
if
roles
is
None
:
return
name
keys
=
None
keys
=
None
try
:
keys
=
groups
.
keys
except
:
keys
=
groups
.
keys
except
Exception
:
try
:
groups
=
groups
()
# Maybe it was a method defining a group
keys
=
groups
.
keys
except
:
pass
groups
=
groups
()
# Maybe it was a method defining a group
keys
=
groups
.
keys
except
Exception
:
pass
if
keys
is
not
None
:
# OK, we have a named group, so apply the roles to the named
# group.
if
roles
is
UNSPECIFIED_ROLES
:
roles
=
keys
()
g
=
[]
if
roles
is
UNSPECIFIED_ROLES
:
roles
=
keys
()
g
=
[]
for
role
in
roles
:
if
role
in
groups
:
g
.
append
(
groups
[
role
])
groups
=
g
if
role
in
groups
:
g
.
append
(
groups
[
role
])
groups
=
g
for
d
in
groups
:
if
name
in
d
and
(
d
[
name
]
==
password
or
password
is
None
):
if
name
in
d
and
(
d
[
name
]
==
password
or
password
is
None
):
return
name
if
keys
is
None
:
# Not a named group, so don't go further
raise
Forbidden
,
(
raise
Forbidden
(
"""<strong>You are not authorized to access this resource"""
)
return
None
# This mapping contains the built-in types that gained docstrings
# between Python 2.1 and 2.2.2. By specifically checking for these
# types during publishing, we ensure the same publishing rules in
# both versions. The downside is that this needs to be extended as
# new built-in types are added and future Python versions are
# supported.
import
types
itypes
=
{}
for
name
in
(
'NoneType'
,
'IntType'
,
'LongType'
,
'FloatType'
,
'StringType'
,
'BufferType'
,
'TupleType'
,
'ListType'
,
'DictType'
,
'XRangeType'
,
'SliceType'
,
'EllipsisType'
,
'UnicodeType'
,
'CodeType'
,
'TracebackType'
,
'FrameType'
,
'DictProxyType'
,
'BooleanType'
,
'ComplexType'
):
itypes
=
{
bool
:
0
,
types
.
CodeType
:
0
,
complex
:
0
,
dict
:
0
,
float
:
0
,
types
.
FrameType
:
0
,
frozenset
:
0
,
int
:
0
,
list
:
0
,
type
(
None
):
0
,
set
:
0
,
slice
:
0
,
str
:
0
,
types
.
TracebackType
:
0
,
tuple
:
0
,
}
for
name
in
(
'BufferType'
,
'DictProxyType'
,
'EllipsisType'
,
'LongType'
,
'UnicodeType'
,
'XRangeType'
):
if
hasattr
(
types
,
name
):
itypes
[
getattr
(
types
,
name
)]
=
0
# Python 2.4 no longer maintains the types module.
itypes
[
set
]
=
0
itypes
[
frozenset
]
=
0
def
typeCheck
(
obj
,
deny
=
itypes
):
# Return true if its ok to publish the type, false otherwise.
...
...
src/ZPublisher/BaseResponse.py
View file @
efe61189
...
...
@@ -15,10 +15,9 @@
from
zExceptions
import
Unauthorized
,
Forbidden
,
NotFound
,
BadRequest
class
BaseResponse
:
"""Base Response Class
What should be here?
"""
debug_mode
=
None
_auth
=
None
...
...
@@ -59,7 +58,7 @@ class BaseResponse:
'Returns the current HTTP status code as an integer. '
return
self
.
status
def
setCookie
(
self
,
name
,
value
,
**
kw
):
def
setCookie
(
self
,
name
,
value
,
**
kw
):
'''
\
Set an HTTP cookie on the browser
...
...
@@ -101,12 +100,12 @@ class BaseResponse:
return
str
(
self
.
body
)
def
__repr__
(
self
):
return
'%s(%
s)'
%
(
self
.
__class__
.
__name__
,
`self.body`
)
return
'%s(%
r)'
%
(
self
.
__class__
.
__name__
,
self
.
body
)
def
flush
(
self
):
pass
def
write
(
self
,
data
):
def
write
(
self
,
data
):
"""
\
Return data as a stream
...
...
@@ -121,7 +120,7 @@ class BaseResponse:
after beginning stream-oriented output.
"""
self
.
body
=
self
.
body
+
data
self
.
body
=
self
.
body
+
data
def
exception
(
self
,
fatal
=
0
,
info
=
None
):
"""Handle an exception.
...
...
@@ -135,23 +134,23 @@ class BaseResponse:
def
notFoundError
(
self
,
v
=
''
):
"""Generate an error indicating that an object was not found.
"""
raise
NotFound
,
v
raise
NotFound
(
v
)
def
debugError
(
self
,
v
=
''
):
"""Raise an error with debigging info and in debugging mode"""
raise
NotFound
,
"Debugging notice: %s"
%
v
raise
NotFound
(
"Debugging notice: %s"
%
v
)
def
badRequestError
(
self
,
v
=
''
):
"""Raise an error indicating something wrong with the request"""
raise
BadRequest
,
v
raise
BadRequest
(
v
)
def
forbiddenError
(
self
,
v
=
''
):
"""Raise an error indicating that the request cannot be done"""
raise
Forbidden
,
v
raise
Forbidden
(
v
)
def
unauthorized
(
self
):
"""Raise an eror indicating that the user was not authizated
Make sure to generate an appropriate challenge, as appropriate.
"""
raise
Unauthorized
raise
Unauthorized
()
src/ZPublisher/BeforeTraverse.py
View file @
efe61189
...
...
@@ -15,10 +15,9 @@
from
Acquisition
import
aq_base
from
logging
import
getLogger
# Interface
LOG
=
getLogger
(
'ZPublisher'
)
def
registerBeforeTraverse
(
container
,
object
,
app_handle
,
priority
=
99
):
"""Register an object to be called before a container is traversed.
...
...
@@ -36,6 +35,7 @@ def registerBeforeTraverse(container, object, app_handle, priority=99):
btr
[(
priority
,
app_handle
)]
=
object
rewriteBeforeTraverse
(
container
,
btr
)
def
unregisterBeforeTraverse
(
container
,
app_handle
):
"""Unregister a __before_traverse__ hook object, given its 'app_handle'.
...
...
@@ -50,6 +50,7 @@ def unregisterBeforeTraverse(container, app_handle):
rewriteBeforeTraverse
(
container
,
btr
)
return
objects
def
queryBeforeTraverse
(
container
,
app_handle
):
"""Find __before_traverse__ hook objects, given an 'app_handle'.
...
...
@@ -61,7 +62,6 @@ def queryBeforeTraverse(container, app_handle):
objects
.
append
((
k
[
0
],
btr
[
k
]))
return
objects
# Implementation tools
def
rewriteBeforeTraverse
(
container
,
btr
):
"""Rewrite the list of __before_traverse__ hook objects"""
...
...
@@ -79,6 +79,7 @@ def rewriteBeforeTraverse(container, btr):
for
key
in
keys
:
bpth
.
add
(
btr
[
key
])
class
MultiHook
:
"""Class used to multiplex hook.
...
...
@@ -102,13 +103,12 @@ class MultiHook:
try
:
cob
(
container
,
request
)
except
TypeError
:
LOG
.
error
(
'%
s call %s
failed.'
%
(
`self._hookname`
,
`cob`
),
exc_info
=
True
)
LOG
.
error
(
'%
r call %r
failed.'
%
(
self
.
_hookname
,
cob
),
exc_info
=
True
)
def
add
(
self
,
cob
):
self
.
_list
.
append
(
cob
)
# Helper class
class
NameCaller
:
"""Class used to proxy sibling objects by name.
...
...
@@ -134,10 +134,8 @@ class NameCaller:
# This happens especially, if "meth" is a "CookieCrumber" instance,
# i.e. in a CMF Portal, if a DTMLMethod (or a similar object
# with a fake "func_code" is in the acquisition context
#args = getattr(getattr(meth, 'func_code', None), 'co_argcount', 2)
args
=
getattr
(
getattr
(
aq_base
(
meth
),
'func_code'
,
None
),
'co_argcount'
,
2
)
'co_argcount'
,
2
)
try
:
meth
(
*
(
container
,
request
,
None
)[:
args
])
...
...
@@ -148,5 +146,5 @@ class NameCaller:
# Only catch exceptions that are likely to be logic errors.
# We shouldn't catch Redirects, Unauthorizeds, etc. since
# the programmer may want to raise them deliberately.
LOG
.
error
(
'BeforeTraverse: Error while invoking hook: "%s"'
%
self
.
name
,
exc_info
=
True
)
LOG
.
error
(
'BeforeTraverse: Error while invoking hook: "%s"'
%
self
.
name
,
exc_info
=
True
)
src/ZPublisher/Client.py
deleted
100644 → 0
View file @
2e9d01ea
#!/bin/sh
""":"
exec python $0 ${1+"$@"}
"""
#"
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Bobo call interface
This module provides tools for accessing web objects as if they were
functions or objects with methods. It also provides a simple call function
that allows one to simply make a single web request.
Function -- Function-like objects that return both header and body
data when called.
Object -- Treat a URL as a web object with methods
call -- Simple interface to call a remote function.
The module also provides a command-line interface for calling objects.
"""
import
sys
,
re
,
socket
,
mimetools
from
httplib
import
HTTP
from
os
import
getpid
from
time
import
time
from
random
import
random
from
base64
import
encodestring
from
urllib
import
urlopen
,
quote
from
types
import
FileType
,
ListType
,
DictType
,
TupleType
from
string
import
translate
,
maketrans
from
urlparse
import
urlparse
class
BadReply
(
Exception
):
pass
class
Function
:
username
=
None
password
=
None
method
=
None
timeout
=
60
def
__init__
(
self
,
url
,
arguments
=
(),
method
=
None
,
username
=
None
,
password
=
None
,
timeout
=
None
,
**
headers
):
while
url
[
-
1
:]
==
'/'
:
url
=
url
[:
-
1
]
self
.
url
=
url
self
.
headers
=
headers
if
not
headers
.
has_key
(
'Host'
)
and
not
headers
.
has_key
(
'host'
):
headers
[
'Host'
]
=
urlparse
(
url
)[
1
]
self
.
func_name
=
url
[
url
.
rfind
(
'/'
)
+
1
:]
self
.
__dict__
[
'__name__'
]
=
self
.
func_name
self
.
func_defaults
=
self
.
__defaults__
=
()
self
.
args
=
arguments
if
method
is
not
None
:
self
.
method
=
method
if
username
is
not
None
:
self
.
username
=
username
if
password
is
not
None
:
self
.
password
=
password
if
timeout
is
not
None
:
self
.
timeout
=
timeout
mo
=
urlregex
.
match
(
url
)
if
mo
is
not
None
:
host
,
port
,
rurl
=
mo
.
group
(
1
,
2
,
3
)
if
port
:
port
=
int
(
port
[
1
:])
else
:
port
=
80
self
.
host
=
host
self
.
port
=
port
rurl
=
rurl
or
'/'
self
.
rurl
=
rurl
else
:
raise
ValueError
,
url
def
__call__
(
self
,
*
args
,
**
kw
):
method
=
self
.
method
if
method
==
'PUT'
and
len
(
args
)
==
1
and
not
kw
:
query
=
[
args
[
0
]]
args
=
()
else
:
query
=
[]
for
i
in
range
(
len
(
args
)):
try
:
k
=
self
.
args
[
i
]
if
kw
.
has_key
(
k
):
raise
TypeError
,
'Keyword arg redefined'
kw
[
k
]
=
args
[
i
]
except
IndexError
:
raise
TypeError
,
'Too many arguments'
headers
=
{}
for
k
,
v
in
self
.
headers
.
items
():
headers
[
translate
(
k
,
dashtrans
)]
=
v
method
=
self
.
method
if
headers
.
has_key
(
'Content-Type'
):
content_type
=
headers
[
'Content-Type'
]
if
content_type
==
'multipart/form-data'
:
return
self
.
_mp_call
(
kw
)
else
:
content_type
=
None
if
not
method
or
method
==
'POST'
:
for
v
in
kw
.
values
():
if
hasattr
(
v
,
'read'
):
return
self
.
_mp_call
(
kw
)
can_marshal
=
type2marshal
.
has_key
for
k
,
v
in
kw
.
items
():
t
=
type
(
v
)
if
can_marshal
(
t
):
q
=
type2marshal
[
t
](
k
,
v
)
else
:
q
=
'%s=%s'
%
(
k
,
quote
(
v
))
query
.
append
(
q
)
url
=
self
.
rurl
if
query
:
query
=
'&'
.
join
(
query
)
method
=
method
or
'POST'
if
method
==
'PUT'
:
headers
[
'Content-Length'
]
=
str
(
len
(
query
))
if
method
!=
'POST'
:
url
=
"%s?%s"
%
(
url
,
query
)
query
=
''
elif
not
content_type
:
headers
[
'Content-Type'
]
=
'application/x-www-form-urlencoded'
headers
[
'Content-Length'
]
=
str
(
len
(
query
))
else
:
method
=
method
or
'GET'
if
(
self
.
username
and
self
.
password
and
not
headers
.
has_key
(
'Authorization'
)):
headers
[
'Authorization'
]
=
(
"Basic %s"
%
encodestring
(
'%s:%s'
%
(
self
.
username
,
self
.
password
)).
replace
(
'
\
012
'
,
''
)
)
try
:
h
=
HTTP
(
self
.
host
,
self
.
port
)
h
.
putrequest
(
method
,
self
.
rurl
)
for
hn
,
hv
in
headers
.
items
():
h
.
putheader
(
translate
(
hn
,
dashtrans
),
hv
)
h
.
endheaders
()
if
query
:
h
.
send
(
query
)
ec
,
em
,
headers
=
h
.
getreply
()
response
=
h
.
getfile
().
read
()
except
:
raise
NotAvailable
,
RemoteException
(
NotAvailable
,
sys
.
exc_info
()[
1
],
self
.
url
,
query
)
if
(
ec
-
(
ec
%
100
))
==
200
:
return
(
headers
,
response
)
self
.
handleError
(
query
,
ec
,
em
,
headers
,
response
)
def
handleError
(
self
,
query
,
ec
,
em
,
headers
,
response
):
try
:
v
=
headers
.
dict
[
'bobo-exception-value'
]
except
:
v
=
ec
try
:
f
=
headers
.
dict
[
'bobo-exception-file'
]
except
:
f
=
'Unknown'
try
:
l
=
headers
.
dict
[
'bobo-exception-line'
]
except
:
l
=
'Unknown'
try
:
t
=
exceptmap
[
headers
.
dict
[
'bobo-exception-type'
]]
except
:
if
ec
>=
400
and
ec
<
500
:
t
=
NotFound
elif
ec
==
503
:
t
=
NotAvailable
else
:
t
=
ServerError
raise
t
,
RemoteException
(
t
,
v
,
f
,
l
,
self
.
url
,
query
,
ec
,
em
,
response
)
def
_mp_call
(
self
,
kw
,
type2suffix
=
{
type
(
1.0
):
':float'
,
type
(
1
):
':int'
,
type
(
1L
):
':long'
,
type
([]):
':list'
,
type
(()):
':tuple'
,
}
):
# Call a function using the file-upload protcol
# Add type markers to special values:
d
=
{}
special_type
=
type2suffix
.
has_key
for
k
,
v
in
kw
.
items
():
if
':'
not
in
k
:
t
=
type
(
v
)
if
special_type
(
t
):
d
[
'%s%s'
%
(
k
,
type2suffix
[
t
])]
=
v
else
:
d
[
k
]
=
v
else
:
d
[
k
]
=
v
rq
=
[(
'POST %s HTTP/1.0'
%
self
.
rurl
),]
for
n
,
v
in
self
.
headers
.
items
():
rq
.
append
(
'%s: %s'
%
(
n
,
v
))
if
self
.
username
and
self
.
password
:
c
=
encodestring
(
'%s:%s'
%
(
self
.
username
,
self
.
password
)).
replace
(
'
\
012
'
,
''
)
rq
.
append
(
'Authorization: Basic %s'
%
c
)
rq
.
append
(
MultiPart
(
d
).
render
())
rq
=
'
\
r
\
n
'
.
join
(
rq
)
try
:
sock
=
socket
.
socket
(
socket
.
AF_INET
,
socket
.
SOCK_STREAM
)
sock
.
connect
((
self
.
host
,
self
.
port
))
sock
.
send
(
rq
)
reply
=
sock
.
makefile
(
'rb'
)
sock
=
None
line
=
reply
.
readline
()
try
:
[
ver
,
ec
,
em
]
=
line
.
split
(
None
,
2
)
except
ValueError
:
raise
BadReply
,
'Bad reply from server: '
+
line
if
ver
[:
5
]
!=
'HTTP/'
:
raise
BadReply
,
'Bad reply from server: '
+
line
ec
=
int
(
ec
)
em
=
em
.
strip
()
headers
=
mimetools
.
Message
(
reply
,
0
)
response
=
reply
.
read
()
finally
:
if
0
:
raise
NotAvailable
,
(
RemoteException
(
NotAvailable
,
sys
.
exc_info
()[
1
],
self
.
url
,
'<MultiPart Form>'
))
if
ec
==
200
:
return
(
headers
,
response
)
self
.
handleError
(
''
,
ec
,
em
,
headers
,
response
)
class
Object
:
"""Surrogate object for an object on the web"""
username
=
None
password
=
None
method
=
None
timeout
=
None
special_methods
=
'GET'
,
'POST'
,
'PUT'
def
__init__
(
self
,
url
,
method
=
None
,
username
=
None
,
password
=
None
,
timeout
=
None
,
**
headers
):
self
.
url
=
url
self
.
headers
=
headers
if
not
headers
.
has_key
(
'Host'
)
and
not
headers
.
has_key
(
'host'
):
headers
[
'Host'
]
=
urlparse
(
url
)[
1
]
if
method
is
not
None
:
self
.
method
=
method
if
username
is
not
None
:
self
.
username
=
username
if
password
is
not
None
:
self
.
password
=
password
if
timeout
is
not
None
:
self
.
timeout
=
timeout
def
__getattr__
(
self
,
name
):
if
name
in
self
.
special_methods
:
method
=
name
url
=
self
.
url
else
:
method
=
self
.
method
url
=
"%s/%s"
%
(
self
.
url
,
name
)
f
=
Function
(
url
,
method
=
method
,
username
=
self
.
username
,
password
=
self
.
password
,
timeout
=
self
.
timeout
)
f
.
headers
=
self
.
headers
return
f
def
call
(
url
,
username
=
None
,
password
=
None
,
**
kw
):
return
apply
(
Function
(
url
,
username
=
username
,
password
=
password
),
(),
kw
)
##############################################################################
# Implementation details below here
urlregex
=
re
.
compile
(
r'http://([^:/]+)(:[0-9]+)?(/.+)?'
,
re
.
I
)
dashtrans
=
maketrans
(
'_'
,
'-'
)
def
marshal_float
(
n
,
f
):
return
'%s:float=%s'
%
(
n
,
f
)
def
marshal_int
(
n
,
f
):
return
'%s:int=%s'
%
(
n
,
f
)
def
marshal_long
(
n
,
f
):
value
=
'%s:long=%s'
%
(
n
,
f
)
if
value
[
-
1
]
==
'L'
:
value
=
value
[:
-
1
]
return
value
def
marshal_list
(
n
,
l
,
tname
=
'list'
,
lt
=
type
([]),
tt
=
type
(())):
r
=
[]
for
v
in
l
:
t
=
type
(
v
)
if
t
is
lt
or
t
is
tt
:
raise
TypeError
,
'Invalid recursion in data to be marshaled.'
r
.
append
(
marshal_whatever
(
"%s:%s"
%
(
n
,
tname
)
,
v
))
return
'&'
.
join
(
r
)
def
marshal_tuple
(
n
,
l
):
return
marshal_list
(
n
,
l
,
'tuple'
)
type2marshal
=
{
type
(
1.0
):
marshal_float
,
type
(
1
):
marshal_int
,
type
(
1L
):
marshal_long
,
type
([]):
marshal_list
,
type
(()):
marshal_tuple
,
}
def
marshal_whatever
(
k
,
v
):
try
:
q
=
type2marshal
[
type
(
v
)](
k
,
v
)
except
KeyError
:
q
=
'%s=%s'
%
(
k
,
quote
(
str
(
v
)))
return
q
def
querify
(
items
):
query
=
[]
for
k
,
v
in
items
:
query
.
append
(
marshal_whatever
(
k
,
v
))
return
query
and
'&'
.
join
(
query
)
or
''
NotFound
=
'bci.NotFound'
InternalError
=
'bci.InternalError'
BadRequest
=
'bci.BadRequest'
Unauthorized
=
'bci.Unauthorized'
ServerError
=
'bci.ServerError'
NotAvailable
=
'bci.NotAvailable'
exceptmap
=
{
'AttributeError'
:
AttributeError
,
'BadRequest'
:
BadRequest
,
'EOFError'
:
EOFError
,
'IOError'
:
IOError
,
'ImportError'
:
ImportError
,
'IndexError'
:
IndexError
,
'InternalError'
:
InternalError
,
'KeyError'
:
KeyError
,
'MemoryError'
:
MemoryError
,
'NameError'
:
NameError
,
'NotAvailable'
:
NotAvailable
,
'NotFound'
:
NotFound
,
'OverflowError'
:
OverflowError
,
'RuntimeError'
:
RuntimeError
,
'ServerError'
:
ServerError
,
'SyntaxError'
:
SyntaxError
,
'SystemError'
:
SystemError
,
'SystemExit'
:
SystemExit
,
'TypeError'
:
TypeError
,
'Unauthorized'
:
Unauthorized
,
'ValueError'
:
ValueError
,
'ZeroDivisionError'
:
ZeroDivisionError
}
class
RemoteException
:
def
__init__
(
self
,
etype
=
None
,
evalue
=
None
,
efile
=
None
,
eline
=
None
,
url
=
None
,
query
=
None
,
http_code
=
None
,
http_msg
=
None
,
http_resp
=
None
):
"""Contains information about an exception which
occurs in a remote method call"""
self
.
exc_type
=
etype
self
.
exc_value
=
evalue
self
.
exc_file
=
efile
self
.
exc_line
=
eline
self
.
url
=
url
self
.
query
=
query
self
.
http_code
=
http_code
self
.
http_message
=
http_msg
self
.
response
=
http_resp
def
__repr__
(
self
):
return
'%s (File: %s Line: %s)
\
n
%s %s for %s'
%
(
self
.
exc_value
,
self
.
exc_file
,
self
.
exc_line
,
self
.
http_code
,
self
.
http_message
,
self
.
url
)
class
MultiPart
:
def
__init__
(
self
,
*
args
):
c
=
len
(
args
)
if
c
==
1
:
name
,
val
=
None
,
args
[
0
]
elif
c
==
2
:
name
,
val
=
args
[
0
],
args
[
1
]
else
:
raise
ValueError
,
'Invalid arguments'
h
=
{
'Content-Type'
:
{
'_v'
:
''
},
'Content-Transfer-Encoding'
:
{
'_v'
:
''
},
'Content-Disposition'
:
{
'_v'
:
''
},}
dt
=
type
(
val
)
b
=
t
=
None
if
dt
==
DictType
:
t
=
1
b
=
self
.
boundary
()
d
=
[]
h
[
'Content-Type'
][
'_v'
]
=
'multipart/form-data; boundary=%s'
%
b
for
n
,
v
in
val
.
items
():
d
.
append
(
MultiPart
(
n
,
v
))
elif
(
dt
==
ListType
)
or
(
dt
==
TupleType
):
raise
ValueError
,
'Sorry, nested multipart is not done yet!'
elif
dt
==
FileType
or
hasattr
(
val
,
'read'
):
if
hasattr
(
val
,
'name'
):
fn
=
val
.
name
.
replace
(
'
\
\
'
,
'/'
)
fn
=
fn
[(
fn
.
rfind
(
'/'
)
+
1
):]
ex
=
(
fn
[(
fn
.
rfind
(
'.'
)
+
1
):]).
lower
()
if
self
.
_extmap
.
has_key
(
ex
):
ct
=
self
.
_extmap
[
ex
]
else
:
ct
=
self
.
_extmap
[
''
]
else
:
fn
=
''
ct
=
self
.
_extmap
[
None
]
if
self
.
_encmap
.
has_key
(
ct
):
ce
=
self
.
_encmap
[
ct
]
else
:
ce
=
''
h
[
'Content-Disposition'
][
'_v'
]
=
'form-data'
h
[
'Content-Disposition'
][
'name'
]
=
'"%s"'
%
name
h
[
'Content-Disposition'
][
'filename'
]
=
'"%s"'
%
fn
h
[
'Content-Transfer-Encoding'
][
'_v'
]
=
ce
h
[
'Content-Type'
][
'_v'
]
=
ct
d
=
[]
l
=
val
.
read
(
8192
)
while
l
:
d
.
append
(
l
)
l
=
val
.
read
(
8192
)
else
:
h
[
'Content-Disposition'
][
'_v'
]
=
'form-data'
h
[
'Content-Disposition'
][
'name'
]
=
'"%s"'
%
name
d
=
[
str
(
val
)]
self
.
_headers
=
h
self
.
_data
=
d
self
.
_boundary
=
b
self
.
_top
=
t
def
boundary
(
self
):
return
'%s_%s_%s'
%
(
int
(
time
()),
getpid
(),
int
(
random
()
*
1000000000
))
def
render
(
self
):
h
=
self
.
_headers
s
=
[]
if
self
.
_top
:
for
n
,
v
in
h
.
items
():
if
v
[
'_v'
]:
s
.
append
(
'%s: %s'
%
(
n
,
v
[
'_v'
]))
for
k
in
v
.
keys
():
if
k
!=
'_v'
:
s
.
append
(
'; %s=%s'
%
(
k
,
v
[
k
]))
s
.
append
(
'
\
r
\
n
'
)
p
=
[]
t
=
[]
b
=
self
.
_boundary
for
d
in
self
.
_data
:
p
.
append
(
d
.
render
())
t
.
append
(
'--%s
\
n
'
%
b
)
t
.
append
((
'
\
n
--%s
\
n
'
%
b
).
join
(
p
))
t
.
append
(
'
\
n
--%s--
\
n
'
%
b
)
t
=
''
.
join
(
t
)
s
.
append
(
'Content-Length: %s
\
r
\
n
\
r
\
n
'
%
len
(
t
))
s
.
append
(
t
)
return
''
.
join
(
s
)
else
:
for
n
,
v
in
h
.
items
():
if
v
[
'_v'
]:
s
.
append
(
'%s: %s'
%
(
n
,
v
[
'_v'
]))
for
k
in
v
.
keys
():
if
k
!=
'_v'
:
s
.
append
(
'; %s=%s'
%
(
k
,
v
[
k
]))
s
.
append
(
'
\
r
\
n
'
)
s
.
append
(
'
\
r
\
n
'
)
if
self
.
_boundary
:
p
=
[]
b
=
self
.
_boundary
for
d
in
self
.
_data
:
p
.
append
(
d
.
render
())
s
.
append
(
'--%s
\
n
'
%
b
)
s
.
append
((
'
\
n
--%s
\
n
'
%
b
).
join
(
p
))
s
.
append
(
'
\
n
--%s--
\
n
'
%
b
)
return
''
.
join
(
s
)
else
:
return
''
.
join
(
s
+
self
.
_data
)
_extmap
=
{
''
:
'text/plain'
,
'rdb'
:
'text/plain'
,
'html'
:
'text/html'
,
'dtml'
:
'text/html'
,
'htm'
:
'text/html'
,
'dtm'
:
'text/html'
,
'gif'
:
'image/gif'
,
'jpg'
:
'image/jpeg'
,
'exe'
:
'application/octet-stream'
,
None
:
'application/octet-stream'
,
}
_encmap
=
{
'image/gif'
:
'binary'
,
'image/jpg'
:
'binary'
,
'application/octet-stream'
:
'binary'
,
}
def
ErrorTypes
(
code
):
if
code
>=
400
and
code
<
500
:
return
NotFound
if
code
>=
500
and
code
<
600
:
return
ServerError
return
'HTTP_Error_%s'
%
code
usage
=
"""
Usage: %s [-u username:password] url [name=value ...]
where url is the web resource to call.
The -u option may be used to provide a user name and password.
Optional arguments may be provides as name=value pairs.
In a name value pair, if a name ends in ":file", then the value is
treated as a file name and the file is send using the file-upload
protocol. If the file name is "-", then data are taken from standard
input.
The body of the response is written to standard output.
The headers of the response are written to standard error.
"""
%
sys
.
argv
[
0
]
def
main
():
import
getopt
user
=
None
try
:
optlist
,
args
=
getopt
.
getopt
(
sys
.
argv
[
1
:],
'u:'
)
url
=
args
[
0
]
u
=
filter
(
lambda
o
:
o
[
0
]
==
'-u'
,
optlist
)
if
u
:
[
user
,
pw
]
=
u
[
0
][
1
].
split
(
':'
)
kw
=
{}
for
arg
in
args
[
1
:]:
[
name
,
v
]
=
arg
.
split
(
'='
)
if
name
[
-
5
:]
==
':file'
:
name
=
name
[:
-
5
]
if
v
==
'-'
:
v
=
sys
.
stdin
else
:
v
=
open
(
v
,
'rb'
)
kw
[
name
]
=
v
except
:
print
usage
sys
.
exit
(
1
)
# The "main" program for this module
f
=
Function
(
url
)
if
user
:
f
.
username
,
f
.
password
=
user
,
pw
headers
,
body
=
apply
(
f
,(),
kw
)
sys
.
stderr
.
write
(
''
.
join
(
map
(
lambda
h
:
"%s: %s
\
n
"
%
h
,
headers
.
items
()))
+
"
\
n
\
n
"
)
print
body
if
__name__
==
"__main__"
:
main
()
src/ZPublisher/Converters.py
View file @
efe61189
...
...
@@ -12,7 +12,6 @@
##############################################################################
import
re
from
types
import
ListType
,
TupleType
,
UnicodeType
from
DateTime
import
DateTime
from
DateTime.interfaces
import
SyntaxError
from
cgi
import
escape
...
...
@@ -20,89 +19,106 @@ from cgi import escape
# This may get overwritten during configuration
default_encoding
=
'utf-8'
def
field2string
(
v
):
if
hasattr
(
v
,
'read'
):
return
v
.
read
()
elif
isinstance
(
v
,
UnicodeType
):
if
hasattr
(
v
,
'read'
):
return
v
.
read
()
elif
isinstance
(
v
,
unicode
):
return
v
.
encode
(
default_encoding
)
else
:
return
str
(
v
)
def
field2text
(
v
,
nl
=
re
.
compile
(
'
\
r
\
n
|
\
n
\
r
'
).
search
):
v
=
field2string
(
v
)
mo
=
nl
(
v
)
if
mo
is
None
:
return
v
if
mo
is
None
:
return
v
l
=
mo
.
start
(
0
)
r
=
[]
s
=
0
r
=
[]
s
=
0
while
l
>=
s
:
r
.
append
(
v
[
s
:
l
])
s
=
l
+
2
mo
=
nl
(
v
,
s
)
if
mo
is
None
:
l
=-
1
else
:
l
=
mo
.
start
(
0
)
s
=
l
+
2
mo
=
nl
(
v
,
s
)
if
mo
is
None
:
l
=
-
1
else
:
l
=
mo
.
start
(
0
)
r
.
append
(
v
[
s
:])
return
'
\
n
'
.
join
(
r
)
def
field2required
(
v
):
v
=
field2string
(
v
)
if
v
.
strip
():
return
v
raise
ValueError
,
'No input for required field<p>'
if
v
.
strip
():
return
v
raise
ValueError
(
'No input for required field<p>'
)
def
field2int
(
v
):
if
isinstance
(
v
,
(
ListType
,
TupleTyp
e
)):
if
isinstance
(
v
,
(
list
,
tupl
e
)):
return
map
(
field2int
,
v
)
v
=
field2string
(
v
)
if
v
:
try
:
return
int
(
v
)
try
:
return
int
(
v
)
except
ValueError
:
raise
ValueError
,
(
"An integer was expected in the value %s"
%
escape
(
`v`
)
)
raise
ValueError
,
'Empty entry when <strong>integer</strong> expected'
raise
ValueError
(
"An integer was expected in the value %r"
%
escape
(
v
)
)
raise
ValueError
(
'Empty entry when <strong>integer</strong> expected'
)
def
field2float
(
v
):
if
isinstance
(
v
,
(
ListType
,
TupleTyp
e
)):
if
isinstance
(
v
,
(
list
,
tupl
e
)):
return
map
(
field2float
,
v
)
v
=
field2string
(
v
)
if
v
:
try
:
return
float
(
v
)
try
:
return
float
(
v
)
except
ValueError
:
raise
ValueError
,
(
"A floating-point number was expected in the value %
s
"
%
escape
(
`v`
)
)
raise
ValueError
,
(
raise
ValueError
(
"A floating-point number was expected in the value %
r
"
%
escape
(
v
)
)
raise
ValueError
(
'Empty entry when <strong>floating-point number</strong> expected'
)
def
field2long
(
v
):
if
isinstance
(
v
,
(
ListType
,
TupleTyp
e
)):
if
isinstance
(
v
,
(
list
,
tupl
e
)):
return
map
(
field2long
,
v
)
v
=
field2string
(
v
)
# handle trailing 'L' if present.
if
v
[
-
1
:]
in
(
'L'
,
'l'
):
v
=
v
[:
-
1
]
if
v
:
try
:
return
long
(
v
)
try
:
return
int
(
v
)
except
ValueError
:
raise
ValueError
,
(
"A long integer was expected in the value %s"
%
escape
(
`v`
)
)
raise
ValueError
,
'Empty entry when <strong>integer</strong> expected'
raise
ValueError
(
"A long integer was expected in the value %r"
%
escape
(
v
)
)
raise
ValueError
(
'Empty entry when <strong>integer</strong> expected'
)
def
field2tokens
(
v
):
v
=
field2string
(
v
)
return
v
.
split
()
def
field2lines
(
v
):
if
isinstance
(
v
,
(
ListType
,
TupleTyp
e
)):
result
=
[]
if
isinstance
(
v
,
(
list
,
tupl
e
)):
result
=
[]
for
item
in
v
:
result
.
append
(
str
(
item
))
return
result
return
field2text
(
v
).
splitlines
()
def
field2date
(
v
):
v
=
field2string
(
v
)
try
:
...
...
@@ -111,6 +127,7 @@ def field2date(v):
raise
SyntaxError
(
"Invalid DateTime "
+
escape
(
repr
(
v
)))
return
v
def
field2date_international
(
v
):
v
=
field2string
(
v
)
try
:
...
...
@@ -119,46 +136,57 @@ def field2date_international(v):
raise
SyntaxError
(
"Invalid DateTime "
+
escape
(
repr
(
v
)))
return
v
def
field2boolean
(
v
):
if
v
==
'False'
:
return
not
1
return
not
not
v
class
_unicode_converter
:
def
__call__
(
self
,
v
):
# Convert a regular python string. This probably doesnt do what you want,
# whatever that might be. If you are getting exceptions below, you
# probably missed the encoding tag from a form field name. Use:
def
__call__
(
self
,
v
):
# Convert a regular python string. This probably doesn't do
# what you want, whatever that might be. If you are getting
# exceptions below, you probably missed the encoding tag
# from a form field name. Use:
# <input name="description:utf8:ustring" .....
# rather than
# <input name="description:ustring" .....
if
hasattr
(
v
,
'read'
):
v
=
v
.
read
()
if
hasattr
(
v
,
'read'
):
v
=
v
.
read
()
v
=
unicode
(
v
)
return
self
.
convert_unicode
(
v
)
def
convert_unicode
(
self
,
v
):
def
convert_unicode
(
self
,
v
):
raise
NotImplementedError
(
'convert_unicode'
)
class
field2ustring
(
_unicode_converter
):
def
convert_unicode
(
self
,
v
):
def
convert_unicode
(
self
,
v
):
return
v
field2ustring
=
field2ustring
()
class
field2utokens
(
_unicode_converter
):
def
convert_unicode
(
self
,
v
):
def
convert_unicode
(
self
,
v
):
return
v
.
split
()
field2utokens
=
field2utokens
()
class
field2utext
(
_unicode_converter
):
def
convert_unicode
(
self
,
v
):
return
unicode
(
field2text
(
v
.
encode
(
'utf8'
)),
'utf8'
)
def
convert_unicode
(
self
,
v
):
return
unicode
(
field2text
(
v
.
encode
(
'utf8'
)),
'utf8'
)
field2utext
=
field2utext
()
class
field2ulines
:
def
__call__
(
self
,
v
):
if
hasattr
(
v
,
'read'
):
v
=
v
.
read
()
if
isinstance
(
v
,
(
ListType
,
TupleType
)):
if
hasattr
(
v
,
'read'
):
v
=
v
.
read
()
if
isinstance
(
v
,
(
list
,
tuple
)):
return
[
field2ustring
(
x
)
for
x
in
v
]
v
=
unicode
(
v
)
return
self
.
convert_unicode
(
v
)
...
...
@@ -169,21 +197,21 @@ class field2ulines:
field2ulines
=
field2ulines
()
type_converters
=
{
'float'
:
field2float
,
'int'
:
field2int
,
'long'
:
field2long
,
'string'
:
field2string
,
'date'
:
field2date
,
'float'
:
field2float
,
'int'
:
field2int
,
'long'
:
field2long
,
'string'
:
field2string
,
'date'
:
field2date
,
'date_international'
:
field2date_international
,
'required'
:
field2required
,
'tokens'
:
field2tokens
,
'lines'
:
field2lines
,
'text'
:
field2text
,
'boolean'
:
field2boolean
,
'ustring'
:
field2ustring
,
'utokens'
:
field2utokens
,
'ulines'
:
field2ulines
,
'utext'
:
field2utext
,
}
get_converter
=
type_converters
.
get
'required'
:
field2required
,
'tokens'
:
field2tokens
,
'lines'
:
field2lines
,
'text'
:
field2text
,
'boolean'
:
field2boolean
,
'ustring'
:
field2ustring
,
'utokens'
:
field2utokens
,
'ulines'
:
field2ulines
,
'utext'
:
field2utext
,
}
get_converter
=
type_converters
.
get
src/ZPublisher/HTTPRangeSupport.py
View file @
efe61189
...
...
@@ -19,11 +19,13 @@ flag-interface and some support functions for implementing this functionality.
For an implementation example, see the File class in OFS/Image.py.
"""
import
re
,
sys
import
re
import
sys
from
zope.interface
import
Interface
WHITESPACE
=
re
.
compile
(
'
\
s*
'
, re.MULTILINE)
def parseRange(header):
"""RFC 2616 (HTTP 1.1) Range header parsing.
...
...
@@ -32,7 +34,6 @@ def parseRange(header):
end offset to be inclusive, we return python convention indexes, where the
end is exclusive. Syntactically incorrect headers are to be ignored, so if
we encounter one we return None.
"""
ranges = []
...
...
@@ -43,8 +44,11 @@ def parseRange(header):
header = WHITESPACE.sub('', header)
# A range header only can specify a byte range
try: spec, sets = header.split('
=
')
except ValueError: return None
try:
spec, sets = header.split('
=
')
except ValueError:
return None
if spec != '
bytes
':
return None
...
...
@@ -57,8 +61,10 @@ def parseRange(header):
return None
for set in sets:
try: start, end = set.split('
-
')
except ValueError: return None
try:
start, end = set.split('
-
')
except ValueError:
return None
# Catch empty sets
if not start and not end:
...
...
@@ -67,10 +73,14 @@ def parseRange(header):
# Convert to integers or None (which will raise errors if
# non-integers were used (which is what we want)).
try:
if start == '': start = None
else: start = int(start)
if end == '': end = None
else: end = int(end)
if start == '':
start = None
else:
start = int(start)
if end == '':
end = None
else:
end = int(end)
except ValueError:
return None
...
...
@@ -84,7 +94,7 @@ def parseRange(header):
if not start:
start = sys.maxint
elif end is not None:
end = end + 1 # Make the end of the range exclusive
end = end + 1
# Make the end of the range exclusive
if end is not None and end <= start:
return None
...
...
@@ -94,11 +104,11 @@ def parseRange(header):
return ranges
def expandRanges(ranges, size):
"""Expand Range sets, given those sets and the length of the resource.
Expansion means relative start values and open ends
"""
expanded = []
...
...
@@ -107,13 +117,15 @@ def expandRanges(ranges, size):
if start < 0:
start = size + start
end = end or size
if end > size: end = size
if end > size:
end = size
# Only use satisfiable ranges
if start < size:
add((start, end))
return expanded
class HTTPRangeInterface(Interface):
"""Objects implementing this Interface support the HTTP Range header.
...
...
@@ -124,5 +136,4 @@ class HTTPRangeInterface(Interface):
This interface specifies no methods, as this functionality can either be
implemented in the index_html or __call__ methods of a published object.
"""
src/ZPublisher/HTTPResponse.py
View file @
efe61189
...
...
@@ -64,28 +64,30 @@ status_codes['resourcelockederror'] = 423
start_of_header_search
=
re
.
compile
(
'(<head[^>]*>)'
,
re
.
IGNORECASE
).
search
_gzip_header
=
(
"
\
037
\
213
"
# magic
"
\
010
"
# compression method
"
\
000
"
# flags
"
\
000
\
000
\
000
\
000
"
# time
_gzip_header
=
(
"
\
037
\
213
"
# magic
"
\
010
"
# compression method
"
\
000
"
# flags
"
\
000
\
000
\
000
\
000
"
# time
"
\
002
"
"
\
377
"
)
uncompressableMimeMajorTypes
=
(
'image'
,)
# these mime major types shoul
d
# not be gzip content encoded
# these mime major types should not be gzip content encode
d
uncompressableMimeMajorTypes
=
(
'image'
,)
# The environment variable DONT_GZIP_MAJOR_MIME_TYPES can be set to a list
# of comma seperated mime major types which should also not be compressed
otherTypes
=
os
.
environ
.
get
(
'DONT_GZIP_MAJOR_MIME_TYPES'
,
''
).
lower
()
otherTypes
=
os
.
environ
.
get
(
'DONT_GZIP_MAJOR_MIME_TYPES'
,
''
).
lower
()
if
otherTypes
:
uncompressableMimeMajorTypes
+=
tuple
(
otherTypes
.
split
(
','
))
_CRLF
=
re
.
compile
(
r'[\r\n]'
)
def
_scrubHeader
(
name
,
value
):
return
''
.
join
(
_CRLF
.
split
(
str
(
name
))),
''
.
join
(
_CRLF
.
split
(
str
(
value
)))
class
HTTPResponse
(
BaseResponse
):
""" An object representation of an HTTP response.
...
...
@@ -104,7 +106,7 @@ class HTTPResponse(BaseResponse):
If stream oriented output is used, then the response object
passed into the object must be used.
"""
#'
"""
body
=
''
base
=
''
...
...
@@ -124,8 +126,7 @@ class HTTPResponse(BaseResponse):
status
=
200
,
headers
=
None
,
stdout
=
sys
.
stdout
,
stderr
=
sys
.
stderr
,
):
stderr
=
sys
.
stderr
):
""" Create a new response using the given values.
"""
if
headers
is
None
:
...
...
@@ -166,8 +167,8 @@ class HTTPResponse(BaseResponse):
# It has already been determined.
return
if
(
isinstance
(
status
,
(
type
,
types
.
ClassType
))
and
issubclass
(
status
,
Exception
)):
if
(
isinstance
(
status
,
(
type
,
types
.
ClassType
))
and
issubclass
(
status
,
Exception
)):
status
=
status
.
__name__
if
isinstance
(
status
,
str
):
...
...
@@ -304,7 +305,7 @@ class HTTPResponse(BaseResponse):
h
=
"%s%s%s"
%
(
h
,
delimiter
,
value
)
else
:
h
=
value
self
.
setHeader
(
name
,
h
,
scrubbed
=
True
)
self
.
setHeader
(
name
,
h
,
scrubbed
=
True
)
def
addHeader
(
self
,
name
,
value
):
""" Set a new HTTP return header with the given value,
...
...
@@ -334,8 +335,7 @@ class HTTPResponse(BaseResponse):
self
.
base
=
str
(
base
)
def
insertBase
(
self
,
base_re_search
=
re
.
compile
(
'(<base.*?>)'
,
re
.
I
).
search
):
base_re_search
=
re
.
compile
(
'(<base.*?>)'
,
re
.
I
).
search
):
# Only insert a base tag if content appears to be html.
content_type
=
self
.
headers
.
get
(
'content-type'
,
''
).
split
(
';'
)[
0
]
...
...
@@ -351,8 +351,8 @@ class HTTPResponse(BaseResponse):
ibase
=
base_re_search
(
body
)
if
ibase
is
None
:
self
.
body
=
(
'%s
\
n
<base href="%s" />
\
n
%s'
%
(
body
[:
index
],
escape
(
self
.
base
,
1
),
body
[
index
:]))
(
body
[:
index
],
escape
(
self
.
base
,
1
),
body
[
index
:]))
self
.
setHeader
(
'content-length'
,
len
(
self
.
body
))
def
isHTML
(
self
,
s
):
...
...
@@ -368,11 +368,10 @@ class HTTPResponse(BaseResponse):
def
setBody
(
self
,
body
,
title
=
''
,
is_error
=
0
,
bogus_str_search
=
re
.
compile
(
" [a-fA-F0-9]+>$"
).
search
,
latin1_alias_match
=
re
.
compile
(
r'text/html(\
s*;
\s*charset=((latin)|(latin[-_]?1)|'
r'(cp1252)|(cp819)|(csISOLatin1)|(IBM819)|(iso-ir-100)|'
r'(iso[-_]8859[-_]1(:1987)?)))?$'
,
re
.
I
).
match
,
lock
=
None
):
r'text/html(\
s*;
\s*charset=((latin)|(latin[-_]?1)|'
r'(cp1252)|(cp819)|(csISOLatin1)|(IBM819)|(iso-ir-100)|'
r'(iso[-_]8859[-_]1(:1987)?)))?$'
,
re
.
I
).
match
,
lock
=
None
):
""" Set the body of the response
Sets the return body equal to the (string) argument "body". Also
...
...
@@ -411,7 +410,7 @@ class HTTPResponse(BaseResponse):
title
,
body
=
body
if
not
isinstance
(
body
,
str
):
if
hasattr
(
body
,
'asHTML'
):
if
hasattr
(
body
,
'asHTML'
):
body
=
body
.
asHTML
()
if
isinstance
(
body
,
unicode
):
...
...
@@ -425,8 +424,8 @@ class HTTPResponse(BaseResponse):
body
=
self
.
_encode_unicode
(
unicode
(
body
))
l
=
len
(
body
)
if
((
l
<
200
)
and
body
[:
1
]
==
'<'
and
body
.
find
(
'>'
)
==
l
-
1
and
bogus_str_search
(
body
)
is
not
None
):
if
((
l
<
200
)
and
body
[:
1
]
==
'<'
and
body
.
find
(
'>'
)
==
l
-
1
and
bogus_str_search
(
body
)
is
not
None
):
self
.
notFoundError
(
body
[
1
:
-
1
])
else
:
if
title
:
...
...
@@ -444,7 +443,7 @@ class HTTPResponse(BaseResponse):
# special characters. These cannot be removed by html_quote,
# because this is not the case for all encodings.
if
(
content_type
==
'text/html'
or
content_type
and
latin1_alias_match
(
content_type
)
is
not
None
):
content_type
and
latin1_alias_match
(
content_type
)
is
not
None
):
body
=
'<'
.
join
(
body
.
split
(
'
\
213
'
))
body
=
'>'
.
join
(
body
.
split
(
'
\
233
'
))
self
.
body
=
body
...
...
@@ -457,7 +456,7 @@ class HTTPResponse(BaseResponse):
self
.
setHeader
(
'content-type'
,
content_type
)
else
:
if
(
content_type
.
startswith
(
'text/'
)
and
'charset='
not
in
content_type
):
'charset='
not
in
content_type
):
content_type
=
'%s; charset=%s'
%
(
content_type
,
default_encoding
)
self
.
setHeader
(
'content-type'
,
content_type
)
...
...
@@ -466,25 +465,25 @@ class HTTPResponse(BaseResponse):
self
.
insertBase
()
if
self
.
use_HTTP_content_compression
and
\
self
.
headers
.
get
(
'content-encoding'
,
'gzip'
)
==
'gzip'
:
if
(
self
.
use_HTTP_content_compression
and
self
.
headers
.
get
(
'content-encoding'
,
'gzip'
)
==
'gzip'
)
:
# use HTTP content encoding to compress body contents unless
# this response already has another type of content encoding
if
content_type
.
split
(
'/'
)[
0
]
not
in
uncompressableMimeMajorTypes
:
# only compress if not listed as uncompressable
body
=
self
.
body
startlen
=
len
(
body
)
co
=
zlib
.
compressobj
(
6
,
zlib
.
DEFLATED
,
-
zlib
.
MAX_WBITS
,
zlib
.
DEF_MEM_LEVEL
,
0
)
co
=
zlib
.
compressobj
(
6
,
zlib
.
DEFLATED
,
-
zlib
.
MAX_WBITS
,
zlib
.
DEF_MEM_LEVEL
,
0
)
chunks
=
[
_gzip_header
,
co
.
compress
(
body
),
co
.
flush
(),
struct
.
pack
(
"<ll"
,
zlib
.
crc32
(
body
),
startlen
)]
struct
.
pack
(
"<ll"
,
zlib
.
crc32
(
body
),
startlen
)]
z
=
""
.
join
(
chunks
)
newlen
=
len
(
z
)
if
newlen
<
startlen
:
self
.
body
=
z
self
.
setHeader
(
'content-length'
,
newlen
)
self
.
setHeader
(
'content-encoding'
,
'gzip'
)
self
.
setHeader
(
'content-encoding'
,
'gzip'
)
if
self
.
use_HTTP_content_compression
==
1
:
# use_HTTP_content_compression == 1 if force was
# NOT used in enableHTTPCompression().
...
...
@@ -542,7 +541,7 @@ class HTTPResponse(BaseResponse):
self
.
use_HTTP_content_compression
=
0
elif
(
force
or
(
REQUEST
.
get
(
'HTTP_ACCEPT_ENCODING'
,
''
).
find
(
'gzip'
)
!=
-
1
)):
(
REQUEST
.
get
(
'HTTP_ACCEPT_ENCODING'
,
''
).
find
(
'gzip'
)
!=
-
1
)):
if
force
:
self
.
use_HTTP_content_compression
=
2
else
:
...
...
@@ -574,11 +573,11 @@ class HTTPResponse(BaseResponse):
"""
return
self
.
_shutdown_flag
is
not
None
def
_encode_unicode
(
self
,
body
,
def
_encode_unicode
(
self
,
body
,
charset_re
=
re
.
compile
(
r'(?:application|text)/[-+0-9a-z]+\
s*;
\s*'
+
r'charset=([-_0-9a-z]+'
+
r')(?:(?:\
s*;)|
\Z)'
,
re
.
IGNORECASE
)):
r'(?:application|text)/[-+0-9a-z]+\
s*;
\s*'
+
r'charset=([-_0-9a-z]+'
+
r')(?:(?:\
s*;)|
\Z)'
,
re
.
IGNORECASE
)):
def
fix_xml_preamble
(
body
,
encoding
):
""" fixes the encoding in the XML preamble according
...
...
@@ -587,8 +586,8 @@ class HTTPResponse(BaseResponse):
if
body
.
startswith
(
'<?xml'
):
pos_right
=
body
.
find
(
'?>'
)
# right end of the XML preamble
body
=
(
'<?xml version="1.0" encoding="%s" ?>'
%
encoding
)
+
body
[
pos_right
+
2
:]
body
=
(
'<?xml version="1.0" encoding="%s" ?>'
%
encoding
)
+
body
[
pos_right
+
2
:]
return
body
# Encode the Unicode data as requested
...
...
@@ -603,8 +602,8 @@ class HTTPResponse(BaseResponse):
return
body
else
:
if
ct
.
startswith
(
'text/'
)
or
ct
.
startswith
(
'application/'
):
self
.
headers
[
'content-type'
]
=
'%s; charset=%s'
%
(
ct
,
default_encoding
)
self
.
headers
[
'content-type'
]
=
'%s; charset=%s'
%
(
ct
,
default_encoding
)
# Use the default character encoding
body
=
body
.
encode
(
default_encoding
,
'replace'
)
...
...
@@ -619,12 +618,11 @@ class HTTPResponse(BaseResponse):
tb
=
format_exception
(
t
,
v
,
tb
,
as_html
=
as_html
)
return
'
\
n
'
.
join
(
tb
)
def
_html
(
self
,
title
,
body
):
def
_html
(
self
,
title
,
body
):
return
(
"<html>
\
n
"
"<head>
\
n
<title>%s</title>
\
n
</head>
\
n
"
"<body>
\
n
%s
\
n
</body>
\
n
"
"</html>
\
n
"
%
(
title
,
body
))
"</html>
\
n
"
%
(
title
,
body
))
def
_error_html
(
self
,
title
,
body
):
return
(
"""<html>
...
...
@@ -635,8 +633,7 @@ class HTTPResponse(BaseResponse):
</p>
<p><strong>%s</strong></p>
%s"""
%
(
title
,
body
)
+
\
"""
%s"""
%
(
title
,
body
)
+
"""
<hr noshade="noshade"/>
<p>Troubleshooting Suggestions</p>
...
...
@@ -652,7 +649,7 @@ class HTTPResponse(BaseResponse):
Thank you for your patience.
</p></body></html>"""
)
def
notFoundError
(
self
,
entry
=
'Unknown'
):
def
notFoundError
(
self
,
entry
=
'Unknown'
):
self
.
setStatus
(
404
)
raise
NotFound
(
self
.
_error_html
(
"Resource not found"
,
...
...
@@ -660,18 +657,18 @@ class HTTPResponse(BaseResponse):
"<p>Check the URL and try again.</p>"
+
"<p><b>Resource:</b> %s</p>"
%
escape
(
entry
)))
forbiddenError
=
notFoundError
# If a resource is forbidden,
# why reveal that it exists?
# If a resource is forbidden, why reveal that it exists?
forbiddenError
=
notFoundError
def
debugError
(
self
,
entry
):
def
debugError
(
self
,
entry
):
raise
NotFound
(
self
.
_error_html
(
"Debugging Notice"
,
"Zope has encountered a problem publishing your object.<p>"
"
\
n
%s</p>"
%
entry
))
def
badRequestError
(
self
,
name
):
def
badRequestError
(
self
,
name
):
self
.
setStatus
(
400
)
if
re
.
match
(
'^[A-Z_0-9]+$'
,
name
):
if
re
.
match
(
'^[A-Z_0-9]+$'
,
name
):
raise
InternalError
(
self
.
_error_html
(
"Internal Error"
,
"Sorry, an internal error occurred in this resource."
))
...
...
@@ -682,7 +679,7 @@ class HTTPResponse(BaseResponse):
"was omitted from the request.<p>"
+
"Make sure to specify all required parameters, "
+
"and try the request again.</p>"
))
))
def
_unauthorized
(
self
):
realm
=
self
.
realm
...
...
@@ -749,9 +746,9 @@ class HTTPResponse(BaseResponse):
if self.status == 300:
self.setStatus(302)
self.setHeader('
location
', v)
tb = None # just one path covered
tb = None
# just one path covered
return self
elif isinstance(v, Redirect): # death to string exceptions!
elif isinstance(v, Redirect):
# death to string exceptions!
if self.status == 300:
self.setStatus(302)
self.setHeader('
location
', v.args[0])
...
...
@@ -761,16 +758,15 @@ class HTTPResponse(BaseResponse):
else:
try:
l, b = v
if (isinstance(l, str)
and absuri_match(l) is not None):
if (isinstance(l, str) and absuri_match(l) is not None):
if self.status == 300:
self.setStatus(302)
self.setHeader('
location
', l)
self.setBody(b)
tb = None # one more patch covered
tb = None
# one more patch covered
return self
except:
pass # tb is not cleared in this case
except
Exception
:
pass
# tb is not cleared in this case
b = v
if isinstance(b, Exception):
...
...
@@ -785,8 +781,8 @@ class HTTPResponse(BaseResponse):
if fatal and t is SystemExit and v.code == 0:
body = self.setBody(
(str(t),
'
Zope
has
exited
normally
.
<
p
>
'
+
self._traceback(t, v, tb) + '
</
p
>
'),
'
Zope
has
exited
normally
.
<
p
>
'
+
self._traceback(t, v, tb) + '
</
p
>
'),
is_error=1)
else:
try:
...
...
@@ -796,9 +792,8 @@ class HTTPResponse(BaseResponse):
if match is None:
body = self.setBody(
(str(t),
'
Sorry
,
a
site
error
occurred
.
<
p
>
'
+ self._traceback(t, v, tb)
+ '
</
p
>
'),
'
Sorry
,
a
site
error
occurred
.
<
p
>
' +
self._traceback(t, v, tb) + '
</
p
>
'),
is_error=1)
elif self.isHTML(b):
# error is an HTML document, not just a snippet of html
...
...
@@ -809,7 +804,7 @@ class HTTPResponse(BaseResponse):
body = self.setBody(b, is_error=1)
else:
body = self.setBody(
(str(t), b + self._traceback(t,'
(
see
above
)
', tb, 0)),
(str(t), b + self._traceback(t,
'
(
see
above
)
', tb, 0)),
is_error=1)
del tb
return body
...
...
@@ -831,15 +826,15 @@ class HTTPResponse(BaseResponse):
for name, v in attrs.items():
name = name.lower()
if name == '
expires
':
cookie = '
%
s
;
Expires
=%
s
' % (cookie,v)
cookie = '
%
s
;
Expires
=%
s
' % (cookie,
v)
elif name == '
domain
':
cookie = '
%
s
;
Domain
=%
s
' % (cookie,v)
cookie = '
%
s
;
Domain
=%
s
' % (cookie,
v)
elif name == '
path
':
cookie = '
%
s
;
Path
=%
s
' % (cookie,v)
cookie = '
%
s
;
Path
=%
s
' % (cookie,
v)
elif name == '
max_age
':
cookie = '
%
s
;
Max
-
Age
=%
s
' % (cookie,v)
cookie = '
%
s
;
Max
-
Age
=%
s
' % (cookie,
v)
elif name == '
comment
':
cookie = '
%
s
;
Comment
=%
s
' % (cookie,v)
cookie = '
%
s
;
Comment
=%
s
' % (cookie,
v)
elif name == '
secure
' and v:
cookie = '
%
s
;
Secure
' % cookie
# Some browsers recognize this cookie attribute
...
...
@@ -856,8 +851,8 @@ class HTTPResponse(BaseResponse):
""" Set headers required by various parts of protocol.
"""
body = self.body
if (
not '
content
-
length
'
in self.headers and
not '
transfer
-
encoding
'
in self.headers):
if (
'
content
-
length
' not
in self.headers and
'
transfer
-
encoding
' not
in self.headers):
self.setHeader('
content
-
length
', len(body))
return "%d %s" % (self.status, self.errmsg), self.listHeaders()
...
...
@@ -868,7 +863,7 @@ class HTTPResponse(BaseResponse):
"""
result = [
('
X
-
Powered
-
By
', '
Zope
(
www
.
zope
.
org
),
Python
(
www
.
python
.
org
)
')
('
X
-
Powered
-
By
', '
Zope
(
www
.
zope
.
org
),
Python
(
www
.
python
.
org
)
')
]
for key, value in self.headers.items():
...
...
@@ -881,9 +876,7 @@ class HTTPResponse(BaseResponse):
result.extend(self.accumulated_headers)
return result
def __str__(self,
html_search=re.compile('
<
html
>
',re.I).search,
):
def __str__(self, html_search=re.compile('
<
html
>
', re.I).search):
if self._wrote:
return '' # Streaming output was used.
...
...
@@ -902,8 +895,8 @@ class HTTPResponse(BaseResponse):
chunks.append(body)
return '
\
r
\
n
'.join(chunks)
def write(self,data):
"""
\
def write(self,
data):
"""
Return data as a stream
HTML data may be returned using a stream-oriented interface.
...
...
@@ -915,10 +908,8 @@ class HTTPResponse(BaseResponse):
Note that published objects must not generate any errors
after beginning stream-oriented output.
"""
if not self._wrote:
notify(PubBeforeStreaming(self))
self.outputBody()
...
...
src/ZPublisher/Iterators.py
View file @
efe61189
from
zope.interface
import
Interface
from
zope.interface
import
implements
class
IUnboundStreamIterator
(
Interface
):
"""
An iterator with unknown length that can be published.
...
...
@@ -25,7 +26,8 @@ class IStreamIterator(IUnboundStreamIterator):
is still closed, ZODB would raise an error. If the connection
happens to be re-opened by another thread, ZODB might allow it,
but it has a chance of going insane if it happens to be loading
or storing something in the other thread at the same time. """
or storing something in the other thread at the same time.
"""
def
__len__
():
"""
...
...
@@ -42,7 +44,7 @@ class filestream_iterator(file):
implements
(
IStreamIterator
)
def
__init__
(
self
,
name
,
mode
=
'r'
,
bufsize
=-
1
,
streamsize
=
1
<<
16
):
def
__init__
(
self
,
name
,
mode
=
'r'
,
bufsize
=-
1
,
streamsize
=
1
<<
16
):
file
.
__init__
(
self
,
name
,
mode
,
bufsize
)
self
.
streamsize
=
streamsize
...
...
@@ -57,5 +59,4 @@ class filestream_iterator(file):
self
.
seek
(
0
,
2
)
size
=
self
.
tell
()
self
.
seek
(
cur_pos
,
0
)
return
size
src/ZPublisher/Publish.py
View file @
efe61189
...
...
@@ -14,6 +14,7 @@
"""
import
os
import
sys
from
thread
import
allocate_lock
import
transaction
from
urlparse
import
urlparse
...
...
@@ -24,11 +25,10 @@ from zope.publisher.interfaces.browser import IBrowserPage
from
zope.publisher.skinnable
import
setDefaultSkin
from
zope.security.management
import
newInteraction
,
endInteraction
from
.mapply
import
mapply
from
.maybe_lock
import
allocate_lock
from
ZPublisher.mapply
import
mapply
from
ZPublisher
import
pubevents
from
.Request
import
Request
from
.Response
import
Response
from
ZPublisher.HTTPRequest
import
HTTPRequest
as
Request
from
ZPublisher.HTTPResponse
import
HTTPResponse
as
Response
class
Retry
(
Exception
):
...
...
@@ -36,37 +36,47 @@ class Retry(Exception):
"""
def
__init__
(
self
,
t
=
None
,
v
=
None
,
tb
=
None
):
self
.
_args
=
t
,
v
,
tb
self
.
_args
=
t
,
v
,
tb
def
reraise
(
self
):
t
,
v
,
tb
=
self
.
_args
if
t
is
None
:
t
=
Retry
if
tb
is
None
:
raise
t
,
v
try
:
raise
t
,
v
,
tb
finally
:
tb
=
None
if
t
is
None
:
t
=
Retry
if
tb
is
None
:
raise
t
(
v
)
try
:
raise
t
,
v
,
tb
finally
:
tb
=
None
def
call_object
(
object
,
args
,
request
):
re
sult
=
apply
(
object
,
args
)
# Type s<cr> to step into published object.
return
result
re
turn
object
(
*
args
)
def
missing_name
(
name
,
request
):
if
name
==
'self'
:
return
request
[
'PARENTS'
][
0
]
if
name
==
'self'
:
return
request
[
'PARENTS'
][
0
]
request
.
response
.
badRequestError
(
name
)
def
dont_publish_class
(
klass
,
request
):
request
.
response
.
forbiddenError
(
"class %s"
%
klass
.
__name__
)
_default_debug_mode
=
False
_default_realm
=
None
def
set_default_debug_mode
(
debug_mode
):
global
_default_debug_mode
_default_debug_mode
=
debug_mode
def
set_default_authentication_realm
(
realm
):
global
_default_realm
_default_realm
=
realm
def
publish
(
request
,
module_name
,
after_list
,
debug
=
0
,
# Optimize:
call_object
=
call_object
,
...
...
@@ -76,10 +86,10 @@ def publish(request, module_name, after_list, debug=0,
):
(
bobo_before
,
bobo_after
,
object
,
realm
,
debug_mode
,
err_hook
,
validated_hook
,
transactions_manager
)
=
get_module_info
(
module_name
)
validated_hook
,
transactions_manager
)
=
get_module_info
(
module_name
)
parents
=
None
response
=
None
parents
=
None
response
=
None
try
:
notify
(
pubevents
.
PubStart
(
request
))
...
...
@@ -88,8 +98,8 @@ def publish(request, module_name, after_list, debug=0,
request
.
processInputs
()
request_get
=
request
.
get
response
=
request
.
response
request_get
=
request
.
get
response
=
request
.
response
# First check for "cancel" redirect:
if
request_get
(
'SUBMIT'
,
''
).
strip
().
lower
()
==
'cancel'
:
...
...
@@ -105,27 +115,27 @@ def publish(request, module_name, after_list, debug=0,
cancel
=
''
break
if
cancel
:
raise
Redirect
,
cancel
raise
Redirect
(
cancel
)
after_list
[
0
]
=
bobo_after
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
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'
)
path
=
request_get
(
'PATH_INFO'
)
request
[
'PARENTS'
]
=
parents
=
[
object
]
request
[
'PARENTS'
]
=
parents
=
[
object
]
if
transactions_manager
:
transactions_manager
.
begin
()
object
=
request
.
traverse
(
path
,
validated_hook
=
validated_hook
)
object
=
request
.
traverse
(
path
,
validated_hook
=
validated_hook
)
if
IBrowserPage
.
providedBy
(
object
):
request
.
postProcessInputs
()
...
...
@@ -135,11 +145,11 @@ def publish(request, module_name, after_list, debug=0,
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
)
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
)
...
...
@@ -163,16 +173,16 @@ def publish(request, module_name, after_list, debug=0,
if
sm
is
not
None
:
from
asyncore
import
compact_traceback
cl
,
val
=
sys
.
exc_info
()[:
2
]
cl
,
val
=
sys
.
exc_info
()[:
2
]
sm
(
'%s: %s %s'
%
(
getattr
(
cl
,
'__name__'
,
cl
),
val
,
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
]
parents
=
parents
[
0
]
try
:
try
:
return
err_hook
(
parents
,
request
,
...
...
@@ -189,7 +199,8 @@ def publish(request, module_name, after_list, debug=0,
)
retry
=
True
finally
:
# Note: 'abort's can fail. Nevertheless, we want end request handling
# Note: 'abort's can fail.
# Nevertheless, we want end request handling.
try
:
try
:
notify
(
pubevents
.
PubBeforeAbort
(
...
...
@@ -202,7 +213,7 @@ def publish(request, module_name, after_list, debug=0,
notify
(
pubevents
.
PubFailure
(
request
,
exc_info
,
retry
))
# Only reachable if Retry is raised and request supports retry.
newrequest
=
request
.
retry
()
newrequest
=
request
.
retry
()
request
.
close
()
# Free resources held by the request.
# Set the default layer/skin on the newly generated request
...
...
@@ -214,7 +225,8 @@ def publish(request, module_name, after_list, debug=0,
newrequest
.
close
()
else
:
# Note: 'abort's can fail. Nevertheless, we want end request handling
# Note: 'abort's can fail.
# Nevertheless, we want end request handling.
try
:
try
:
notify
(
pubevents
.
PubBeforeAbort
(
request
,
exc_info
,
False
))
...
...
@@ -226,24 +238,26 @@ def publish(request, module_name, after_list, debug=0,
notify
(
pubevents
.
PubFailure
(
request
,
exc_info
,
False
))
raise
def
publish_module_standard
(
module_name
,
stdin
=
sys
.
stdin
,
stdout
=
sys
.
stdout
,
stderr
=
sys
.
stderr
,
environ
=
os
.
environ
,
debug
=
0
,
request
=
None
,
response
=
None
):
must_die
=
0
status
=
200
after_list
=
[
None
]
def
publish_module_standard
(
module_name
,
stdin
=
sys
.
stdin
,
stdout
=
sys
.
stdout
,
stderr
=
sys
.
stderr
,
environ
=
os
.
environ
,
debug
=
0
,
request
=
None
,
response
=
None
):
must_die
=
0
status
=
200
after_list
=
[
None
]
try
:
try
:
if
response
is
None
:
response
=
Response
(
stdout
=
stdout
,
stderr
=
stderr
)
response
=
Response
(
stdout
=
stdout
,
stderr
=
stderr
)
else
:
stdout
=
response
.
stdout
stdout
=
response
.
stdout
# debug is just used by tests (has nothing to do with debug_mode!)
response
.
handle_errors
=
not
debug
if
request
is
None
:
request
=
Request
(
stdin
,
environ
,
response
)
request
=
Request
(
stdin
,
environ
,
response
)
# make sure that the request we hand over has the
# default layer/skin set on it; subsequent code that
...
...
@@ -267,116 +281,129 @@ def publish_module_standard(module_name,
status
=
response
.
getStatus
()
if
response
:
outputBody
=
getattr
(
response
,
'outputBody'
,
None
)
outputBody
=
getattr
(
response
,
'outputBody'
,
None
)
if
outputBody
is
not
None
:
outputBody
()
else
:
response
=
str
(
response
)
if
response
:
stdout
.
write
(
response
)
response
=
str
(
response
)
if
response
:
stdout
.
write
(
response
)
# The module defined a post-access function, call it
if
after_list
[
0
]
is
not
None
:
after_list
[
0
]()
if
after_list
[
0
]
is
not
None
:
after_list
[
0
]()
finally
:
if
request
is
not
None
:
request
.
close
()
if
request
is
not
None
:
request
.
close
()
if
must_die
:
# Try to turn exception value into an exit code.
try
:
if
hasattr
(
must_die
[
1
],
'code'
):
code
=
must_die
[
1
].
code
else
:
code
=
int
(
must_die
[
1
])
else
:
code
=
int
(
must_die
[
1
])
except
:
code
=
must_die
[
1
]
and
1
or
0
if
hasattr
(
request
.
response
,
'_requestShutdown'
):
request
.
response
.
_requestShutdown
(
code
)
try
:
raise
must_die
[
0
],
must_die
[
1
],
must_die
[
2
]
finally
:
must_die
=
None
try
:
raise
must_die
[
0
],
must_die
[
1
],
must_die
[
2
]
finally
:
must_die
=
None
return
status
_l
=
allocate_lock
()
_l
=
allocate_lock
()
def
get_module_info
(
module_name
,
modules
=
{},
acquire
=
_l
.
acquire
,
release
=
_l
.
release
,
):
release
=
_l
.
release
):
if
module_name
in
modules
:
return
modules
[
module_name
]
if
module_name
in
modules
:
return
modules
[
module_name
]
if
module_name
[
-
4
:]
==
'.cgi'
:
module_name
=
module_name
[:
-
4
]
if
module_name
[
-
4
:]
==
'.cgi'
:
module_name
=
module_name
[:
-
4
]
acquire
()
tb
=
None
tb
=
None
g
=
globals
()
try
:
try
:
module
=
__import__
(
module_name
,
g
,
g
,
(
'__doc__'
,))
module
=
__import__
(
module_name
,
g
,
g
,
(
'__doc__'
,))
# Let the app specify a realm
if
hasattr
(
module
,
'__bobo_realm__'
):
realm
=
module
.
__bobo_realm__
if
hasattr
(
module
,
'__bobo_realm__'
):
realm
=
module
.
__bobo_realm__
elif
_default_realm
is
not
None
:
realm
=
_default_realm
realm
=
_default_realm
else
:
realm
=
module_name
realm
=
module_name
# Check for debug mode
debug_mode
=
None
if
hasattr
(
module
,
'__bobo_debug_mode__'
):
debug_mode
=
not
not
module
.
__bobo_debug_mode__
debug_mode
=
None
if
hasattr
(
module
,
'__bobo_debug_mode__'
):
debug_mode
=
bool
(
module
.
__bobo_debug_mode__
)
else
:
debug_mode
=
_default_debug_mode
bobo_before
=
getattr
(
module
,
"__bobo_before__"
,
None
)
bobo_after
=
getattr
(
module
,
"__bobo_after__"
,
None
)
if
hasattr
(
module
,
'bobo_application'
):
object
=
module
.
bobo_application
elif
hasattr
(
module
,
'web_objects'
):
object
=
module
.
web_objects
else
:
object
=
module
if
hasattr
(
module
,
'bobo_application'
):
object
=
module
.
bobo_application
elif
hasattr
(
module
,
'web_objects'
):
object
=
module
.
web_objects
else
:
object
=
module
error_hook
=
getattr
(
module
,
'zpublisher_exception_hook'
,
None
)
validated_hook
=
getattr
(
module
,
'zpublisher_validated_hook'
,
None
)
error_hook
=
getattr
(
module
,
'zpublisher_exception_hook'
,
None
)
validated_hook
=
getattr
(
module
,
'zpublisher_validated_hook'
,
None
)
transactions_manager
=
getattr
(
module
,
'zpublisher_transactions_manager'
,
None
)
transactions_manager
=
getattr
(
module
,
'zpublisher_transactions_manager'
,
None
)
if
not
transactions_manager
:
# Create a default transactions manager for use
# by software that uses ZPublisher and ZODB but
# not the rest of Zope.
transactions_manager
=
DefaultTransactionsManager
()
info
=
(
bobo_before
,
bobo_after
,
object
,
realm
,
debug_mode
,
error_hook
,
validated_hook
,
transactions_manager
)
info
=
(
bobo_before
,
bobo_after
,
object
,
realm
,
debug_mode
,
error_hook
,
validated_hook
,
transactions_manager
)
modules
[
module_name
]
=
modules
[
module_name
+
'.cgi'
]
=
info
modules
[
module_name
]
=
modules
[
module_name
+
'.cgi'
]
=
info
return
info
except
:
t
,
v
,
tb
=
sys
.
exc_info
()
v
=
str
(
v
)
t
,
v
,
tb
=
sys
.
exc_info
()
v
=
str
(
v
)
raise
ImportError
,
(
t
,
v
),
tb
finally
:
tb
=
None
tb
=
None
release
()
class
DefaultTransactionsManager
:
def
begin
(
self
):
transaction
.
begin
()
def
commit
(
self
):
transaction
.
commit
()
def
abort
(
self
):
transaction
.
abort
()
def
recordMetaData
(
self
,
object
,
request
):
# Is this code needed?
request_get
=
request
.
get
T
=
transaction
.
get
()
T
=
transaction
.
get
()
T
.
note
(
request_get
(
'PATH_INFO'
))
auth_user
=
request_get
(
'AUTHENTICATED_USER'
,
None
)
auth_user
=
request_get
(
'AUTHENTICATED_USER'
,
None
)
if
auth_user
is
not
None
:
T
.
setUser
(
auth_user
,
request_get
(
'AUTHENTICATION_PATH'
))
...
...
@@ -384,6 +411,6 @@ class DefaultTransactionsManager:
def
publish_module
(
module_name
,
stdin
=
sys
.
stdin
,
stdout
=
sys
.
stdout
,
stderr
=
sys
.
stderr
,
environ
=
os
.
environ
,
debug
=
0
,
request
=
None
,
response
=
None
):
""" publish a Python module
, with or without profiling enabled
"""
""" publish a Python module """
return
publish_module_standard
(
module_name
,
stdin
,
stdout
,
stderr
,
environ
,
debug
,
request
,
response
)
src/ZPublisher/Request.py
View file @
efe61189
...
...
@@ -10,6 +10,11 @@
# FOR A PARTICULAR PURPOSE
#
##############################################################################
import
HTTPRequest
Request
=
HTTPRequest
.
HTTPRequest
del
HTTPRequest
from
zope.deferredimport
import
deprecated
# BBB: Zope 5.0
deprecated
(
'Please import from ZPublisher.HTTPRequest'
,
Request
=
'ZPublisher.HTTPRequest:HTTPRequest'
,
)
src/ZPublisher/Response.py
View file @
efe61189
...
...
@@ -10,6 +10,11 @@
# FOR A PARTICULAR PURPOSE
#
##############################################################################
import
HTTPResponse
Response
=
HTTPResponse
.
HTTPResponse
del
HTTPResponse
from
zope.deferredimport
import
deprecated
# BBB: Zope 5.0
deprecated
(
'Please import from ZPublisher.HTTPResponse'
,
Response
=
'ZPublisher.HTTPResponse:HTTPResponse'
,
)
src/ZPublisher/__init__.py
View file @
efe61189
...
...
@@ -11,18 +11,6 @@
#
##############################################################################
# This allows ZPublisher to work with embedded interpreters
# that for some reason have no sys.argv (required by cgi.py).
import
sys
if
not
hasattr
(
sys
,
'argv'
):
sys
.
argv
=
[]
from
zExceptions
import
NotFound
,
BadRequest
,
InternalError
,
Forbidden
# NOQA
from
zExceptions
import
NotFound
,
BadRequest
,
InternalError
,
Forbidden
from
Publish
import
publish_module
,
Retry
def
test
(
*
args
,
**
kw
):
global
test
import
Test
test
=
Test
.
publish
return
apply
(
test
,
args
,
kw
)
from
ZPublisher.Publish
import
publish_module
,
Retry
# NOQA
src/ZPublisher/interfaces.py
View file @
efe61189
...
...
@@ -4,6 +4,7 @@ from zope.interface import Interface, Attribute
# Publication events
# These are events notified in 'ZPublisher.Publish.publish'.
class
IPubEvent
(
Interface
):
'''Base class for publication events.
...
...
@@ -12,9 +13,11 @@ class IPubEvent(Interface):
'''
request
=
Attribute
(
'The request being affected'
)
class
IPubStart
(
IPubEvent
):
'''Event notified at the beginning of 'ZPublisher.Publish.publish'.'''
class
IPubEnd
(
IPubEvent
):
'''Event notified after request processing.
...
...
@@ -22,16 +25,19 @@ class IPubEnd(IPubEvent):
itself is considered a new event.
'''
class
IPubSuccess
(
IPubEnd
):
'''A successful request processing.'''
class
IPubFailure
(
IPubEnd
):
'''A failed request processing.
Note: If a subscriber to 'IPubSuccess' raises an exception,
then 'IPubFailure' may be notified in addtion to 'IPubSuccess'.
'''
exc_info
=
Attribute
(
'''The exception info as returned by 'sys.exc_info()'.'''
)
exc_info
=
Attribute
(
'''The exception info as returned by 'sys.exc_info()'.'''
)
retry
=
Attribute
(
'Whether the request will be retried'
)
...
...
@@ -44,29 +50,28 @@ class IPubBeforeCommit(IPubEvent):
request processing is finished).
"""
class
IPubBeforeAbort
(
IPubEvent
):
"""notified immediately before the transaction abort (i.e. after the main
request processing is finished, and there was an error).
"""
exc_info
=
Attribute
(
'''The exception info as returned by 'sys.exc_info()'.'''
)
exc_info
=
Attribute
(
'''The exception info as returned by 'sys.exc_info()'.'''
)
retry
=
Attribute
(
'Whether the request will be retried'
)
class
IPubBeforeStreaming
(
Interface
):
"""Event fired just before a streaming response is initiated, i.e. when
something calls response.write() for the first time. Note that this is
carries a reference to the *response*, not the request.
"""
response
=
Attribute
(
u"The current HTTP response"
)
# Exceptions
class
UseTraversalDefault
(
Exception
):
"""Indicate default traversal in ``__bobo_traverse__``
This exception can be raised by '__bobo_traverse__' implementations to
indicate that it has no special casing for the given name and that standard
traversal logic should be applied.
"""
src/ZPublisher/mapply.py
View file @
efe61189
...
...
@@ -14,22 +14,26 @@
"""
import
zope.publisher.publish
def
default_call_object
(
object
,
args
,
context
):
result
=
object
(
*
args
)
# Type s<cr> to step into published object.
result
=
object
(
*
args
)
# Type s<cr> to step into published object.
return
result
def
default_missing_name
(
name
,
context
):
raise
TypeError
,
'argument %s was ommitted'
%
name
raise
TypeError
(
'argument %s was ommitted'
%
name
)
def
default_handle_class
(
klass
,
context
):
if
hasattr
(
klass
,
'__init__'
):
f
=
klass
.
__init__
.
im_func
c
=
f
.
func_code
names
=
c
.
co_varnames
[
1
:
c
.
co_argcount
]
if
hasattr
(
klass
,
'__init__'
):
f
=
klass
.
__init__
.
im_func
c
=
f
.
func_code
names
=
c
.
co_varnames
[
1
:
c
.
co_argcount
]
return
klass
,
names
,
f
.
func_defaults
else
:
return
klass
,
(),
()
def
mapply
(
object
,
positional
=
(),
keyword
=
{},
debug
=
None
,
maybe
=
None
,
missing_name
=
default_missing_name
,
...
...
@@ -37,7 +41,7 @@ def mapply(object, positional=(), keyword={},
context
=
None
,
bind
=
0
,
):
if
hasattr
(
object
,
'__bases__'
):
if
hasattr
(
object
,
'__bases__'
):
f
,
names
,
defaults
=
handle_class
(
object
,
context
)
else
:
try
:
...
...
@@ -50,29 +54,34 @@ def mapply(object, positional=(), keyword={},
defaults
=
f
.
func_defaults
names
=
code
.
co_varnames
[
count
:
code
.
co_argcount
]
nargs
=
len
(
names
)
nargs
=
len
(
names
)
if
positional
:
positional
=
list
(
positional
)
if
bind
and
nargs
and
names
[
0
]
==
'self'
:
positional
=
list
(
positional
)
if
bind
and
nargs
and
names
[
0
]
==
'self'
:
positional
.
insert
(
0
,
missing_name
(
'self'
,
context
))
if
len
(
positional
)
>
nargs
:
raise
TypeError
,
'too many arguments'
args
=
positional
if
len
(
positional
)
>
nargs
:
raise
TypeError
(
'too many arguments'
)
args
=
positional
else
:
if
bind
and
nargs
and
names
[
0
]
==
'self'
:
args
=
[
missing_name
(
'self'
,
context
)]
if
bind
and
nargs
and
names
[
0
]
==
'self'
:
args
=
[
missing_name
(
'self'
,
context
)]
else
:
args
=
[]
args
=
[]
get
=
keyword
.
get
nrequired
=
len
(
names
)
-
(
len
(
defaults
or
()))
get
=
keyword
.
get
nrequired
=
len
(
names
)
-
(
len
(
defaults
or
()))
for
index
in
range
(
len
(
args
),
len
(
names
)):
name
=
names
[
index
]
v
=
get
(
name
,
args
)
name
=
names
[
index
]
v
=
get
(
name
,
args
)
if
v
is
args
:
if
index
<
nrequired
:
v
=
missing_name
(
name
,
context
)
else
:
v
=
defaults
[
index
-
nrequired
]
if
index
<
nrequired
:
v
=
missing_name
(
name
,
context
)
else
:
v
=
defaults
[
index
-
nrequired
]
args
.
append
(
v
)
args
=
tuple
(
args
)
if
debug
is
not
None
:
return
debug
(
object
,
args
,
context
)
else
:
return
object
(
*
args
)
args
=
tuple
(
args
)
if
debug
is
not
None
:
return
debug
(
object
,
args
,
context
)
else
:
return
object
(
*
args
)
src/ZPublisher/maybe_lock.py
View file @
efe61189
...
...
@@ -11,9 +11,4 @@
#
##############################################################################
# Waaaa, I wish I didn't have to work this hard.
try
:
from
thread
import
allocate_lock
except
:
class
allocate_lock
:
def
acquire
(
*
args
):
pass
def
release
(
*
args
):
pass
from
thread
import
allocate_lock
# NOQA
src/ZPublisher/pubevents.py
View file @
efe61189
'''Publication events.
They are notified in 'ZPublisher.Publish.publish' and
They are notified in 'ZPublisher.Publish.publish' and
inform about publications and their fate.
Subscriptions can be used for all kinds of request supervision,
...
...
@@ -9,9 +9,12 @@ for detailed time related analysis, inline request monitoring.
'''
from
zope.interface
import
implements
from
interfaces
import
IPubStart
,
IPubSuccess
,
IPubFailure
,
\
IPubAfterTraversal
,
IPubBeforeCommit
,
IPubBeforeAbort
,
\
IPubBeforeStreaming
from
ZPublisher.interfaces
import
(
IPubStart
,
IPubSuccess
,
IPubFailure
,
IPubAfterTraversal
,
IPubBeforeCommit
,
IPubBeforeAbort
,
IPubBeforeStreaming
,
)
class
_Base
(
object
):
"""PubEvent base class."""
...
...
@@ -19,14 +22,17 @@ class _Base(object):
def
__init__
(
self
,
request
):
self
.
request
=
request
class
PubStart
(
_Base
):
'''notified at the beginning of 'ZPublisher.Publish.publish'.'''
implements
(
IPubStart
)
class
PubSuccess
(
_Base
):
'''notified at successful request end.'''
implements
(
IPubSuccess
)
class
PubFailure
(
object
):
'''notified at failed request end.'''
implements
(
IPubFailure
)
...
...
@@ -44,17 +50,19 @@ class PubBeforeCommit(_Base):
"""notified immediately before the commit."""
implements
(
IPubBeforeCommit
)
class
PubBeforeAbort
(
_Base
):
"""notified immediately before an abort."""
implements
(
IPubBeforeAbort
)
def
__init__
(
self
,
request
,
exc_info
,
retry
):
self
.
request
,
self
.
exc_info
,
self
.
retry
=
request
,
exc_info
,
retry
class
PubBeforeStreaming
(
object
):
"""Notified immediately before streaming via response.write() commences
"""
implements
(
IPubBeforeStreaming
)
def
__init__
(
self
,
response
):
self
.
response
=
response
src/ZPublisher/tests/__init__.py
View file @
efe61189
# This helps debugging.
src/ZPublisher/tests/generate_conflicts.py
deleted
100644 → 0
View file @
2e9d01ea
## This script requires:
## - python >= 2.4
## - zope.testbrowser
##
## The just run:
## $python generate_conflicts.py
import
base64
import
string
import
threading
import
urllib2
from
zope.testbrowser.browser
import
Browser
# create our browser
class
AuthBrowser
(
Browser
):
def
addBasicAuth
(
self
,
username
,
password
):
self
.
addHeader
(
'Authorization'
,
'Basic '
+
base64
.
encodestring
(
username
+
':'
+
password
).
strip
()
)
def
open
(
self
,
uri
,
include_server
=
True
):
if
include_server
:
uri
=
server
+
uri
return
Browser
.
open
(
self
,
uri
)
browser
=
AuthBrowser
()
# constants
server
=
'http://localhost:8080'
# the following user must be able to view the management screens
# and create file objects
username
=
'username'
password
=
'password'
browser
.
addBasicAuth
(
username
,
password
)
threads
=
10
filename
=
'conflict.txt'
filesize
=
10000
hits
=
5
# delete the file if it's already there
browser
.
open
(
'/manage_main'
)
if
filename
in
[
c
.
optionValue
for
c
in
browser
.
getControl
(
name
=
'ids:list'
).
controls
]:
browser
.
open
(
'/manage_delObjects?ids:list='
+
filename
)
# create it
browser
.
open
(
'/manage_addFile?id='
+
filename
)
# edit it, hopefully causing conflicts
data
=
'X'
*
filesize
class
EditThread
(
threading
.
Thread
):
def
__init__
(
self
,
i
):
self
.
conflicts
=
0
self
.
browser
=
AuthBrowser
()
self
.
browser
.
handleErrors
=
False
self
.
browser
.
addBasicAuth
(
username
,
password
)
threading
.
Thread
.
__init__
(
self
,
name
=
str
(
i
))
def
run
(
self
):
for
i
in
range
(
1
,
hits
+
1
):
self
.
browser
.
open
(
'/conflict.txt/manage_main'
)
self
.
browser
.
getControl
(
name
=
'title'
).
value
=
'Test Title'
self
.
browser
.
getControl
(
name
=
'filedata:text'
).
value
=
data
try
:
self
.
browser
.
getControl
(
name
=
'manage_edit:method'
).
click
()
except
urllib2
.
HTTPError
,
e
:
# print e.read()
self
.
conflicts
+=
1
print
"Thread %s - CONFLICT"
%
self
.
getName
()
else
:
print
"Thread %s - EDIT"
%
self
.
getName
()
thread_objects
=
[]
for
i
in
range
(
1
,
threads
+
1
):
t
=
EditThread
(
i
)
thread_objects
.
append
(
t
)
t
.
start
()
for
t
in
thread_objects
:
t
.
join
()
total
=
0
print
for
t
in
thread_objects
:
print
"Thread %s - %i conflicts seen"
%
(
t
.
getName
(),
t
.
conflicts
)
total
+=
t
.
conflicts
print
print
"%i conflicts seen by browsers"
%
total
src/ZPublisher/tests/testBaseRequest.py
View file @
efe61189
...
...
@@ -33,26 +33,24 @@ class BaseRequest_factory:
if
base
is
None
:
base
=
''
elif
not
base
.
endswith
(
'/'
):
base
=
base
+
'/'
base
=
base
+
'/'
self
.
base
=
str
(
base
)
def
notFoundError
(
self
,
name
):
from
zExceptions
import
NotFound
raise
NotFound
(
name
)
# Real responses raise NotFound, to avoid information disclosure
#def forbiddenError(self, name):
# from zExceptions import Forbidden
# raise Forbidden(name)
forbiddenError
=
notFoundError
response
=
DummyResponse
()
environment
=
{
'URL'
:
''
,
'PARENTS'
:
[
root
],
'steps'
:
[],
'_hacked_path'
:
0
,
'_test_counter'
:
0
,
'response'
:
response
}
environment
=
{
'URL'
:
''
,
'PARENTS'
:
[
root
],
'steps'
:
[],
'_hacked_path'
:
0
,
'_test_counter'
:
0
,
'response'
:
response
}
return
self
.
_getTargetClass
()(
environment
)
def
_makeBasicObjectClass
(
self
):
...
...
@@ -112,7 +110,7 @@ class BaseRequest_factory:
else
:
raise
RuntimeError
(
'Infinite loop detected.'
)
REQUEST
[
'TraversalRequestNameStack'
]
+=
self
.
_path
REQUEST
.
_hacked_path
=
1
REQUEST
.
_hacked_path
=
1
return
DummyObjectWithBPTH
()
...
...
@@ -151,16 +149,18 @@ class BaseRequest_factory:
def
_makeObjectWithBDBBT
(
self
):
class
DummyObjectWithBDBBT
(
self
.
_makeBasicObjectClass
()):
"""Dummy class with __browser_default__."""
def
__browser_default__
(
self
,
REQUEST
):
if
REQUEST
[
'_test_counter'
]
<
100
:
REQUEST
[
'_test_counter'
]
+=
1
else
:
raise
RuntimeError
(
'Infinite loop detected.'
)
return
self
,
self
.
_default_path
def
__bobo_traverse__
(
self
,
REQUEST
,
name
):
if
name
==
self
.
_default_path
[
0
]:
return
getattr
(
self
,
name
)
raise
AttributeError
,
name
raise
AttributeError
(
name
)
return
DummyObjectWithBDBBT
()
def
_makeObjectWithEmptyDocstring
(
self
):
...
...
@@ -292,14 +292,15 @@ class TestBaseRequest(unittest.TestCase, BaseRequest_factory):
# that we get a NotFound
from
ZPublisher
import
NotFound
root
,
folder
=
self
.
_makeRootAndFolder
()
def
_faux___bobo_traverse__
(
REQUEST
,
name
):
raise
AttributeError
,
name
raise
AttributeError
(
name
)
obj
=
self
.
_makeBasicObject
()
obj
.
__bobo_traverse__
=
_faux___bobo_traverse__
folder
.
_setObject
(
'objWithBBT'
,
obj
)
r
=
self
.
_makeOne
(
root
)
self
.
assertRaises
(
NotFound
,
r
.
traverse
,
'folder/objWithBBT/bbt_foo'
)
'folder/objWithBBT/bbt_foo'
)
def
test_traverse_UseTraversalDefault
(
self
):
root
,
folder
=
self
.
_makeRootAndFolder
()
...
...
@@ -309,7 +310,8 @@ class TestBaseRequest(unittest.TestCase, BaseRequest_factory):
self
.
assertEqual
(
r
.
traverse
(
'folder/objWithBBT/normal'
).
tag
,
'Normal'
)
# test default usage
r
=
self
.
_makeOne
(
root
)
self
.
assertEqual
(
r
.
traverse
(
'folder/objWithBBT/default'
).
tag
,
'Default'
)
self
.
assertEqual
(
r
.
traverse
(
'folder/objWithBBT/default'
).
tag
,
'Default'
)
def
test_traverse_withBDBBT
(
self
):
# Test for an object which has a __browser_default__
...
...
@@ -371,7 +373,7 @@ class TestBaseRequest(unittest.TestCase, BaseRequest_factory):
def
test_traverse_class_without_docstring
(
self
):
from
ZPublisher
import
NotFound
root
,
folder
=
self
.
_makeRootAndFolder
()
folder
.
_setObject
(
'objWithoutDocstring'
,
folder
.
_setObject
(
'objWithoutDocstring'
,
self
.
_makeObjectWithEmptyDocstring
())
r
=
self
.
_makeOne
(
root
)
self
.
assertRaises
(
NotFound
,
r
.
traverse
,
'folder/objWithoutDocstring'
)
...
...
@@ -379,20 +381,20 @@ class TestBaseRequest(unittest.TestCase, BaseRequest_factory):
def
test_traverse_attribute_of_class_without_docstring
(
self
):
from
ZPublisher
import
NotFound
root
,
folder
=
self
.
_makeRootAndFolder
()
folder
.
_setObject
(
'objWithoutDocstring'
,
folder
.
_setObject
(
'objWithoutDocstring'
,
self
.
_makeObjectWithEmptyDocstring
())
r
=
self
.
_makeOne
(
root
)
self
.
assertRaises
(
NotFound
,
r
.
traverse
,
'folder/objWithoutDocstring/view'
)
'folder/objWithoutDocstring/view'
)
def
test_traverse_attribute_and_class_without_docstring
(
self
):
from
ZPublisher
import
NotFound
root
,
folder
=
self
.
_makeRootAndFolder
()
r
=
self
.
_makeOne
(
root
)
folder
.
_setObject
(
'objWithoutDocstring'
,
folder
.
_setObject
(
'objWithoutDocstring'
,
self
.
_makeObjectWithEmptyDocstring
())
self
.
assertRaises
(
NotFound
,
r
.
traverse
,
'folder/objWithoutDocstring/noview'
)
'folder/objWithoutDocstring/noview'
)
def
test_traverse_simple_string
(
self
):
from
ZPublisher
import
NotFound
...
...
@@ -444,6 +446,7 @@ class TestBaseRequest(unittest.TestCase, BaseRequest_factory):
r
=
self
.
_makeOne
(
root
)
r
.
other
[
'foo'
]
=
'Foo'
BEFORE
=
subscribers
[:]
def
_broken
(
event
):
raise
ValueError
(
"I'm broken"
)
subscribers
.
append
(
_broken
)
...
...
@@ -481,7 +484,7 @@ class TestBaseRequest(unittest.TestCase, BaseRequest_factory):
self
.
assertRaises
(
NotFound
,
r
.
traverse
,
'not_found'
)
class
TestRequest
Zope3
ViewsBase
(
unittest
.
TestCase
,
BaseRequest_factory
):
class
TestRequestViewsBase
(
unittest
.
TestCase
,
BaseRequest_factory
):
_dummy_interface
=
None
...
...
@@ -492,7 +495,7 @@ class TestRequestZope3ViewsBase(unittest.TestCase, BaseRequest_factory):
def
_makeOne
(
self
,
root
):
from
zope.interface
import
directlyProvides
from
zope.publisher.browser
import
IDefaultBrowserLayer
request
=
super
(
TestRequest
Zope3
ViewsBase
,
self
).
_makeOne
(
root
)
request
=
super
(
TestRequestViewsBase
,
self
).
_makeOne
(
root
)
# The request needs to implement the proper interface
directlyProvides
(
request
,
IDefaultBrowserLayer
)
return
request
...
...
@@ -532,6 +535,7 @@ class TestRequestZope3ViewsBase(unittest.TestCase, BaseRequest_factory):
class
DummyObjectZ3
(
self
.
_makeBasicObjectClass
()):
implements
(
self
.
_dummyInterface
())
def
__init__
(
self
,
name
):
self
.
name
=
name
...
...
@@ -542,12 +546,14 @@ class TestRequestZope3ViewsBase(unittest.TestCase, BaseRequest_factory):
class
DummyObjectZ3WithAttr
(
self
.
_makeBasicObjectClass
()):
implements
(
self
.
_dummyInterface
())
def
__init__
(
self
,
name
):
self
.
name
=
name
def
meth
(
self
):
"""doc"""
return
'meth on %s'
%
self
.
name
def
methonly
(
self
):
"""doc"""
return
'methonly on %s'
%
self
.
name
...
...
@@ -577,11 +583,11 @@ class TestRequestZope3ViewsBase(unittest.TestCase, BaseRequest_factory):
def
__init__
(
self
,
content
,
request
):
self
.
content
=
content
self
.
request
=
request
def
__call__
(
self
):
return
'view on %s'
%
(
self
.
content
.
name
)
class
DummyPage
(
BrowserPage
):
# BrowserPage is an IBrowserPublisher with a browserDefault that
# returns self, () so that __call__ is invoked by the publisher.
...
...
@@ -594,7 +600,8 @@ class TestRequestZope3ViewsBase(unittest.TestCase, BaseRequest_factory):
# intentionally return something that's not self
return
DummyPage
(
self
.
context
,
request
),
()
# __call__ remains unimplemented, baseclass raises NotImplementedError
# __call__ remains unimplemented,
# baseclass raises NotImplementedError
class
DummyPage3
(
BrowserPage
):
...
...
@@ -605,7 +612,8 @@ class TestRequestZope3ViewsBase(unittest.TestCase, BaseRequest_factory):
def
foo
(
self
):
return
'Test page'
# __call__ remains unimplemented, baseclass raises NotImplementedError
# __call__ remains unimplemented,
# baseclass raises NotImplementedError
class
DummyPage4
(
Implicit
,
DummyPage
):
# a normal page that can implicitly acquire attributes
...
...
@@ -641,10 +649,10 @@ class TestRequestZope3ViewsBase(unittest.TestCase, BaseRequest_factory):
IDefaultViewName
,
''
)
class
TestBaseRequest
Zope3Views
(
TestRequestZope3
ViewsBase
):
class
TestBaseRequest
Views
(
TestRequest
ViewsBase
):
def
test_traverse_view
(
self
):
#simple view
#
simple view
root
,
folder
=
self
.
_makeRootAndFolder
()
folder
.
_setObject
(
'obj'
,
self
.
_makeDummyObject
(
'obj'
))
r
=
self
.
_makeOne
(
root
)
...
...
@@ -658,9 +666,10 @@ class TestBaseRequestZope3Views(TestRequestZope3ViewsBase):
self
.
assertEqual
(
ob
(),
'view on obj'
)
def
test_traverse_view_attr_local
(
self
):
#method on object used first
#
method on object used first
root
,
folder
=
self
.
_makeRootAndFolder
()
folder
.
_setObject
(
'withattr'
,
self
.
_makeDummyObjectWithAttr
(
'withattr'
))
folder
.
_setObject
(
'withattr'
,
self
.
_makeDummyObjectWithAttr
(
'withattr'
))
r
=
self
.
_makeOne
(
root
)
ob
=
r
.
traverse
(
'folder/withattr/meth'
)
self
.
assertEqual
(
ob
(),
'meth on withattr'
)
...
...
@@ -672,13 +681,14 @@ class TestBaseRequestZope3Views(TestRequestZope3ViewsBase):
self
.
assertEqual
(
ob
(),
'view on withattr'
)
def
test_traverse_view_attr_above
(
self
):
#view takes precedence over acquired attribute
#
view takes precedence over acquired attribute
root
,
folder
=
self
.
_makeRootAndFolder
()
folder2
=
root
.
_setObject
(
'folder2'
,
self
.
_makeDummyObjectWithAttr
(
'folder2'
))
folder2
=
root
.
_setObject
(
'folder2'
,
self
.
_makeDummyObjectWithAttr
(
'folder2'
))
folder2
.
_setObject
(
'obj2'
,
self
.
_makeDummyObject
(
'obj2'
))
r
=
self
.
_makeOne
(
root
)
ob
=
r
.
traverse
(
'folder2/obj2/meth'
)
self
.
assertEqual
(
ob
(),
'view on obj2'
)
# used to be buggy (acquired)
self
.
assertEqual
(
ob
(),
'view on obj2'
)
# used to be buggy (acquired)
ob
=
r
.
traverse
(
'folder2/obj2/@@meth'
)
self
.
assertEqual
(
ob
(),
'view on obj2'
)
# using default view
...
...
@@ -687,10 +697,12 @@ class TestBaseRequestZope3Views(TestRequestZope3ViewsBase):
self
.
assertEqual
(
ob
(),
'view on obj2'
)
def
test_traverse_view_attr_local2
(
self
):
#method with other method above
#
method with other method above
root
,
folder
=
self
.
_makeRootAndFolder
()
folder2
=
root
.
_setObject
(
'folder2'
,
self
.
_makeDummyObjectWithAttr
(
'folder2'
))
folder2
.
_setObject
(
'withattr2'
,
self
.
_makeDummyObjectWithAttr
(
'withattr2'
))
folder2
=
root
.
_setObject
(
'folder2'
,
self
.
_makeDummyObjectWithAttr
(
'folder2'
))
folder2
.
_setObject
(
'withattr2'
,
self
.
_makeDummyObjectWithAttr
(
'withattr2'
))
r
=
self
.
_makeOne
(
root
)
ob
=
r
.
traverse
(
'folder2/withattr2/meth'
)
self
.
assertEqual
(
ob
(),
'meth on withattr2'
)
...
...
@@ -702,10 +714,11 @@ class TestBaseRequestZope3Views(TestRequestZope3ViewsBase):
self
.
assertEqual
(
ob
(),
'view on withattr2'
)
def
test_traverse_view_attr_acquired
(
self
):
#normal acquired attribute without view
#
normal acquired attribute without view
from
ZPublisher
import
NotFound
root
,
folder
=
self
.
_makeRootAndFolder
()
folder2
=
root
.
_setObject
(
'folder2'
,
self
.
_makeDummyObjectWithAttr
(
'folder2'
))
folder2
=
root
.
_setObject
(
'folder2'
,
self
.
_makeDummyObjectWithAttr
(
'folder2'
))
folder2
.
_setObject
(
'obj2'
,
self
.
_makeDummyObject
(
'obj2'
))
r
=
self
.
_makeOne
(
root
)
ob
=
r
.
traverse
(
'folder2/obj2/methonly'
)
...
...
@@ -714,17 +727,17 @@ class TestBaseRequestZope3Views(TestRequestZope3ViewsBase):
# using default view
self
.
_setDefaultViewName
(
'methonly'
)
self
.
assertRaises
(
NotFound
,
r
.
traverse
,
'folder2/obj2'
)
def
test_quoting_goggles
(
self
):
#View goggles ('@@') should not be quoted
#
View goggles ('@@') should not be quoted
root
,
folder
=
self
.
_makeRootAndFolder
()
folder
.
_setObject
(
'obj'
,
self
.
_makeDummyObject
(
'obj'
))
r
=
self
.
_makeOne
(
root
)
r
.
traverse
(
'folder/obj/@@meth'
)
self
.
assertEqual
(
r
[
'URL'
],
'/folder/obj/@@meth'
)
def
test_quoting_plusplus
(
self
):
#View markers ('++ should not be quoted
#
View markers ('++ should not be quoted
root
,
folder
=
self
.
_makeRootAndFolder
()
folder
.
_setObject
(
'obj'
,
self
.
_makeDummyObject
(
'obj'
))
r
=
self
.
_makeOne
(
root
)
...
...
@@ -751,7 +764,7 @@ class TestBaseRequestZope3Views(TestRequestZope3ViewsBase):
r
=
self
.
_makeOne
(
root
)
ob
=
r
.
traverse
(
'folder/obj/page3'
)
self
.
assertEqual
(
ob
(),
'Test page'
)
def
test_wrapping_implicit_acquirers
(
self
):
# when the default publish traverser finds via adaptation
# an object providing IAcquirer, it should wrap it in the
...
...
@@ -764,10 +777,3 @@ class TestBaseRequestZope3Views(TestRequestZope3ViewsBase):
self
.
assertEqual
(
ob
(),
'Test page'
)
# make sure we can acquire
self
.
assertEqual
(
ob
.
ob2
,
ob2
)
def
test_suite
():
return
unittest
.
TestSuite
((
unittest
.
makeSuite
(
TestBaseRequest
),
unittest
.
makeSuite
(
TestBaseRequestZope3Views
),
))
src/ZPublisher/tests/testBeforeTraverse.py
View file @
efe61189
import
sys
import
logging
import
doctest
from
Acquisition
import
Implicit
from
ZPublisher
import
BeforeTraverse
from
ZPublisher.BaseRequest
import
BaseRequest
from
ZPublisher.HTTPResponse
import
HTTPResponse
def
makeBaseRequest
(
root
):
response
=
HTTPResponse
()
environment
=
{
'URL'
:
''
,
'PARENTS'
:
[
root
],
'steps'
:
[],
'_hacked_path'
:
0
,
'_test_counter'
:
0
,
'response'
:
response
}
environment
=
{
'URL'
:
''
,
'PARENTS'
:
[
root
],
'steps'
:
[],
'_hacked_path'
:
0
,
'_test_counter'
:
0
,
'response'
:
response
,
}
return
BaseRequest
(
environment
)
...
...
@@ -23,19 +24,24 @@ class DummyObjectBasic(Implicit):
pass
class
BrokenHook
:
class
BrokenHook
(
object
)
:
def
__call__
(
self
,
*
args
):
print
self
.
__class__
.
__name__
,
'called'
raise
TypeError
,
self
.
__class__
.
__name__
print
(
'%s called'
%
self
.
__class__
.
__name__
)
raise
TypeError
(
self
.
__class__
.
__name__
)
def
testBeforeTraverse
(
self
):
"""
"""
Zope supports a 'before traverse' hook that is used for several
features, including 'Site Access Rules'. It is implemented using a
special API for registering hooks, and the hooks themselves are
called during traversal by ZPublisher.
>>> import sys
>>> import logging
>>> from ZPublisher import BeforeTraverse
>>> root = DummyObjectBasic()
>>> request = makeBaseRequest(root)
...
...
@@ -58,7 +64,7 @@ def testBeforeTraverse(self):
{(99, 'broken_hook'): <ZPublisher.tests.testBeforeTraverse.BrokenHook ...>}
Setup logging so we can see the actual exception being logged:
>>> logger = logging.getLogger('ZPublisher')
>>> level = logger.level
>>> handlers = logger.handlers[:]
...
...
@@ -67,7 +73,7 @@ def testBeforeTraverse(self):
>>> logger.setLevel(logging.ERROR)
Now do the actual traversal:
>>> _ = request.traverse('container/obj')
BrokenHook called
'__before_publishing_traverse__' call ... failed.
...
...
@@ -93,9 +99,9 @@ def testBeforeTraverse(self):
during traversal you can register a 'NameCaller' as the hook
instead, and it will delegate to the callable by looking it up as
an attribute of the container:
>>> container.broken_callable = BrokenHook()
>>> BeforeTraverse.registerBeforeTraverse(container,
>>> BeforeTraverse.registerBeforeTraverse(container,
... BeforeTraverse.NameCaller('broken_callable'),
... 'broken_callable')
...
...
@@ -103,7 +109,7 @@ def testBeforeTraverse(self):
{(99, 'broken_callable'): <ZPublisher.BeforeTraverse.NameCaller ...>}
Now do the actual traversal:
>>> _ = request.traverse('container/obj')
BrokenHook called
BeforeTraverse: Error while invoking hook: "broken_callable"
...
...
@@ -131,10 +137,7 @@ def testBeforeTraverse(self):
>>> logger.handlers = handlers[:]
"""
pass
import
doctest
def
test_suite
():
return
doctest
.
DocTestSuite
(
optionflags
=
doctest
.
ELLIPSIS
)
src/ZPublisher/tests/testHTTPRangeSupport.py
View file @
efe61189
...
...
@@ -16,17 +16,19 @@ from ZPublisher.HTTPRangeSupport import parseRange, expandRanges
import
unittest
class
TestRangeHeaderParse
(
unittest
.
TestCase
):
# Utility methods
def
expectNone
(
self
,
header
):
result
=
parseRange
(
header
)
self
.
assertTrue
(
result
is
None
,
'Expected None, got %
s'
%
`result`
)
self
.
assertTrue
(
result
is
None
,
'Expected None, got %
r'
%
result
)
def
expectSets
(
self
,
header
,
sets
):
result
=
parseRange
(
header
)
self
.
assertTrue
(
result
==
sets
,
'Expected %s, got %s'
%
(
`sets`
,
`result`
))
self
.
assertTrue
(
result
==
sets
,
'Expected %r, got %r'
%
(
sets
,
result
))
# Syntactically incorrect headers
def
testGarbage
(
self
):
...
...
@@ -67,7 +69,8 @@ class TestRangeHeaderParse(unittest.TestCase):
self
.
expectSets
(
'bytes=100-100'
,
[(
100
,
101
)])
def
testMultiple
(
self
):
self
.
expectSets
(
'bytes=-100,,1-2,20-'
,
self
.
expectSets
(
'bytes=-100,,1-2,20-'
,
[(
-
100
,
None
),
(
1
,
3
),
(
20
,
None
)])
def
testFirstByte
(
self
):
...
...
@@ -81,8 +84,9 @@ class TestExpandRanges(unittest.TestCase):
def
expectSets
(
self
,
sets
,
size
,
expect
):
result
=
expandRanges
(
sets
,
size
)
self
.
assertTrue
(
result
==
expect
,
'Expected %s, got %s'
%
(
`expect`
,
`result`
))
self
.
assertTrue
(
result
==
expect
,
'Expected %r, got %r'
%
(
expect
,
result
))
def
testExpandOpenEnd
(
self
):
self
.
expectSets
([(
1
,
2
),
(
5
,
None
)],
50
,
[(
1
,
2
),
(
5
,
50
)])
...
...
@@ -91,23 +95,28 @@ class TestExpandRanges(unittest.TestCase):
self
.
expectSets
([(
1
,
2
),
(
-
5
,
None
)],
50
,
[(
1
,
2
),
(
45
,
50
)])
def
testNoOverlapInOrder
(
self
):
self
.
expectSets
([(
1
,
5
),
(
1000
,
2000
),
(
3000
,
None
)],
5000
,
self
.
expectSets
(
[(
1
,
5
),
(
1000
,
2000
),
(
3000
,
None
)],
5000
,
[(
1
,
5
),
(
1000
,
2000
),
(
3000
,
5000
)])
def
testNoOverlapOutOfOrder
(
self
):
self
.
expectSets
([(
1000
,
2000
),
(
3000
,
None
),
(
1
,
5
)],
5000
,
self
.
expectSets
(
[(
1000
,
2000
),
(
3000
,
None
),
(
1
,
5
)],
5000
,
[(
1000
,
2000
),
(
3000
,
5000
),
(
1
,
5
)])
def
testOverlapInOrder
(
self
):
self
.
expectSets
([(
1
,
10
),
(
8
,
20
),
(
25
,
None
)],
5000
,
self
.
expectSets
(
[(
1
,
10
),
(
8
,
20
),
(
25
,
None
)],
5000
,
[(
1
,
10
),
(
8
,
20
),
(
25
,
5000
)])
def
testOverlapOutOfOrder
(
self
):
self
.
expectSets
([(
25
,
50
),
(
8
,
None
),
(
1
,
10
)],
5000
,
self
.
expectSets
(
[(
25
,
50
),
(
8
,
None
),
(
1
,
10
)],
5000
,
[(
25
,
50
),
(
8
,
5000
),
(
1
,
10
)])
def
testAdjacentInOrder
(
self
):
self
.
expectSets
([(
1
,
10
),
(
10
,
20
),
(
25
,
50
)],
5000
,
self
.
expectSets
(
[(
1
,
10
),
(
10
,
20
),
(
25
,
50
)],
5000
,
[(
1
,
10
),
(
10
,
20
),
(
25
,
50
)])
def
testAdjacentOutOfOrder
(
self
):
...
...
@@ -119,20 +128,3 @@ class TestExpandRanges(unittest.TestCase):
def
testRemoveUnsatisfiable
(
self
):
self
.
expectSets
([(
sys
.
maxint
,
None
),
(
10
,
20
)],
50
,
[(
10
,
20
)])
def
test_suite
():
suite
=
unittest
.
TestSuite
()
suite
.
addTest
(
unittest
.
makeSuite
(
TestRangeHeaderParse
,
'test'
))
suite
.
addTest
(
unittest
.
makeSuite
(
TestExpandRanges
,
'test'
))
return
suite
def
main
():
unittest
.
TextTestRunner
().
run
(
test_suite
())
def
debug
():
test_suite
().
debug
()
def
pdebug
():
import
pdb
pdb
.
run
(
'debug()'
)
src/ZPublisher/tests/testHTTPRequest.py
View file @
efe61189
import
unittest
from
ZPublisher.tests.testBaseRequest
import
TestRequest
Zope3
ViewsBase
from
ZPublisher.tests.testBaseRequest
import
TestRequestViewsBase
from
zope.testing.cleanup
import
cleanUp
...
...
@@ -54,8 +54,8 @@ class HTTPRequestTests(unittest.TestCase, HTTPRequestFactoryMixin):
def
_processInputs
(
self
,
inputs
):
from
urllib
import
quote_plus
# Have the inputs processed, and return a HTTPRequest object
holding the
# result.
# Have the inputs processed, and return a HTTPRequest object
#
holding the
result.
# inputs is expected to be a list of (key, value) tuples, no CGI
# encoding is required.
...
...
@@ -86,55 +86,66 @@ class HTTPRequestTests(unittest.TestCase, HTTPRequestFactoryMixin):
retval
=
0
if
isinstance
(
val
,
TaintedString
):
self
.
assertFalse
(
not
'<'
in
val
,
"%r is not dangerous, no taint required."
%
val
)
self
.
assertFalse
(
'<'
not
in
val
,
"%r is not dangerous, no taint required."
%
val
)
retval
=
1
elif
isinstance
(
val
,
record
):
for
attr
,
value
in
val
.
__dict__
.
items
():
rval
=
self
.
_valueIsOrHoldsTainted
(
attr
)
if
rval
:
retval
=
1
if
rval
:
retval
=
1
rval
=
self
.
_valueIsOrHoldsTainted
(
value
)
if
rval
:
retval
=
1
if
rval
:
retval
=
1
elif
type
(
val
)
in
(
list
,
tuple
):
for
entry
in
val
:
rval
=
self
.
_valueIsOrHoldsTainted
(
entry
)
if
rval
:
retval
=
1
if
rval
:
retval
=
1
elif
type
(
val
)
in
(
str
,
unicode
):
self
.
assertFalse
(
'<'
in
val
,
"'%s' is dangerous and should have been tainted."
%
val
)
self
.
assertFalse
(
'<'
in
val
,
"'%s' is dangerous and should have been tainted."
%
val
)
return
retval
def
_noFormValuesInOther
(
self
,
req
):
for
key
in
req
.
taintedform
.
keys
():
self
.
assertFalse
(
req
.
other
.
has_key
(
key
),
self
.
assertFalse
(
key
in
req
.
other
,
'REQUEST.other should not hold tainted values at first!'
)
for
key
in
req
.
form
.
keys
():
self
.
assertFalse
(
req
.
other
.
has_key
(
key
),
self
.
assertFalse
(
key
in
req
.
other
,
'REQUEST.other should not hold form values at first!'
)
def
_onlyTaintedformHoldsTaintedStrings
(
self
,
req
):
for
key
,
val
in
req
.
taintedform
.
items
():
self
.
assert_
(
self
.
_valueIsOrHoldsTainted
(
key
)
or
self
.
_valueIsOrHoldsTainted
(
val
),
'Tainted form holds item %s that is not tainted'
%
key
)
self
.
assert_
(
self
.
_valueIsOrHoldsTainted
(
key
)
or
self
.
_valueIsOrHoldsTainted
(
val
),
'Tainted form holds item %s that is not tainted'
%
key
)
for
key
,
val
in
req
.
form
.
items
():
if
req
.
taintedform
.
has_key
(
key
)
:
if
key
in
req
.
taintedform
:
continue
self
.
assertFalse
(
self
.
_valueIsOrHoldsTainted
(
key
)
or
self
.
_valueIsOrHoldsTainted
(
val
),
'Normal form holds item %s that is tainted'
%
key
)
self
.
assertFalse
(
self
.
_valueIsOrHoldsTainted
(
key
)
or
self
.
_valueIsOrHoldsTainted
(
val
),
'Normal form holds item %s that is tainted'
%
key
)
def
_taintedKeysAlsoInForm
(
self
,
req
):
for
key
in
req
.
taintedform
.
keys
():
self
.
assert_
(
req
.
form
.
has_key
(
key
),
self
.
assert_
(
key
in
req
.
form
,
"Found tainted %s not in form"
%
key
)
self
.
assertEquals
(
req
.
form
[
key
],
req
.
taintedform
[
key
],
self
.
assertEqual
(
req
.
form
[
key
],
req
.
taintedform
[
key
],
"Key %s not correctly reproduced in tainted; expected %r, "
"got %r"
%
(
key
,
req
.
form
[
key
],
req
.
taintedform
[
key
]))
...
...
@@ -156,7 +167,7 @@ class HTTPRequestTests(unittest.TestCase, HTTPRequestFactoryMixin):
req
=
self
.
_makeOne
(
environ
=
env
)
req
.
processInputs
()
self
.
_noFormValuesInOther
(
req
)
self
.
assertEqual
s
(
req
.
form
,
{})
self
.
assertEqual
(
req
.
form
,
{})
def
test_processInputs_wo_marshalling
(
self
):
inputs
=
(
...
...
@@ -168,12 +179,13 @@ class HTTPRequestTests(unittest.TestCase, HTTPRequestFactoryMixin):
formkeys
=
list
(
req
.
form
.
keys
())
formkeys
.
sort
()
self
.
assertEquals
(
formkeys
,
[
'foo'
,
'key'
,
'multi'
,
'number'
,
'spacey key'
,
'spam'
])
self
.
assertEquals
(
req
[
'number'
],
'1'
)
self
.
assertEquals
(
req
[
'multi'
],
[
'1'
,
'2'
])
self
.
assertEquals
(
req
[
'spacey key'
],
'val'
)
self
.
assertEquals
(
req
[
'key'
],
'spacey val'
)
self
.
assertEqual
(
formkeys
,
[
'foo'
,
'key'
,
'multi'
,
'number'
,
'spacey key'
,
'spam'
])
self
.
assertEqual
(
req
[
'number'
],
'1'
)
self
.
assertEqual
(
req
[
'multi'
],
[
'1'
,
'2'
])
self
.
assertEqual
(
req
[
'spacey key'
],
'val'
)
self
.
assertEqual
(
req
[
'key'
],
'spacey val'
)
self
.
_noTaintedValues
(
req
)
self
.
_onlyTaintedformHoldsTaintedStrings
(
req
)
...
...
@@ -191,18 +203,20 @@ class HTTPRequestTests(unittest.TestCase, HTTPRequestFactoryMixin):
formkeys
=
list
(
req
.
form
.
keys
())
formkeys
.
sort
()
self
.
assertEquals
(
formkeys
,
[
'2tokens'
,
'accountedfor'
,
'aday'
,
'bign'
,
'fract'
,
'morewords'
,
'multiline'
,
'num'
,
'words'
])
self
.
assertEquals
(
req
[
'2tokens'
],
[
'one'
,
'two'
])
self
.
assertEquals
(
req
[
'accountedfor'
],
'yes'
)
self
.
assertEquals
(
req
[
'aday'
],
DateTime
(
'2002/07/23'
))
self
.
assertEquals
(
req
[
'bign'
],
45L
)
self
.
assertEquals
(
req
[
'fract'
],
4.2
)
self
.
assertEquals
(
req
[
'morewords'
],
'one
\
n
two
\
n
'
)
self
.
assertEquals
(
req
[
'multiline'
],
[
'one'
,
'two'
])
self
.
assertEquals
(
req
[
'num'
],
42
)
self
.
assertEquals
(
req
[
'words'
],
'Some words'
)
self
.
assertEqual
(
formkeys
,
[
'2tokens'
,
'accountedfor'
,
'aday'
,
'bign'
,
'fract'
,
'morewords'
,
'multiline'
,
'num'
,
'words'
])
self
.
assertEqual
(
req
[
'2tokens'
],
[
'one'
,
'two'
])
self
.
assertEqual
(
req
[
'accountedfor'
],
'yes'
)
self
.
assertEqual
(
req
[
'aday'
],
DateTime
(
'2002/07/23'
))
self
.
assertEqual
(
req
[
'bign'
],
45
)
self
.
assertEqual
(
req
[
'fract'
],
4.2
)
self
.
assertEqual
(
req
[
'morewords'
],
'one
\
n
two
\
n
'
)
self
.
assertEqual
(
req
[
'multiline'
],
[
'one'
,
'two'
])
self
.
assertEqual
(
req
[
'num'
],
42
)
self
.
assertEqual
(
req
[
'words'
],
'Some words'
)
self
.
_noTaintedValues
(
req
)
self
.
_onlyTaintedformHoldsTaintedStrings
(
req
)
...
...
@@ -217,16 +231,17 @@ class HTTPRequestTests(unittest.TestCase, HTTPRequestFactoryMixin):
formkeys
=
list
(
req
.
form
.
keys
())
formkeys
.
sort
()
self
.
assertEquals
(
formkeys
,
[
'nouconverter'
,
'ulines'
,
'ustring'
,
'utext'
,
'utokens'
])
self
.
assertEqual
(
formkeys
,
[
'nouconverter'
,
'ulines'
,
'ustring'
,
'utext'
,
'utokens'
])
self
.
assertEqual
s
(
req
[
'ustring'
],
u'test
\
u00AE
'
)
self
.
assertEqual
s
(
req
[
'utext'
],
u'test
\
u00AE
\
n
test
\
u00AE
\
n
'
)
self
.
assertEqual
s
(
req
[
'utokens'
],
[
u'test
\
u00AE
'
,
u'test
\
u00AE
'
])
self
.
assertEqual
s
(
req
[
'ulines'
],
[
u'test
\
u00AE
'
,
u'test
\
u00AE
'
])
self
.
assertEqual
(
req
[
'ustring'
],
u'test
\
u00AE
'
)
self
.
assertEqual
(
req
[
'utext'
],
u'test
\
u00AE
\
n
test
\
u00AE
\
n
'
)
self
.
assertEqual
(
req
[
'utokens'
],
[
u'test
\
u00AE
'
,
u'test
\
u00AE
'
])
self
.
assertEqual
(
req
[
'ulines'
],
[
u'test
\
u00AE
'
,
u'test
\
u00AE
'
])
# expect a utf-8 encoded version
self
.
assertEqual
s
(
req
[
'nouconverter'
],
'test
\
xc2
\
xae
'
)
self
.
assertEqual
(
req
[
'nouconverter'
],
'test
\
xc2
\
xae
'
)
self
.
_noTaintedValues
(
req
)
self
.
_onlyTaintedformHoldsTaintedStrings
(
req
)
...
...
@@ -244,20 +259,21 @@ class HTTPRequestTests(unittest.TestCase, HTTPRequestFactoryMixin):
formkeys
=
list
(
req
.
form
.
keys
())
formkeys
.
sort
()
self
.
assertEquals
(
formkeys
,
[
'alist'
,
'atuple'
,
'oneitem'
,
'oneitemtuple'
,
'onerec'
,
'setrec'
])
self
.
assertEquals
(
req
[
'oneitem'
],
[
'one'
])
self
.
assertEquals
(
req
[
'oneitemtuple'
],
(
'one'
,))
self
.
assertEquals
(
req
[
'alist'
],
[
'one'
,
'two'
])
self
.
assertEquals
(
req
[
'atuple'
],
(
'one'
,
'two'
))
self
.
assertEquals
(
req
[
'onerec'
].
foo
,
'foo'
)
self
.
assertEquals
(
req
[
'onerec'
].
bar
,
'bar'
)
self
.
assertEquals
(
len
(
req
[
'setrec'
]),
2
)
self
.
assertEquals
(
req
[
'setrec'
][
0
].
foo
,
'foo'
)
self
.
assertEquals
(
req
[
'setrec'
][
0
].
bar
,
'bar'
)
self
.
assertEquals
(
req
[
'setrec'
][
1
].
foo
,
'spam'
)
self
.
assertEquals
(
req
[
'setrec'
][
1
].
bar
,
'eggs'
)
self
.
assertEqual
(
formkeys
,
[
'alist'
,
'atuple'
,
'oneitem'
,
'oneitemtuple'
,
'onerec'
,
'setrec'
])
self
.
assertEqual
(
req
[
'oneitem'
],
[
'one'
])
self
.
assertEqual
(
req
[
'oneitemtuple'
],
(
'one'
,))
self
.
assertEqual
(
req
[
'alist'
],
[
'one'
,
'two'
])
self
.
assertEqual
(
req
[
'atuple'
],
(
'one'
,
'two'
))
self
.
assertEqual
(
req
[
'onerec'
].
foo
,
'foo'
)
self
.
assertEqual
(
req
[
'onerec'
].
bar
,
'bar'
)
self
.
assertEqual
(
len
(
req
[
'setrec'
]),
2
)
self
.
assertEqual
(
req
[
'setrec'
][
0
].
foo
,
'foo'
)
self
.
assertEqual
(
req
[
'setrec'
][
0
].
bar
,
'bar'
)
self
.
assertEqual
(
req
[
'setrec'
][
1
].
foo
,
'spam'
)
self
.
assertEqual
(
req
[
'setrec'
][
1
].
bar
,
'eggs'
)
self
.
_noTaintedValues
(
req
)
self
.
_onlyTaintedformHoldsTaintedStrings
(
req
)
...
...
@@ -273,11 +289,11 @@ class HTTPRequestTests(unittest.TestCase, HTTPRequestFactoryMixin):
formkeys
=
list
(
req
.
form
.
keys
())
formkeys
.
sort
()
self
.
assertEqual
s
(
formkeys
,
[
'ftuple'
,
'ilist'
,
'tlist'
])
self
.
assertEqual
(
formkeys
,
[
'ftuple'
,
'ilist'
,
'tlist'
])
self
.
assertEqual
s
(
req
[
'ilist'
],
[
1
,
2
,
3
])
self
.
assertEqual
s
(
req
[
'ftuple'
],
(
1.0
,
1.1
,
1.2
))
self
.
assertEqual
s
(
req
[
'tlist'
],
[[
'one'
,
'two'
],
[
'3'
,
'4'
]])
self
.
assertEqual
(
req
[
'ilist'
],
[
1
,
2
,
3
])
self
.
assertEqual
(
req
[
'ftuple'
],
(
1.0
,
1.1
,
1.2
))
self
.
assertEqual
(
req
[
'tlist'
],
[[
'one'
,
'two'
],
[
'3'
,
'4'
]])
self
.
_noTaintedValues
(
req
)
self
.
_onlyTaintedformHoldsTaintedStrings
(
req
)
...
...
@@ -303,20 +319,20 @@ class HTTPRequestTests(unittest.TestCase, HTTPRequestFactoryMixin):
formkeys
=
list
(
req
.
form
.
keys
())
formkeys
.
sort
()
self
.
assertEqual
s
(
formkeys
,
[
'onerec'
,
'setrec'
])
self
.
assertEqual
(
formkeys
,
[
'onerec'
,
'setrec'
])
self
.
assertEqual
s
(
req
[
'onerec'
].
name
,
'foo'
)
self
.
assertEqual
s
(
req
[
'onerec'
].
tokens
,
[
'one'
,
'two'
])
self
.
assertEqual
(
req
[
'onerec'
].
name
,
'foo'
)
self
.
assertEqual
(
req
[
'onerec'
].
tokens
,
[
'one'
,
'two'
])
# Implicit sequences and records don't mix.
self
.
assertEqual
s
(
req
[
'onerec'
].
ints
,
2
)
self
.
assertEqual
(
req
[
'onerec'
].
ints
,
2
)
self
.
assertEqual
s
(
len
(
req
[
'setrec'
]),
2
)
self
.
assertEqual
s
(
req
[
'setrec'
][
0
].
name
,
'first'
)
self
.
assertEqual
s
(
req
[
'setrec'
][
1
].
name
,
'second'
)
self
.
assertEqual
(
len
(
req
[
'setrec'
]),
2
)
self
.
assertEqual
(
req
[
'setrec'
][
0
].
name
,
'first'
)
self
.
assertEqual
(
req
[
'setrec'
][
1
].
name
,
'second'
)
for
i
in
range
(
2
):
self
.
assertEqual
s
(
req
[
'setrec'
][
i
].
ilist
,
[
1
,
2
])
self
.
assertEqual
s
(
req
[
'setrec'
][
i
].
ituple
,
(
1
,
2
))
self
.
assertEqual
(
req
[
'setrec'
][
i
].
ilist
,
[
1
,
2
])
self
.
assertEqual
(
req
[
'setrec'
][
i
].
ituple
,
(
1
,
2
))
self
.
_noTaintedValues
(
req
)
self
.
_onlyTaintedformHoldsTaintedStrings
(
req
)
...
...
@@ -345,26 +361,26 @@ class HTTPRequestTests(unittest.TestCase, HTTPRequestFactoryMixin):
(
'setrec.foo:records:default'
,
'foo'
),
(
'setrec.foo:records'
,
'baz'
),
(
'setrec.foo:records'
,
'ham'
),
)
)
req
=
self
.
_processInputs
(
inputs
)
formkeys
=
list
(
req
.
form
.
keys
())
formkeys
.
sort
()
self
.
assertEqual
s
(
formkeys
,
[
'alist'
,
'bar'
,
'explicitlist'
,
'foo'
,
'setrec'
])
self
.
assertEqual
(
formkeys
,
[
'alist'
,
'bar'
,
'explicitlist'
,
'foo'
,
'setrec'
])
self
.
assertEqual
s
(
req
[
'alist'
],
[
1
,
2
,
3
,
4
,
5
])
self
.
assertEqual
s
(
req
[
'explicitlist'
],
[
1
,
2
,
3
,
4
,
5
])
self
.
assertEqual
(
req
[
'alist'
],
[
1
,
2
,
3
,
4
,
5
])
self
.
assertEqual
(
req
[
'explicitlist'
],
[
1
,
2
,
3
,
4
,
5
])
self
.
assertEqual
s
(
req
[
'foo'
],
5
)
self
.
assertEqual
s
(
req
[
'bar'
].
spam
,
'eggs'
)
self
.
assertEqual
s
(
req
[
'bar'
].
foo
,
'baz'
)
self
.
assertEqual
(
req
[
'foo'
],
5
)
self
.
assertEqual
(
req
[
'bar'
].
spam
,
'eggs'
)
self
.
assertEqual
(
req
[
'bar'
].
foo
,
'baz'
)
self
.
assertEqual
s
(
len
(
req
[
'setrec'
]),
2
)
self
.
assertEqual
s
(
req
[
'setrec'
][
0
].
spam
,
'eggs'
)
self
.
assertEqual
s
(
req
[
'setrec'
][
0
].
foo
,
'baz'
)
self
.
assertEqual
s
(
req
[
'setrec'
][
1
].
spam
,
'eggs'
)
self
.
assertEqual
s
(
req
[
'setrec'
][
1
].
foo
,
'ham'
)
self
.
assertEqual
(
len
(
req
[
'setrec'
]),
2
)
self
.
assertEqual
(
req
[
'setrec'
][
0
].
spam
,
'eggs'
)
self
.
assertEqual
(
req
[
'setrec'
][
0
].
foo
,
'baz'
)
self
.
assertEqual
(
req
[
'setrec'
][
1
].
spam
,
'eggs'
)
self
.
assertEqual
(
req
[
'setrec'
][
1
].
foo
,
'ham'
)
self
.
_noTaintedValues
(
req
)
self
.
_onlyTaintedformHoldsTaintedStrings
(
req
)
...
...
@@ -383,8 +399,10 @@ class HTTPRequestTests(unittest.TestCase, HTTPRequestFactoryMixin):
taintedformkeys
=
list
(
req
.
taintedform
.
keys
())
taintedformkeys
.
sort
()
self
.
assertEquals
(
taintedformkeys
,
[
'<tainted key>'
,
'tainted'
,
'tallmulti'
,
'tdefermulti'
,
'tinitmulti'
])
self
.
assertEqual
(
taintedformkeys
,
[
'<tainted key>'
,
'tainted'
,
'tallmulti'
,
'tdefermulti'
,
'tinitmulti'
])
self
.
_taintedKeysAlsoInForm
(
req
)
self
.
_onlyTaintedformHoldsTaintedStrings
(
req
)
...
...
@@ -393,7 +411,8 @@ class HTTPRequestTests(unittest.TestCase, HTTPRequestFactoryMixin):
inputs
=
(
(
'<tnum>:int'
,
'42'
),
(
'<tfract>:float'
,
'4.2'
),
(
'<tbign>:long'
,
'45'
),
(
'twords:string'
,
'Some <words>'
),
(
't2tokens:tokens'
,
'one <two>'
),
(
'twords:string'
,
'Some <words>'
),
(
't2tokens:tokens'
,
'one <two>'
),
(
'<taday>:date'
,
'2002/07/23'
),
(
'taccountedfor:required'
,
'<yes>'
),
(
'tmultiline:lines'
,
'<one
\
n
two>'
),
...
...
@@ -402,31 +421,37 @@ class HTTPRequestTests(unittest.TestCase, HTTPRequestFactoryMixin):
taintedformkeys
=
list
(
req
.
taintedform
.
keys
())
taintedformkeys
.
sort
()
self
.
assertEquals
(
taintedformkeys
,
[
'<taday>'
,
'<tbign>'
,
'<tfract>'
,
'<tnum>'
,
't2tokens'
,
'taccountedfor'
,
'tmorewords'
,
'tmultiline'
,
'twords'
])
self
.
assertEqual
(
taintedformkeys
,
[
'<taday>'
,
'<tbign>'
,
'<tfract>'
,
'<tnum>'
,
't2tokens'
,
'taccountedfor'
,
'tmorewords'
,
'tmultiline'
,
'twords'
])
self
.
_taintedKeysAlsoInForm
(
req
)
self
.
_onlyTaintedformHoldsTaintedStrings
(
req
)
def
test_processInputs_w_unicode_w_taints
(
self
):
inputs
=
((
'tustring:ustring:utf8'
,
'<test
\
xc2
\
xae
>'
),
(
'tutext:utext:utf8'
,
'<test
\
xc2
\
xae
>
\
n
<test
\
xc2
\
xae
\
n
>'
),
inputs
=
(
(
'tustring:ustring:utf8'
,
'<test
\
xc2
\
xae
>'
),
(
'tutext:utext:utf8'
,
'<test
\
xc2
\
xae
>
\
n
<test
\
xc2
\
xae
\
n
>'
),
(
'tinitutokens:utokens:utf8'
,
'<test
\
xc2
\
xae
> test
\
xc2
\
xae
'
),
(
'tinitulines:ulines:utf8'
,
'<test
\
xc2
\
xae
>
\
n
test
\
xc2
\
xae
'
),
(
'tinitutokens:utokens:utf8'
,
'<test
\
xc2
\
xae
> test
\
xc2
\
xae
'
),
(
'tinitulines:ulines:utf8'
,
'<test
\
xc2
\
xae
>
\
n
test
\
xc2
\
xae
'
),
(
'tdeferutokens:utokens:utf8'
,
'test
\
xc2
\
xae
<test
\
xc2
\
xae
>'
),
(
'tdeferulines:ulines:utf8'
,
'test
\
xc2
\
xae
\
n
<test
\
xc2
\
xae
>'
),
(
'tdeferutokens:utokens:utf8'
,
'test
\
xc2
\
xae
<test
\
xc2
\
xae
>'
),
(
'tdeferulines:ulines:utf8'
,
'test
\
xc2
\
xae
\
n
<test
\
xc2
\
xae
>'
),
(
'tnouconverter:string:utf8'
,
'<test
\
xc2
\
xae
>'
))
(
'tnouconverter:string:utf8'
,
'<test
\
xc2
\
xae
>'
),
)
req
=
self
.
_processInputs
(
inputs
)
taintedformkeys
=
list
(
req
.
taintedform
.
keys
())
taintedformkeys
.
sort
()
self
.
assertEquals
(
taintedformkeys
,
[
'tdeferulines'
,
'tdeferutokens'
,
'tinitulines'
,
'tinitutokens'
,
'tnouconverter'
,
'tustring'
,
'tutext'
])
self
.
assertEqual
(
taintedformkeys
,
[
'tdeferulines'
,
'tdeferutokens'
,
'tinitulines'
,
'tinitutokens'
,
'tnouconverter'
,
'tustring'
,
'tutext'
])
self
.
_taintedKeysAlsoInForm
(
req
)
self
.
_onlyTaintedformHoldsTaintedStrings
(
req
)
...
...
@@ -470,10 +495,12 @@ class HTTPRequestTests(unittest.TestCase, HTTPRequestFactoryMixin):
taintedformkeys
=
list
(
req
.
taintedform
.
keys
())
taintedformkeys
.
sort
()
self
.
assertEquals
(
taintedformkeys
,
[
'<tkeyoneitem>'
,
'tdeferalist'
,
'tdeferatuple'
,
'tdeferdefersetrec'
,
'tdeferinitsetrec'
,
'tdeferonerec'
,
'tinitalist'
,
'tinitatuple'
,
'tinitdefersetrec'
,
'tinitinitsetrec'
,
'tinitonerec'
,
'toneitem'
,
'toneitemtuple'
])
self
.
assertEqual
(
taintedformkeys
,
[
'<tkeyoneitem>'
,
'tdeferalist'
,
'tdeferatuple'
,
'tdeferdefersetrec'
,
'tdeferinitsetrec'
,
'tdeferonerec'
,
'tinitalist'
,
'tinitatuple'
,
'tinitdefersetrec'
,
'tinitinitsetrec'
,
'tinitonerec'
,
'toneitem'
,
'toneitemtuple'
])
self
.
_taintedKeysAlsoInForm
(
req
)
self
.
_onlyTaintedformHoldsTaintedStrings
(
req
)
...
...
@@ -515,13 +542,15 @@ class HTTPRequestTests(unittest.TestCase, HTTPRequestFactoryMixin):
(
'tdefersecondsetrec.ilist:list:records'
,
'<2>'
),
(
'tdefersecondsetrec.ituple:tuple:int:records'
,
'1'
),
(
'tdefersecondsetrec.ituple:tuple:int:records'
,
'2'
),
)
)
req
=
self
.
_processInputs
(
inputs
)
taintedformkeys
=
list
(
req
.
taintedform
.
keys
())
taintedformkeys
.
sort
()
self
.
assertEquals
(
taintedformkeys
,
[
'tdeferfirstsetrec'
,
'tdeferonerec'
,
'tdefersecondsetrec'
,
'tinitonerec'
,
'tinitsetrec'
])
self
.
assertEqual
(
taintedformkeys
,
[
'tdeferfirstsetrec'
,
'tdeferonerec'
,
'tdefersecondsetrec'
,
'tinitonerec'
,
'tinitsetrec'
])
self
.
_taintedKeysAlsoInForm
(
req
)
self
.
_onlyTaintedformHoldsTaintedStrings
(
req
)
...
...
@@ -572,8 +601,10 @@ class HTTPRequestTests(unittest.TestCase, HTTPRequestFactoryMixin):
taintedformkeys
=
list
(
req
.
taintedform
.
keys
())
taintedformkeys
.
sort
()
self
.
assertEquals
(
taintedformkeys
,
[
'tdeferbar'
,
'tdeferlist'
,
'tdefersetrec'
,
'tfoo'
,
'tinitbar'
,
'tinitlist'
,
'tinitsetrec'
])
self
.
assertEqual
(
taintedformkeys
,
[
'tdeferbar'
,
'tdeferlist'
,
'tdefersetrec'
,
'tfoo'
,
'tinitbar'
,
'tinitlist'
,
'tinitsetrec'
])
self
.
_taintedKeysAlsoInForm
(
req
)
self
.
_onlyTaintedformHoldsTaintedStrings
(
req
)
...
...
@@ -592,10 +623,12 @@ class HTTPRequestTests(unittest.TestCase, HTTPRequestFactoryMixin):
try
:
convert
(
'<html garbage>'
)
except
Exception
as
e
:
self
.
assertFalse
(
'<'
in
e
.
args
,
self
.
assertFalse
(
'<'
in
e
.
args
,
'%s converter does not quote unsafe value!'
%
type
)
except
SyntaxError
as
e
:
self
.
assertFalse
(
'<'
in
e
,
self
.
assertFalse
(
'<'
in
e
,
'%s converter does not quote unsafe value!'
%
type
)
def
test_processInputs_w_dotted_name_as_tuple
(
self
):
...
...
@@ -606,9 +639,9 @@ class HTTPRequestTests(unittest.TestCase, HTTPRequestFactoryMixin):
formkeys
=
list
(
req
.
form
.
keys
())
formkeys
.
sort
()
self
.
assertEqual
s
(
formkeys
,
[
'name.'
])
self
.
assertEqual
(
formkeys
,
[
'name.'
])
self
.
assertEqual
s
(
req
[
'name.'
],
(
'name with dot as tuple'
,))
self
.
assertEqual
(
req
[
'name.'
],
(
'name with dot as tuple'
,))
self
.
_noTaintedValues
(
req
)
self
.
_onlyTaintedformHoldsTaintedStrings
(
req
)
...
...
@@ -618,20 +651,20 @@ class HTTPRequestTests(unittest.TestCase, HTTPRequestFactoryMixin):
env
[
'HTTP_COOKIE'
]
=
'foo=bar; baz=gee'
req
=
self
.
_makeOne
(
environ
=
env
)
self
.
assertEqual
s
(
req
.
cookies
[
'foo'
],
'bar'
)
self
.
assertEqual
s
(
req
.
cookies
[
'baz'
],
'gee'
)
self
.
assertEqual
(
req
.
cookies
[
'foo'
],
'bar'
)
self
.
assertEqual
(
req
.
cookies
[
'baz'
],
'gee'
)
env
[
'HTTP_COOKIE'
]
=
'foo=bar; baz="gee, like, e=mc^2"'
req
=
self
.
_makeOne
(
environ
=
env
)
self
.
assertEqual
s
(
req
.
cookies
[
'foo'
],
'bar'
)
self
.
assertEqual
s
(
req
.
cookies
[
'baz'
],
'gee, like, e=mc^2'
)
self
.
assertEqual
(
req
.
cookies
[
'foo'
],
'bar'
)
self
.
assertEqual
(
req
.
cookies
[
'baz'
],
'gee, like, e=mc^2'
)
# Collector #1498: empty cookies
env
[
'HTTP_COOKIE'
]
=
'foo=bar; hmm; baz=gee'
req
=
self
.
_makeOne
(
environ
=
env
)
self
.
assertEqual
s
(
req
.
cookies
[
'foo'
],
'bar'
)
self
.
assertEqual
s
(
req
.
cookies
[
'hmm'
],
''
)
self
.
assertEqual
s
(
req
.
cookies
[
'baz'
],
'gee'
)
self
.
assertEqual
(
req
.
cookies
[
'foo'
],
'bar'
)
self
.
assertEqual
(
req
.
cookies
[
'hmm'
],
''
)
self
.
assertEqual
(
req
.
cookies
[
'baz'
],
'gee'
)
# Unquoted multi-space cookies
env
[
'HTTP_COOKIE'
]
=
'single=cookie data; '
\
...
...
@@ -639,13 +672,13 @@ class HTTPRequestTests(unittest.TestCase, HTTPRequestFactoryMixin):
'multi=cookie data with unquoted spaces; '
\
'multi2=cookie data with unquoted spaces'
req
=
self
.
_makeOne
(
environ
=
env
)
self
.
assertEqual
s
(
req
.
cookies
[
'single'
],
'cookie data'
)
self
.
assertEqual
s
(
req
.
cookies
[
'quoted'
],
'cookie data with unquoted spaces'
)
self
.
assertEqual
s
(
req
.
cookies
[
'multi'
],
'cookie data with unquoted spaces'
)
self
.
assertEqual
s
(
req
.
cookies
[
'multi2'
],
'cookie data with unquoted spaces'
)
self
.
assertEqual
(
req
.
cookies
[
'single'
],
'cookie data'
)
self
.
assertEqual
(
req
.
cookies
[
'quoted'
],
'cookie data with unquoted spaces'
)
self
.
assertEqual
(
req
.
cookies
[
'multi'
],
'cookie data with unquoted spaces'
)
self
.
assertEqual
(
req
.
cookies
[
'multi2'
],
'cookie data with unquoted spaces'
)
def
test_postProcessInputs
(
self
):
from
ZPublisher.HTTPRequest
import
default_encoding
...
...
@@ -707,43 +740,43 @@ class HTTPRequestTests(unittest.TestCase, HTTPRequestFactoryMixin):
req
=
self
.
_makeOne
(
stdin
=
s
,
environ
=
TEST_ENVIRON
.
copy
())
req
.
processInputs
()
f
=
req
.
form
.
get
(
'file'
)
self
.
assertEqual
(
list
(
f
),[
'test
\
n
'
])
f
=
req
.
form
.
get
(
'file'
)
self
.
assertEqual
(
list
(
f
),
[
'test
\
n
'
])
f
.
seek
(
0
)
self
.
assertEqual
(
f
.
next
(),
'test
\
n
'
)
self
.
assertEqual
(
f
.
next
(),
'test
\
n
'
)
f
.
seek
(
0
)
self
.
assertEqual
(
f
.
xreadlines
(),
f
)
self
.
assertEqual
(
f
.
xreadlines
(),
f
)
def
test__authUserPW_simple
(
self
):
def
test__authUserPW_simple
(
self
):
import
base64
user_id
=
'user'
password
=
'password'
encoded
=
base64
.
encodestring
(
'%s:%s'
%
(
user_id
,
password
)
)
encoded
=
base64
.
encodestring
(
'%s:%s'
%
(
user_id
,
password
)
)
auth_header
=
'basic %s'
%
encoded
environ
=
{
'HTTP_AUTHORIZATION'
:
auth_header
}
request
=
self
.
_makeOne
(
environ
=
environ
)
environ
=
{
'HTTP_AUTHORIZATION'
:
auth_header
}
request
=
self
.
_makeOne
(
environ
=
environ
)
user_id_x
,
password_x
=
request
.
_authUserPW
()
self
.
assertEqual
(
user_id_x
,
user_id
)
self
.
assertEqual
(
password_x
,
password
)
self
.
assertEqual
(
user_id_x
,
user_id
)
self
.
assertEqual
(
password_x
,
password
)
def
test__authUserPW_with_embedded_colon
(
self
):
def
test__authUserPW_with_embedded_colon
(
self
):
# http://www.zope.org/Collectors/Zope/2039
import
base64
user_id
=
'user'
password
=
'embedded:colon'
encoded
=
base64
.
encodestring
(
'%s:%s'
%
(
user_id
,
password
)
)
encoded
=
base64
.
encodestring
(
'%s:%s'
%
(
user_id
,
password
)
)
auth_header
=
'basic %s'
%
encoded
environ
=
{
'HTTP_AUTHORIZATION'
:
auth_header
}
request
=
self
.
_makeOne
(
environ
=
environ
)
environ
=
{
'HTTP_AUTHORIZATION'
:
auth_header
}
request
=
self
.
_makeOne
(
environ
=
environ
)
user_id_x
,
password_x
=
request
.
_authUserPW
()
self
.
assertEqual
(
user_id_x
,
user_id
)
self
.
assertEqual
(
password_x
,
password
)
self
.
assertEqual
(
user_id_x
,
user_id
)
self
.
assertEqual
(
password_x
,
password
)
def
test_debug_not_in_qs_still_gets_attr
(
self
):
from
zope.publisher.base
import
DebugFlags
...
...
@@ -774,14 +807,6 @@ class HTTPRequestTests(unittest.TestCase, HTTPRequestFactoryMixin):
request
[
'debug'
]
=
'2'
self
.
assertEqual
(
request
.
debug
,
'2'
)
def
test_interfaces
(
self
):
from
zope.publisher.interfaces.browser
import
IBrowserRequest
from
zope.interface.verify
import
verifyClass
klass
=
self
.
_getTargetClass
()
# TODO
# verifyClass(IBrowserRequest, klass)
def
test_locale_property_accessor
(
self
):
from
zope.component
import
provideAdapter
from
zope.publisher.browser
import
BrowserLanguages
...
...
@@ -920,7 +945,7 @@ class HTTPRequestTests(unittest.TestCase, HTTPRequestFactoryMixin):
def
test_getClientAddr_one_trusted_proxy
(
self
):
from
ZPublisher.HTTPRequest
import
trusted_proxies
env
=
{
'REMOTE_ADDR'
:
'127.0.0.1'
,
'HTTP_X_FORWARDED_FOR'
:
'10.1.20.30, 192.168.1.100'
}
'HTTP_X_FORWARDED_FOR'
:
'10.1.20.30, 192.168.1.100'
}
orig
=
trusted_proxies
[:]
try
:
...
...
@@ -1029,6 +1054,7 @@ class HTTPRequestTests(unittest.TestCase, HTTPRequestFactoryMixin):
def
test_clone_preserves_direct_interfaces
(
self
):
from
zope.interface
import
directlyProvides
from
zope.interface
import
Interface
class
IFoo
(
Interface
):
pass
request
=
self
.
_makeOne
()
...
...
@@ -1047,7 +1073,8 @@ class HTTPRequestTests(unittest.TestCase, HTTPRequestFactoryMixin):
request
.
resolve_url
(
request
.
script
+
'/'
)
finally
:
zope
.
event
.
subscribers
.
remove
(
events
.
append
)
self
.
assertFalse
(
len
(
events
),
self
.
assertFalse
(
len
(
events
),
"HTTPRequest.resolve_url should not emit events"
)
def
test_resolve_url_errorhandling
(
self
):
...
...
@@ -1056,37 +1083,36 @@ class HTTPRequestTests(unittest.TestCase, HTTPRequestFactoryMixin):
from
zExceptions
import
NotFound
request
=
self
.
_makeOne
()
request
[
'PARENTS'
]
=
[
object
()]
self
.
assertRaises
(
NotFound
,
request
.
resolve_url
,
request
.
script
+
'/does_not_exist'
)
self
.
assertRaises
(
NotFound
,
request
.
resolve_url
,
request
.
script
+
'/does_not_exist'
)
def
test_parses_json_cookies
(
self
):
# https://bugs.launchpad.net/zope2/+bug/563229
# reports cookies in the wild with embedded double quotes (e.g,
# JSON-encoded data structures.
env
=
{
'SERVER_NAME'
:
'testingharnas'
,
'SERVER_PORT'
:
'80'
,
'HTTP_COOKIE'
:
'json={"intkey":123,"stringkey":"blah"}; '
'anothercookie=boring; baz'
}
env
=
{
'SERVER_NAME'
:
'testingharnas'
,
'SERVER_PORT'
:
'80'
,
'HTTP_COOKIE'
:
'json={"intkey":123,"stringkey":"blah"}; '
'anothercookie=boring; baz'
}
req
=
self
.
_makeOne
(
environ
=
env
)
self
.
assertEqual
s
(
req
.
cookies
[
'json'
],
'{"intkey":123,"stringkey":"blah"}'
)
self
.
assertEqual
s
(
req
.
cookies
[
'anothercookie'
],
'boring'
)
self
.
assertEqual
(
req
.
cookies
[
'json'
],
'{"intkey":123,"stringkey":"blah"}'
)
self
.
assertEqual
(
req
.
cookies
[
'anothercookie'
],
'boring'
)
def
test_getVirtualRoot
(
self
):
# https://bugs.launchpad.net/zope2/+bug/193122
req
=
self
.
_makeOne
()
req
.
_script
=
[]
self
.
assertEqual
s
(
req
.
getVirtualRoot
(),
''
)
self
.
assertEqual
(
req
.
getVirtualRoot
(),
''
)
req
.
_script
=
[
'foo'
,
'bar'
]
self
.
assertEqual
s
(
req
.
getVirtualRoot
(),
'/foo/bar'
)
self
.
assertEqual
(
req
.
getVirtualRoot
(),
'/foo/bar'
)
class
TestHTTPRequestZope3Views
(
TestRequest
Zope3ViewsBase
,
):
class
TestHTTPRequestZope3Views
(
TestRequest
ViewsBase
):
def
_makeOne
(
self
,
root
):
from
zope.interface
import
directlyProvides
...
...
@@ -1118,7 +1144,7 @@ TEST_ENVIRON = {
'REQUEST_METHOD'
:
'POST'
,
'SERVER_NAME'
:
'localhost'
,
'SERVER_PORT'
:
'80'
,
}
}
TEST_FILE_DATA
=
'''
--12345
...
...
@@ -1138,11 +1164,3 @@ Content-Type: application/octet-stream
test %s
'''
%
(
'test'
*
1000
)
def
test_suite
():
suite
=
unittest
.
TestSuite
()
suite
.
addTest
(
unittest
.
makeSuite
(
RecordTests
))
suite
.
addTest
(
unittest
.
makeSuite
(
HTTPRequestTests
))
suite
.
addTest
(
unittest
.
makeSuite
(
TestHTTPRequestZope3Views
))
return
suite
src/ZPublisher/tests/testHTTPResponse.py
View file @
efe61189
...
...
@@ -13,17 +13,15 @@ class HTTPResponseTests(unittest.TestCase):
self
.
_setDefaultEncoding
(
self
.
_old_default_encoding
)
def
_setDefaultEncoding
(
self
,
value
):
from
ZPublisher
import
HTTPResponse
as
module
(
modul
e
.
default_encoding
,
self
.
_old_default_encoding
)
=
(
value
,
modul
e
.
default_encoding
)
from
ZPublisher
import
HTTPResponse
(
HTTPRespons
e
.
default_encoding
,
self
.
_old_default_encoding
)
=
(
value
,
HTTPRespons
e
.
default_encoding
)
def
_getTargetClass
(
self
):
from
ZPublisher.HTTPResponse
import
HTTPResponse
return
HTTPResponse
def
_makeOne
(
self
,
*
args
,
**
kw
):
return
self
.
_getTargetClass
()(
*
args
,
**
kw
)
def
test_ctor_defaults
(
self
):
...
...
@@ -43,8 +41,7 @@ class HTTPResponseTests(unittest.TestCase):
def
test_ctor_w_headers
(
self
):
response
=
self
.
_makeOne
(
headers
=
{
'foo'
:
'bar'
})
self
.
assertEqual
(
response
.
headers
,
{
'foo'
:
'bar'
,
})
self
.
assertEqual
(
response
.
headers
,
{
'foo'
:
'bar'
})
def
test_ctor_w_status_code
(
self
):
response
=
self
.
_makeOne
(
status
=
401
)
...
...
@@ -83,9 +80,9 @@ class HTTPResponseTests(unittest.TestCase):
'application/foo'
)
def
test_ctor_charset_application_header_with_header
(
self
):
response
=
self
.
_makeOne
(
body
=
'foo'
,
headers
=
{
'content-type'
:
'application/foo; charset: something'
})
response
=
self
.
_makeOne
(
body
=
'foo'
,
headers
=
{
'content-type'
:
'application/foo; charset: something'
})
self
.
assertEqual
(
response
.
headers
.
get
(
'content-type'
),
'application/foo; charset: something'
)
...
...
@@ -101,7 +98,7 @@ class HTTPResponseTests(unittest.TestCase):
BODY
=
u'
\
xe4
rger'
response
=
self
.
_makeOne
(
body
=
BODY
,
headers
=
{
'content-type'
:
'application/foo; charset=utf-8'
})
'application/foo; charset=utf-8'
})
self
.
assertEqual
(
response
.
headers
.
get
(
'content-type'
),
'application/foo; charset=utf-8'
)
# Body is re-encoded to match the header
...
...
@@ -109,16 +106,18 @@ class HTTPResponseTests(unittest.TestCase):
def
test_ctor_body_recodes_to_match_content_type_charset
(
self
):
xml
=
(
u'<?xml version="1.0" encoding="iso-8859-15" ?>
\
n
'
'<foo><bar/></foo>'
)
response
=
self
.
_makeOne
(
body
=
xml
,
headers
=
{
'content-type'
:
'text/xml; charset=utf-8'
})
u'<foo><bar/></foo>'
)
response
=
self
.
_makeOne
(
body
=
xml
,
headers
=
{
'content-type'
:
'text/xml; charset=utf-8'
})
self
.
assertEqual
(
response
.
body
,
xml
.
replace
(
'iso-8859-15'
,
'utf-8'
))
def
test_ctor_body_already_matches_charset_unchanged
(
self
):
xml
=
(
u'<?xml version="1.0" encoding="iso-8859-15" ?>
\
n
'
'<foo><bar/></foo>'
)
response
=
self
.
_makeOne
(
body
=
xml
,
headers
=
{
'content-type'
:
'text/xml; charset=iso-8859-15'
})
u'<foo><bar/></foo>'
)
response
=
self
.
_makeOne
(
body
=
xml
,
headers
=
{
'content-type'
:
'text/xml; charset=iso-8859-15'
})
self
.
assertEqual
(
response
.
body
,
xml
)
def
test_retry
(
self
):
...
...
@@ -278,7 +277,7 @@ class HTTPResponseTests(unittest.TestCase):
cookies
=
response
.
_cookie_list
()
self
.
assertEqual
(
len
(
cookies
),
1
)
self
.
assertEqual
(
cookies
[
0
],
(
'Set-Cookie'
,
'foo="bar"; Secure'
))
self
.
assertEqual
(
cookies
[
0
],
(
'Set-Cookie'
,
'foo="bar"; Secure'
))
def
test_setCookie_w_secure_false_value
(
self
):
response
=
self
.
_makeOne
()
...
...
@@ -444,7 +443,7 @@ class HTTPResponseTests(unittest.TestCase):
# RFC2616 disallows CRLF in a header value.
response
=
self
.
_makeOne
()
response
.
appendHeader
(
'Location'
,
'http://www.ietf.org/rfc/
\
r
\
n
rfc2616.txt'
)
'http://www.ietf.org/rfc/
\
r
\
n
rfc2616.txt'
)
self
.
assertEqual
(
response
.
headers
[
'location'
],
'http://www.ietf.org/rfc/rfc2616.txt'
)
...
...
@@ -586,6 +585,7 @@ class HTTPResponseTests(unittest.TestCase):
def
test_setBody_object_with_asHTML
(
self
):
HTML
=
'<html><head></head><body></body></html>'
class
Dummy
:
def
asHTML
(
self
):
return
HTML
...
...
@@ -598,7 +598,8 @@ class HTTPResponseTests(unittest.TestCase):
self
.
assertEqual
(
response
.
getHeader
(
'Content-Length'
),
str
(
len
(
HTML
)))
def
test_setBody_object_with_unicode
(
self
):
HTML
=
u'<html><head></head><body><h1>Tr
\
u0039
s Bien</h1></body></html>'
HTML
=
(
u'<html><head></head><body>'
u'<h1>Tr
\
u0039
s Bien</h1></body></html>'
)
ENCODED
=
HTML
.
encode
(
'utf-8'
)
response
=
self
.
_makeOne
()
result
=
response
.
setBody
(
HTML
)
...
...
@@ -624,7 +625,7 @@ class HTTPResponseTests(unittest.TestCase):
BEFORE
=
(
'<html><head></head><body><p>LT:
\
213
</p>'
'<p>GT:
\
233
</p></body></html>'
)
AFTER
=
(
'<html><head></head><body><p>LT: <</p>'
'<p>GT: ></p></body></html>'
)
'<p>GT: ></p></body></html>'
)
response
.
setHeader
(
'Content-Type'
,
'text/html'
)
result
=
response
.
setBody
(
BEFORE
)
self
.
assertTrue
(
result
)
...
...
@@ -636,7 +637,7 @@ class HTTPResponseTests(unittest.TestCase):
BEFORE
=
(
'<html><head></head><body><p>LT:
\
213
</p>'
'<p>GT:
\
233
</p></body></html>'
)
AFTER
=
(
'<html><head></head><body><p>LT: <</p>'
'<p>GT: ></p></body></html>'
)
'<p>GT: ></p></body></html>'
)
response
.
setHeader
(
'Content-Type'
,
'text/html; charset=latin1'
)
result
=
response
.
setBody
(
BEFORE
)
self
.
assertTrue
(
result
)
...
...
@@ -646,16 +647,15 @@ class HTTPResponseTests(unittest.TestCase):
def
test_setBody_calls_insertBase
(
self
):
response
=
self
.
_makeOne
()
lamb
=
{}
def
_insertBase
():
lamb
[
'flavor'
]
=
'CURRY'
response
.
insertBase
=
_insertBase
response
.
setBody
(
'Garlic Naan'
)
self
.
assertEqual
(
lamb
[
'flavor'
],
'CURRY'
)
#def test_setBody_w_HTTP_content_compression(self):
def
test_setBody_compression_uncompressible_mimetype
(
self
):
BEFORE
=
'foo'
*
100
# body must get smaller on compression
BEFORE
=
'foo'
*
100
# body must get smaller on compression
response
=
self
.
_makeOne
()
response
.
setHeader
(
'Content-Type'
,
'image/jpeg'
)
response
.
enableHTTPCompression
({
'HTTP_ACCEPT_ENCODING'
:
'gzip'
})
...
...
@@ -664,7 +664,7 @@ class HTTPResponseTests(unittest.TestCase):
self
.
assertEqual
(
response
.
body
,
BEFORE
)
def
test_setBody_compression_existing_encoding
(
self
):
BEFORE
=
'foo'
*
100
# body must get smaller on compression
BEFORE
=
'foo'
*
100
# body must get smaller on compression
response
=
self
.
_makeOne
()
response
.
setHeader
(
'Content-Encoding'
,
'piglatin'
)
response
.
enableHTTPCompression
({
'HTTP_ACCEPT_ENCODING'
:
'gzip'
})
...
...
@@ -673,7 +673,7 @@ class HTTPResponseTests(unittest.TestCase):
self
.
assertEqual
(
response
.
body
,
BEFORE
)
def
test_setBody_compression_too_short_to_gzip
(
self
):
BEFORE
=
'foo'
# body must get smaller on compression
BEFORE
=
'foo'
# body must get smaller on compression
response
=
self
.
_makeOne
()
response
.
enableHTTPCompression
({
'HTTP_ACCEPT_ENCODING'
:
'gzip'
})
response
.
setBody
(
BEFORE
)
...
...
@@ -684,7 +684,7 @@ class HTTPResponseTests(unittest.TestCase):
# Vary header should be added here
response
=
self
.
_makeOne
()
response
.
enableHTTPCompression
({
'HTTP_ACCEPT_ENCODING'
:
'gzip'
})
response
.
setBody
(
'foo'
*
100
)
# body must get smaller on compression
response
.
setBody
(
'foo'
*
100
)
# body must get smaller on compression
self
.
assertTrue
(
'Accept-Encoding'
in
response
.
getHeader
(
'Vary'
))
def
test_setBody_compression_w_prior_vary_header_wo_encoding
(
self
):
...
...
@@ -692,7 +692,7 @@ class HTTPResponseTests(unittest.TestCase):
response
=
self
.
_makeOne
()
response
.
setHeader
(
'Vary'
,
'Cookie'
)
response
.
enableHTTPCompression
({
'HTTP_ACCEPT_ENCODING'
:
'gzip'
})
response
.
setBody
(
'foo'
*
100
)
# body must get smaller on compression
response
.
setBody
(
'foo'
*
100
)
# body must get smaller on compression
self
.
assertTrue
(
'Accept-Encoding'
in
response
.
getHeader
(
'Vary'
))
def
test_setBody_compression_w_prior_vary_header_incl_encoding
(
self
):
...
...
@@ -701,7 +701,7 @@ class HTTPResponseTests(unittest.TestCase):
response
=
self
.
_makeOne
()
response
.
enableHTTPCompression
({
'HTTP_ACCEPT_ENCODING'
:
'gzip'
})
response
.
setHeader
(
'Vary'
,
PRIOR
)
response
.
setBody
(
'foo'
*
100
)
response
.
setBody
(
'foo'
*
100
)
self
.
assertEqual
(
response
.
getHeader
(
'Vary'
),
PRIOR
)
def
test_setBody_compression_no_prior_vary_header_but_forced
(
self
):
...
...
@@ -709,7 +709,7 @@ class HTTPResponseTests(unittest.TestCase):
response
=
self
.
_makeOne
()
response
.
enableHTTPCompression
({
'HTTP_ACCEPT_ENCODING'
:
'gzip'
},
force
=
True
)
response
.
setBody
(
'foo'
*
100
)
# body must get smaller on compression
response
.
setBody
(
'foo'
*
100
)
# body must get smaller on compression
self
.
assertEqual
(
response
.
getHeader
(
'Vary'
),
None
)
def
test_redirect_defaults
(
self
):
...
...
@@ -770,8 +770,8 @@ class HTTPResponseTests(unittest.TestCase):
response
=
self
.
_makeOne
()
response
.
setHeader
(
'Content-Type'
,
'text/html; charset=latin1'
)
self
.
assertEqual
(
response
.
_encode_unicode
(
UNICODE
),
'<?xml version="1.0" encoding="latin1" ?>
\
n
'
+
ELEMENT
.
encode
(
'latin1'
))
'<?xml version="1.0" encoding="latin1" ?>
\
n
'
+
ELEMENT
.
encode
(
'latin1'
))
response
.
getHeader
(
'Content-Type'
,
'text/html; charset=latin1'
)
def
test_quoteHTML
(
self
):
...
...
@@ -786,7 +786,7 @@ class HTTPResponseTests(unittest.TestCase):
response
=
self
.
_makeOne
()
try
:
response
.
notFoundError
()
except
NotFound
,
raised
:
except
NotFound
as
raised
:
self
.
assertEqual
(
response
.
status
,
404
)
self
.
assertTrue
(
"<p><b>Resource:</b> Unknown</p>"
in
str
(
raised
))
else
:
...
...
@@ -797,7 +797,7 @@ class HTTPResponseTests(unittest.TestCase):
response
=
self
.
_makeOne
()
try
:
response
.
notFoundError
(
'ENTRY'
)
except
NotFound
,
raised
:
except
NotFound
as
raised
:
self
.
assertEqual
(
response
.
status
,
404
)
self
.
assertTrue
(
"<p><b>Resource:</b> ENTRY</p>"
in
str
(
raised
))
else
:
...
...
@@ -808,7 +808,7 @@ class HTTPResponseTests(unittest.TestCase):
response
=
self
.
_makeOne
()
try
:
response
.
forbiddenError
()
except
NotFound
,
raised
:
except
NotFound
as
raised
:
self
.
assertEqual
(
response
.
status
,
404
)
self
.
assertTrue
(
"<p><b>Resource:</b> Unknown</p>"
in
str
(
raised
))
else
:
...
...
@@ -819,7 +819,7 @@ class HTTPResponseTests(unittest.TestCase):
response
=
self
.
_makeOne
()
try
:
response
.
forbiddenError
(
'ENTRY'
)
except
NotFound
,
raised
:
except
NotFound
as
raised
:
self
.
assertEqual
(
response
.
status
,
404
)
self
.
assertTrue
(
"<p><b>Resource:</b> ENTRY</p>"
in
str
(
raised
))
else
:
...
...
@@ -830,7 +830,7 @@ class HTTPResponseTests(unittest.TestCase):
response
=
self
.
_makeOne
()
try
:
response
.
debugError
(
'testing'
)
except
NotFound
,
raised
:
except
NotFound
as
raised
:
self
.
assertEqual
(
response
.
status
,
200
)
self
.
assertTrue
(
"Zope has encountered a problem publishing "
"your object.<p>
\
n
testing</p>"
in
str
(
raised
))
...
...
@@ -842,7 +842,7 @@ class HTTPResponseTests(unittest.TestCase):
response
=
self
.
_makeOne
()
try
:
response
.
badRequestError
(
'some_parameter'
)
except
BadRequest
,
raised
:
except
BadRequest
as
raised
:
self
.
assertEqual
(
response
.
status
,
400
)
self
.
assertTrue
(
"The parameter, <em>some_parameter</em>, "
"was omitted from the request."
in
str
(
raised
))
...
...
@@ -854,7 +854,7 @@ class HTTPResponseTests(unittest.TestCase):
response
=
self
.
_makeOne
()
try
:
response
.
badRequestError
(
'URL1'
)
except
InternalError
,
raised
:
except
InternalError
as
raised
:
self
.
assertEqual
(
response
.
status
,
400
)
self
.
assertTrue
(
"Sorry, an internal error occurred in this "
"resource."
in
str
(
raised
))
...
...
@@ -870,7 +870,7 @@ class HTTPResponseTests(unittest.TestCase):
def
test__unauthorized_w_default_realm
(
self
):
response
=
self
.
_makeOne
()
response
.
_unauthorized
()
self
.
assertTrue
(
'WWW-Authenticate'
in
response
.
headers
)
#
literal
self
.
assertTrue
(
'WWW-Authenticate'
in
response
.
headers
)
#
literal
self
.
assertEqual
(
response
.
headers
[
'WWW-Authenticate'
],
'basic realm="Zope"'
)
...
...
@@ -878,7 +878,7 @@ class HTTPResponseTests(unittest.TestCase):
response
=
self
.
_makeOne
()
response
.
realm
=
'Folly'
response
.
_unauthorized
()
self
.
assertTrue
(
'WWW-Authenticate'
in
response
.
headers
)
#
literal
self
.
assertTrue
(
'WWW-Authenticate'
in
response
.
headers
)
#
literal
self
.
assertEqual
(
response
.
headers
[
'WWW-Authenticate'
],
'basic realm="Folly"'
)
...
...
@@ -887,8 +887,8 @@ class HTTPResponseTests(unittest.TestCase):
response
=
self
.
_makeOne
()
try
:
response
.
unauthorized
()
except
Unauthorized
,
raised
:
self
.
assertEqual
(
response
.
status
,
200
)
# publisher sets 401 later
except
Unauthorized
as
raised
:
self
.
assertEqual
(
response
.
status
,
200
)
# publisher sets 401 later
self
.
assertTrue
(
"You are not authorized "
"to access this resource."
in
str
(
raised
))
else
:
...
...
@@ -900,7 +900,7 @@ class HTTPResponseTests(unittest.TestCase):
response
.
debug_mode
=
True
try
:
response
.
unauthorized
()
except
Unauthorized
,
raised
:
except
Unauthorized
as
raised
:
self
.
assertTrue
(
"
\
n
No Authorization header found."
in
str
(
raised
))
else
:
...
...
@@ -913,7 +913,7 @@ class HTTPResponseTests(unittest.TestCase):
response
.
_auth
=
'bogus'
try
:
response
.
unauthorized
()
except
Unauthorized
,
raised
:
except
Unauthorized
as
raised
:
self
.
assertTrue
(
"
\
n
Username and password are not correct."
in
str
(
raised
))
else
:
...
...
@@ -927,7 +927,7 @@ class HTTPResponseTests(unittest.TestCase):
[(
'X-Powered-By'
,
'Zope (www.zope.org), '
'Python (www.python.org)'
),
(
'Content-Length'
,
'0'
),
])
])
def
test_finalize_w_body
(
self
):
response
=
self
.
_makeOne
()
...
...
@@ -938,7 +938,7 @@ class HTTPResponseTests(unittest.TestCase):
[(
'X-Powered-By'
,
'Zope (www.zope.org), '
'Python (www.python.org)'
),
(
'Content-Length'
,
'4'
),
])
])
def
test_finalize_w_existing_content_length
(
self
):
response
=
self
.
_makeOne
()
...
...
@@ -949,7 +949,7 @@ class HTTPResponseTests(unittest.TestCase):
[(
'X-Powered-By'
,
'Zope (www.zope.org), '
'Python (www.python.org)'
),
(
'Content-Length'
,
'42'
),
])
])
def
test_finalize_w_transfer_encoding
(
self
):
response
=
self
.
_makeOne
()
...
...
@@ -960,7 +960,7 @@ class HTTPResponseTests(unittest.TestCase):
[(
'X-Powered-By'
,
'Zope (www.zope.org), '
'Python (www.python.org)'
),
(
'Transfer-Encoding'
,
'slurry'
),
])
])
def
test_finalize_after_redirect
(
self
):
response
=
self
.
_makeOne
()
...
...
@@ -972,7 +972,7 @@ class HTTPResponseTests(unittest.TestCase):
'Python (www.python.org)'
),
(
'Content-Length'
,
'0'
),
(
'Location'
,
'http://example.com/'
),
])
])
def
test_listHeaders_empty
(
self
):
response
=
self
.
_makeOne
()
...
...
@@ -980,7 +980,7 @@ class HTTPResponseTests(unittest.TestCase):
self
.
assertEqual
(
headers
,
[(
'X-Powered-By'
,
'Zope (www.zope.org), '
'Python (www.python.org)'
),
])
])
def
test_listHeaders_already_wrote
(
self
):
# listHeaders doesn't do the short-circuit on _wrote.
...
...
@@ -990,7 +990,7 @@ class HTTPResponseTests(unittest.TestCase):
self
.
assertEqual
(
headers
,
[(
'X-Powered-By'
,
'Zope (www.zope.org), '
'Python (www.python.org)'
),
])
])
def
test_listHeaders_existing_content_length
(
self
):
response
=
self
.
_makeOne
()
...
...
@@ -1000,7 +1000,7 @@ class HTTPResponseTests(unittest.TestCase):
[(
'X-Powered-By'
,
'Zope (www.zope.org), '
'Python (www.python.org)'
),
(
'Content-Length'
,
'42'
),
])
])
def
test_listHeaders_existing_transfer_encoding
(
self
):
# If 'Transfer-Encoding' is set, don't force 'Content-Length'.
...
...
@@ -1011,7 +1011,7 @@ class HTTPResponseTests(unittest.TestCase):
[(
'X-Powered-By'
,
'Zope (www.zope.org), '
'Python (www.python.org)'
),
(
'Transfer-Encoding'
,
'slurry'
),
])
])
def
test_listHeaders_after_setHeader
(
self
):
response
=
self
.
_makeOne
()
...
...
@@ -1021,7 +1021,7 @@ class HTTPResponseTests(unittest.TestCase):
[(
'X-Powered-By'
,
'Zope (www.zope.org), '
'Python (www.python.org)'
),
(
'X-Consistency'
,
'Foolish'
),
])
])
def
test_listHeaders_after_setHeader_literal
(
self
):
response
=
self
.
_makeOne
()
...
...
@@ -1031,7 +1031,7 @@ class HTTPResponseTests(unittest.TestCase):
[(
'X-Powered-By'
,
'Zope (www.zope.org), '
'Python (www.python.org)'
),
(
'X-consistency'
,
'Foolish'
),
])
])
def
test_listHeaders_after_redirect
(
self
):
response
=
self
.
_makeOne
()
...
...
@@ -1041,7 +1041,7 @@ class HTTPResponseTests(unittest.TestCase):
[(
'X-Powered-By'
,
'Zope (www.zope.org), '
'Python (www.python.org)'
),
(
'Location'
,
'http://example.com/'
),
])
])
def
test_listHeaders_after_setCookie_appendCookie
(
self
):
response
=
self
.
_makeOne
()
...
...
@@ -1052,20 +1052,20 @@ class HTTPResponseTests(unittest.TestCase):
[(
'X-Powered-By'
,
'Zope (www.zope.org), '
'Python (www.python.org)'
),
(
'Set-Cookie'
,
'foo="bar%3Abaz"; Path=/'
),
])
])
def
test_listHeaders_after_expireCookie
(
self
):
response
=
self
.
_makeOne
()
response
.
expireCookie
(
'qux'
,
path
=
'/'
)
headers
=
response
.
listHeaders
()
self
.
assertEqual
(
headers
,
[(
'X-Powered-By'
,
'Zope (www.zope.org), '
'
Python (www.python.org)'
),
(
'Set-Cookie'
,
'qux="deleted"; '
'Path=/; '
'Expires=Wed, 31-Dec-97 23:59:59 GMT; '
'Max-Age=0'
),
])
self
.
assertEqual
(
headers
,
[(
'X-Powered-By'
,
'Zope (www.zope.org),
Python (www.python.org)'
),
(
'Set-Cookie'
,
'qux="deleted"; '
'Path=/; '
'Expires=Wed, 31-Dec-97 23:59:59 GMT; '
'Max-Age=0'
),
])
def
test_listHeaders_after_addHeader
(
self
):
response
=
self
.
_makeOne
()
...
...
@@ -1077,7 +1077,7 @@ class HTTPResponseTests(unittest.TestCase):
'Python (www.python.org)'
),
(
'X-Consistency'
,
'Foolish'
),
(
'X-Consistency'
,
'Oatmeal'
),
])
])
def
test_listHeaders_w_body
(
self
):
response
=
self
.
_makeOne
()
...
...
@@ -1088,7 +1088,7 @@ class HTTPResponseTests(unittest.TestCase):
'Python (www.python.org)'
),
(
'Content-Length'
,
'4'
),
(
'Content-Type'
,
'text/plain; charset=utf-8'
),
])
])
def
test___str__already_wrote
(
self
):
response
=
self
.
_makeOne
()
...
...
@@ -1300,12 +1300,3 @@ class HTTPResponseTests(unittest.TestCase):
'See the server error log for details'
)
self
.
assertTrue
(
'bobo-exception-file'
in
response
.
headers
)
self
.
assertTrue
(
'bobo-exception-line'
in
response
.
headers
)
#TODO
# def test_exception_* WAAAAAA!
def
test_suite
():
suite
=
unittest
.
TestSuite
()
suite
.
addTest
(
unittest
.
makeSuite
(
HTTPResponseTests
,
'test'
))
return
suite
src/ZPublisher/tests/testIterators.py
View file @
efe61189
...
...
@@ -2,11 +2,8 @@ import unittest
from
zope.interface.verify
import
verifyClass
from
ZPublisher.Iterators
import
IStreamIterator
,
filestream_iterator
class
TestFileStreamIterator
(
unittest
.
TestCase
):
def
testInterface
(
self
):
verifyClass
(
IStreamIterator
,
filestream_iterator
)
def
test_suite
():
suite
=
unittest
.
TestSuite
()
suite
.
addTest
(
unittest
.
makeSuite
(
TestFileStreamIterator
)
)
return
suite
src/ZPublisher/tests/testPostTraversal.py
View file @
efe61189
from
unittest
import
TestCase
,
TestSuite
,
makeSuite
,
main
import
Testing
import
Zope2
Zope2
.
startup
()
from
unittest
import
TestCase
from
Acquisition
import
Implicit
from
ZPublisher.BaseRequest
import
BaseRequest
from
ZPublisher.HTTPResponse
import
HTTPResponse
import
Zope2
# Various post traversal methods
Zope2
.
startup
()
pt_simple_was_run
=
0
def
pt_simple
():
global
pt_simple_was_run
global
pt_simple_was_run
pt_simple_was_run
=
1
pass
def
pt_static_arg
(
request
,
b
):
request
.
set
(
'b'
,
b
)
pass
def
pt_simple_redirect
(
a
):
return
a
def
pt_chain_test
(
request
,
string
):
request
.
set
(
'a'
,
request
.
get
(
'a'
,
''
)
+
string
)
class
DummyObjectBasic
(
Implicit
):
""" Dummy class with docstring.
"""
...
...
@@ -41,6 +42,7 @@ class DummyObjectBasic(Implicit):
"""
return
'view content'
class
DummyObjectWithPTHook
(
DummyObjectBasic
):
""" Dummy class with docstring.
"""
...
...
@@ -51,32 +53,35 @@ class DummyObjectWithPTHook(DummyObjectBasic):
for
x
in
self
.
traversal
:
REQUEST
.
post_traverse
(
*
x
)
class
TestBaseRequestPT
(
TestCase
):
def
setUp
(
self
):
self
.
root
=
DummyObjectBasic
()
self
.
f1
=
self
.
root
.
_setObject
(
'folder'
,
DummyObjectBasic
()
)
self
.
f1
.
_setObject
(
'objBasic'
,
DummyObjectWithPTHook
()
)
self
.
f1
=
self
.
root
.
_setObject
(
'folder'
,
DummyObjectBasic
())
self
.
f1
.
_setObject
(
'objBasic'
,
DummyObjectWithPTHook
())
def
makeBaseRequest
(
self
):
response
=
HTTPResponse
()
environment
=
{
'URL'
:
''
,
'PARENTS'
:
[
self
.
root
],
'steps'
:
[],
'_hacked_path'
:
0
,
'_test_counter'
:
0
,
'response'
:
response
}
environment
=
{
'URL'
:
''
,
'PARENTS'
:
[
self
.
root
],
'steps'
:
[],
'_hacked_path'
:
0
,
'_test_counter'
:
0
,
'response'
:
response
,
}
return
BaseRequest
(
environment
)
def
test_post_basic
(
self
):
global
pt_simple_was_run
pt_simple_was_run
=
0
r
=
self
.
makeBaseRequest
()
# Set hook
self
.
f1
.
objBasic
.
traversal
=
[(
pt_simple
,)]
x
=
r
.
traverse
(
'folder/objBasic'
)
# Object should be self.f1.objBasic
self
.
assertEqual
(
x
,
self
.
f1
.
objBasic
)
self
.
assertEqual
(
pt_simple_was_run
,
1
)
...
...
@@ -101,13 +106,15 @@ class TestBaseRequestPT(TestCase):
r
=
self
.
makeBaseRequest
()
self
.
f1
.
objBasic
.
traversal
=
[
(
pt_chain_test
,
(
r
,
'a'
)),
(
pt_chain_test
,
(
r
,
'b'
)),
(
pt_chain_test
,
(
r
,
'c'
)),
(
pt_chain_test
,
(
r
,
'd'
))]
self
.
f1
.
objBasic
.
traversal
=
[
(
pt_chain_test
,
(
r
,
'a'
)),
(
pt_chain_test
,
(
r
,
'b'
)),
(
pt_chain_test
,
(
r
,
'c'
)),
(
pt_chain_test
,
(
r
,
'd'
)),
]
x
=
r
.
traverse
(
'folder/objBasic'
)
self
.
assertEqual
(
r
.
get
(
'a'
,
''
),
'abcd'
)
r
.
traverse
(
'folder/objBasic'
)
self
.
assertEqual
(
r
.
get
(
'a'
,
''
),
'abcd'
)
self
.
f1
.
objBasic
.
traversal
=
[]
...
...
@@ -119,21 +126,20 @@ class TestBaseRequestPT(TestCase):
x
=
r
.
traverse
(
'folder/objBasic'
)
self
.
assertEqual
(
x
,
check
)
def
test_hook_chain_redirect
(
self
):
r
=
self
.
makeBaseRequest
()
check
=
[]
self
.
f1
.
objBasic
.
traversal
=
[
(
pt_chain_test
,
(
r
,
'a'
)),
(
pt_chain_test
,
(
r
,
'b'
)),
(
pt_chain_test
,
(
r
,
'c'
)),
(
pt_simple_redirect
,
(
check
,)),
(
pt_simple_redirect
,
(
1
,)),
(
pt_chain_test
,
(
r
,
'd'
))]
self
.
f1
.
objBasic
.
traversal
=
[
(
pt_chain_test
,
(
r
,
'a'
)),
(
pt_chain_test
,
(
r
,
'b'
)),
(
pt_chain_test
,
(
r
,
'c'
)),
(
pt_simple_redirect
,
(
check
,)),
(
pt_simple_redirect
,
(
1
,)),
(
pt_chain_test
,
(
r
,
'd'
)),
]
x
=
r
.
traverse
(
'folder/objBasic'
)
self
.
assertEqual
(
r
.
get
(
'a'
,
''
),
'abc'
)
self
.
assertEqual
(
r
.
get
(
'a'
,
''
),
'abc'
)
self
.
assertEqual
(
x
,
check
)
def
test_suite
():
return
TestSuite
(
(
makeSuite
(
TestBaseRequestPT
),
)
)
src/ZPublisher/tests/testPublish.py
View file @
efe61189
import
doctest
from
zope.interface
import
implements
from
zope.publisher.interfaces.browser
import
IDefaultBrowserLayer
from
zope.publisher.interfaces.browser
import
IBrowserRequest
...
...
@@ -5,6 +7,7 @@ from zope.publisher.skinnable import setDefaultSkin
from
ZPublisher
import
Retry
from
ZODB.POSException
import
ConflictError
class
Tracer
:
"""Trace used to record pathway taken through the publisher
machinery. And provide framework for spewing out exceptions at
...
...
@@ -23,21 +26,21 @@ class Tracer:
def
showTracedPath
(
self
):
for
arg
in
self
.
tracedPath
:
print
arg
print
(
arg
)
def
possiblyRaiseException
(
self
,
context
):
exceptions
=
tracer
.
exceptions
.
get
(
context
,
None
)
if
exceptions
:
exception
=
exceptions
[
0
]
exceptions
.
remove
(
exception
)
exceptionShortName
=
exception
.
__name__
# KISS
exceptionShortName
=
exception
.
__name__
# KISS
exceptionShortName
=
exceptionShortName
.
split
(
"'"
)[
0
]
self
.
append
(
'raising %s from %s'
%
(
exceptionShortName
,
context
))
self
.
append
(
'raising %s from %s'
%
(
exceptionShortName
,
context
))
raise
exception
tracer
=
Tracer
()
class
TransactionsManager
:
"""Mock TransactionManager to replace
Zope2.App.startup.TransactionsManager.
...
...
@@ -58,6 +61,7 @@ class TransactionsManager:
zpublisher_transactions_manager
=
TransactionsManager
()
def
zpublisher_exception_hook
(
published
,
request
,
t
,
v
,
traceback
):
"""Mock zpublisher_exception_hook to replace
Zope2.App.startup.zpublisher_exception_hook
...
...
@@ -71,6 +75,7 @@ def zpublisher_exception_hook(published, request, t, v, traceback):
tracer
.
possiblyRaiseException
(
'zpublisher_exception_hook'
)
return
'zpublisher_exception_hook'
class
Object
:
"""Mock object for traversing to.
"""
...
...
@@ -80,6 +85,7 @@ class Object:
tracer
.
possiblyRaiseException
(
'__call__'
)
return
'__call__'
class
Response
:
"""Mock Response to replace ZPublisher.HTTPResponse.HTTPResponse.
"""
...
...
@@ -87,6 +93,7 @@ class Response:
def
setBody
(
self
,
a
):
pass
class
Request
:
"""Mock Request to replace ZPublisher.HTTPRequest.HTTPRequest.
"""
...
...
@@ -125,6 +132,7 @@ class Request:
r
.
retry_count
=
self
.
retry_count
return
r
class
RequestWithSkinCheck
(
Request
):
def
traverse
(
self
,
path
,
validated_hook
):
if
IDefaultBrowserLayer
.
providedBy
(
self
):
...
...
@@ -331,6 +339,7 @@ def testPublisher():
"""
pass
class
ObjectNotFound
:
"""Mock object for traversing to.
"""
...
...
@@ -357,6 +366,7 @@ class PathRequest(Request):
else
:
return
ObjectNotFound
()
def
testPublishPath
():
"""
Tests to ensure that publish passes paths through to the request without
...
...
@@ -388,10 +398,7 @@ def testPublishPath():
commit
"""
pass
import
doctest
def
test_suite
():
return
doctest
.
DocTestSuite
()
src/ZPublisher/tests/test_Converters.py
View file @
efe61189
...
...
@@ -13,6 +13,7 @@
import
unittest
class
ConvertersTests
(
unittest
.
TestCase
):
def
test_field2string_with_string
(
self
):
...
...
@@ -29,21 +30,12 @@ class ConvertersTests(unittest.TestCase):
def
test_field2string_with_filelike_object
(
self
):
from
ZPublisher.Converters
import
field2string
to_convert
=
'to_convert'
class
Filelike
:
def
read
(
self
):
return
to_convert
self
.
assertEqual
(
field2string
(
Filelike
()),
to_convert
)
#TODO def test_field2text....
#TODO def test_field2required....
#TODO def test_field2int....
#TODO def test_field2float....
#TODO def test_field2tokens....
def
test_field2lines_with_list
(
self
):
from
ZPublisher.Converters
import
field2lines
to_convert
=
[
'one'
,
'two'
]
...
...
@@ -68,19 +60,6 @@ class ConvertersTests(unittest.TestCase):
from
ZPublisher.Converters
import
field2lines
to_convert
=
'abc
\
n
def
\
n
ghi'
self
.
assertEqual
(
field2lines
(
to_convert
),
to_convert
.
splitlines
())
#TODO def test_field2date....
#TODO def test_field2date_international....
#TODO def test_field2boolean....
#TODO def test_field2ustring....
#TODO def test_field2utokens....
#TODO def test_field2utext....
def
test_field2ulines_with_list
(
self
):
from
ZPublisher.Converters
import
field2ulines
...
...
@@ -108,7 +87,3 @@ class ConvertersTests(unittest.TestCase):
from
ZPublisher.Converters
import
field2ulines
to_convert
=
u'abc
\
n
def
\
n
ghi'
self
.
assertEqual
(
field2ulines
(
to_convert
),
to_convert
.
splitlines
())
def
test_suite
():
return
unittest
.
TestSuite
((
unittest
.
makeSuite
(
ConvertersTests
),))
src/ZPublisher/tests/test_exception_handling.py
View file @
efe61189
...
...
@@ -40,8 +40,11 @@ class ExceptionRaiser3(SimpleItem):
def
test_suite
():
return
unittest
.
TestSuite
([
FunctionalDocFileSuite
(
'exception_handling.txt'
,
globs
=
{
'ExceptionRaiser1'
:
ExceptionRaiser1
,
'ExceptionRaiser2'
:
ExceptionRaiser2
,
'ExceptionRaiser3'
:
ExceptionRaiser3
,}),
])
FunctionalDocFileSuite
(
'exception_handling.txt'
,
globs
=
{
'ExceptionRaiser1'
:
ExceptionRaiser1
,
'ExceptionRaiser2'
:
ExceptionRaiser2
,
'ExceptionRaiser3'
:
ExceptionRaiser3
,
}),
])
src/ZPublisher/tests/test_mapply.py
View file @
efe61189
...
...
@@ -11,19 +11,21 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Test mapply() function
"""
import
unittest
import
ExtensionClass
import
Acquisition
from
ZPublisher.mapply
import
mapply
class
MapplyTests
(
unittest
.
TestCase
):
def
testMethod
(
self
):
def
compute
(
a
,
b
,
c
=
4
):
def
compute
(
a
,
b
,
c
=
4
):
return
'%d%d%d'
%
(
a
,
b
,
c
)
values
=
{
'a'
:
2
,
'b'
:
3
,
'c'
:
5
}
values
=
{
'a'
:
2
,
'b'
:
3
,
'c'
:
5
}
v
=
mapply
(
compute
,
(),
values
)
self
.
assertEqual
(
v
,
'235'
)
...
...
@@ -31,12 +33,16 @@ class MapplyTests(unittest.TestCase):
self
.
assertEqual
(
v
,
'735'
)
def
testClass
(
self
):
values
=
{
'a'
:
2
,
'b'
:
3
,
'c'
:
5
}
values
=
{
'a'
:
2
,
'b'
:
3
,
'c'
:
5
}
class
c
(
object
):
a
=
3
def
__call__
(
self
,
b
,
c
=
4
):
return
'%d%d%d'
%
(
self
.
a
,
b
,
c
)
compute
=
__call__
cc
=
c
()
v
=
mapply
(
cc
,
(),
values
)
self
.
assertEqual
(
v
,
'335'
)
...
...
@@ -47,7 +53,7 @@ class MapplyTests(unittest.TestCase):
class
c2
:
"""Must be a classic class."""
c2inst
=
c2
()
c2inst
.
__call__
=
cc
v
=
mapply
(
c2inst
,
(),
values
)
...
...
@@ -91,8 +97,3 @@ class MapplyTests(unittest.TestCase):
ob
=
NoCallButAcquisition
().
__of__
(
Root
())
self
.
assertRaises
(
TypeError
,
mapply
,
ob
,
(),
{})
def
test_suite
():
suite
=
unittest
.
TestSuite
()
suite
.
addTest
(
unittest
.
makeSuite
(
MapplyTests
))
return
suite
src/ZPublisher/tests/test_xmlrpc.py
View file @
efe61189
import
unittest
from
DateTime
import
DateTime
class
FauxResponse
:
def
__init__
(
self
):
...
...
@@ -16,10 +17,12 @@ class FauxResponse:
def
setStatus
(
self
,
status
):
self
.
_status
=
status
class
FauxInstance
:
def
__init__
(
self
,
**
kw
):
self
.
__dict__
.
update
(
kw
)
class
XMLRPCResponseTests
(
unittest
.
TestCase
):
def
_getTargetClass
(
self
):
...
...
@@ -87,7 +90,8 @@ class XMLRPCResponseTests(unittest.TestCase):
def
test_instanceattribute_recursive
(
self
):
# Instance "flattening" should work recursively, ad infinitum
import
xmlrpclib
body
=
FauxInstance
(
public
=
FauxInstance
(
public
=
FauxInstance
(
_secret
=
'abc'
,
public
=
'def'
)))
body
=
FauxInstance
(
public
=
FauxInstance
(
public
=
FauxInstance
(
_secret
=
'abc'
,
public
=
'def'
)))
faux
=
FauxResponse
()
response
=
self
.
_makeOne
(
faux
)
response
.
setBody
(
body
)
...
...
@@ -148,7 +152,8 @@ class XMLRPCResponseTests(unittest.TestCase):
def
test_zopedatetimeattribute_recursive
(
self
):
# DateTime encoding should work recursively
import
xmlrpclib
body
=
FauxInstance
(
public
=
FauxInstance
(
public
=
DateTime
(
'2006-05-24 07:00:00 GMT+0'
)))
body
=
FauxInstance
(
public
=
FauxInstance
(
public
=
DateTime
(
'2006-05-24 07:00:00 GMT+0'
)))
faux
=
FauxResponse
()
response
=
self
.
_makeOne
(
faux
)
response
.
setBody
(
body
)
...
...
@@ -185,7 +190,10 @@ class XMLRPCResponseTests(unittest.TestCase):
# Cannot marshal functions or methods, obviously
import
sys
import
xmlrpclib
def
foo
():
pass
def
foo
():
pass
body
=
FauxInstance
(
public
=
foo
)
faux
=
FauxResponse
()
response
=
self
.
_makeOne
(
faux
)
...
...
@@ -208,7 +216,3 @@ class XMLRPCResponseTests(unittest.TestCase):
data
,
method
=
xmlrpclib
.
loads
(
faux
.
_body
)
data
=
data
[
0
]
self
.
assertEqual
(
data
,
{
''
:
True
})
def
test_suite
():
return
unittest
.
TestSuite
((
unittest
.
makeSuite
(
XMLRPCResponseTests
),))
src/ZPublisher/tests/testpubevents.py
View file @
efe61189
from
StringIO
import
StringIO
from
sys
import
modules
,
exc_info
from
unittest
import
TestCase
,
TestSuite
,
makeSuite
,
main
from
unittest
import
TestCase
from
ZODB.POSException
import
ConflictError
from
zope.interface.verify
import
verifyObject
...
...
@@ -9,19 +9,24 @@ from zope.event import subscribers
from
ZPublisher.Publish
import
publish
,
Retry
from
ZPublisher.BaseRequest
import
BaseRequest
from
ZPublisher.HTTPResponse
import
HTTPResponse
from
ZPublisher.pubevents
import
PubStart
,
PubSuccess
,
PubFailure
,
\
PubAfterTraversal
,
PubBeforeCommit
,
PubBeforeAbort
,
\
PubBeforeStreaming
from
ZPublisher.interfaces
import
\
IPubStart
,
IPubEnd
,
IPubSuccess
,
IPubFailure
,
\
IPubAfterTraversal
,
IPubBeforeCommit
,
\
IPubBeforeStreaming
from
ZPublisher.pubevents
import
(
PubStart
,
PubSuccess
,
PubFailure
,
PubAfterTraversal
,
PubBeforeCommit
,
PubBeforeAbort
,
PubBeforeStreaming
,
)
from
ZPublisher.interfaces
import
(
IPubStart
,
IPubEnd
,
IPubSuccess
,
IPubFailure
,
IPubAfterTraversal
,
IPubBeforeCommit
,
IPubBeforeStreaming
,
)
PUBMODULE
=
'TEST_testpubevents'
_g
=
globals
()
_g
=
globals
()
class
TestInterface
(
TestCase
):
def
testPubStart
(
self
):
verifyObject
(
IPubStart
,
PubStart
(
_Request
()))
...
...
@@ -32,8 +37,10 @@ class TestInterface(TestCase):
def
testPubFailure
(
self
):
# get some exc info
try
:
raise
ValueError
()
except
:
exc
=
exc_info
()
try
:
raise
ValueError
()
except
Exception
:
exc
=
exc_info
()
e
=
PubFailure
(
_Request
(),
exc
,
False
)
verifyObject
(
IPubFailure
,
e
)
verifyObject
(
IPubEnd
,
e
)
...
...
@@ -45,11 +52,12 @@ class TestInterface(TestCase):
def
testBeforeCommit
(
self
):
e
=
PubBeforeCommit
(
_Request
())
verifyObject
(
IPubBeforeCommit
,
e
)
def
testBeforeStreaming
(
self
):
e
=
PubBeforeStreaming
(
_Response
())
verifyObject
(
IPubBeforeStreaming
,
e
)
class
TestPubEvents
(
TestCase
):
def
setUp
(
self
):
self
.
_saved_subscribers
=
subscribers
[:]
...
...
@@ -59,11 +67,13 @@ class TestPubEvents(TestCase):
self
.
request
=
_Request
()
def
tearDown
(
self
):
if
PUBMODULE
in
modules
:
del
modules
[
PUBMODULE
]
if
PUBMODULE
in
modules
:
del
modules
[
PUBMODULE
]
subscribers
[:]
=
self
.
_saved_subscribers
def
testSuccess
(
self
):
r
=
self
.
request
;
r
.
action
=
'succeed'
r
=
self
.
request
r
.
action
=
'succeed'
publish
(
r
,
PUBMODULE
,
[
None
])
events
=
self
.
reporter
.
events
self
.
assertEqual
(
len
(
events
),
4
)
...
...
@@ -78,7 +88,8 @@ class TestPubEvents(TestCase):
self
.
assertEqual
(
events
[
2
].
request
,
r
)
def
testFailureReturn
(
self
):
r
=
self
.
request
;
r
.
action
=
'fail_return'
r
=
self
.
request
r
.
action
=
'fail_return'
publish
(
r
,
PUBMODULE
,
[
None
])
events
=
self
.
reporter
.
events
self
.
assertEqual
(
len
(
events
),
3
)
...
...
@@ -93,7 +104,8 @@ class TestPubEvents(TestCase):
self
.
assertEqual
(
len
(
events
[
2
].
exc_info
),
3
)
def
testFailureException
(
self
):
r
=
self
.
request
;
r
.
action
=
'fail_exception'
r
=
self
.
request
r
.
action
=
'fail_exception'
self
.
assertRaises
(
Exception
,
publish
,
r
,
PUBMODULE
,
[
None
])
events
=
self
.
reporter
.
events
self
.
assertEqual
(
len
(
events
),
3
)
...
...
@@ -109,59 +121,66 @@ class TestPubEvents(TestCase):
self
.
assertEqual
(
len
(
events
[
2
].
exc_info
),
3
)
def
testFailureConflict
(
self
):
r
=
self
.
request
;
r
.
action
=
'conflict'
r
=
self
.
request
r
.
action
=
'conflict'
publish
(
r
,
PUBMODULE
,
[
None
])
events
=
self
.
reporter
.
events
self
.
assertEqual
(
len
(
events
),
7
)
self
.
assert_
(
isinstance
(
events
[
0
],
PubStart
))
self
.
assertEqual
(
events
[
0
].
request
,
r
)
self
.
assert_
(
isinstance
(
events
[
1
],
PubBeforeAbort
))
self
.
assertEqual
(
events
[
1
].
request
,
r
)
self
.
assertEqual
(
events
[
1
].
retry
,
True
)
self
.
assertEqual
(
len
(
events
[
1
].
exc_info
),
3
)
self
.
assert_
(
isinstance
(
events
[
1
].
exc_info
[
1
],
ConflictError
))
self
.
assert_
(
isinstance
(
events
[
2
],
PubFailure
))
self
.
assertEqual
(
events
[
2
].
request
,
r
)
self
.
assertEqual
(
events
[
2
].
retry
,
True
)
self
.
assertEqual
(
len
(
events
[
2
].
exc_info
),
3
)
self
.
assert_
(
isinstance
(
events
[
2
].
exc_info
[
1
],
ConflictError
))
self
.
assert_
(
isinstance
(
events
[
3
],
PubStart
))
self
.
assert_
(
isinstance
(
events
[
4
],
PubAfterTraversal
))
self
.
assert_
(
isinstance
(
events
[
5
],
PubBeforeCommit
))
self
.
assert_
(
isinstance
(
events
[
6
],
PubSuccess
))
def
testStreaming
(
self
):
out
=
StringIO
()
response
=
HTTPResponse
(
stdout
=
out
)
response
.
write
(
'datachunk1'
)
response
.
write
(
'datachunk2'
)
events
=
self
.
reporter
.
events
self
.
assertEqual
(
len
(
events
),
1
)
self
.
assert_
(
isinstance
(
events
[
0
],
PubBeforeStreaming
))
self
.
assertEqual
(
events
[
0
].
response
,
response
)
self
.
assertTrue
(
'datachunk1datachunk2'
in
out
.
getvalue
())
# Auxiliaries
def
_succeed
():
''' '''
return
'success'
class
_Application
(
object
):
pass
class
_Application
(
object
):
pass
class
_Reporter
(
object
):
def
__init__
(
self
):
self
.
events
=
[]
def
__call__
(
self
,
event
):
self
.
events
.
append
(
event
)
def
__init__
(
self
):
self
.
events
=
[]
def
__call__
(
self
,
event
):
self
.
events
.
append
(
event
)
class
_Response
(
object
):
def
setBody
(
*
unused
):
pass
def
setBody
(
*
unused
):
pass
class
_Request
(
BaseRequest
):
...
...
@@ -174,7 +193,9 @@ class _Request(BaseRequest):
self
[
'PATH_INFO'
]
=
self
[
'URL'
]
=
''
self
.
steps
=
[]
def
supports_retry
(
self
):
return
True
def
supports_retry
(
self
):
return
True
def
retry
(
self
):
r
=
self
.
__class__
()
r
.
action
=
'succeed'
...
...
@@ -182,25 +203,29 @@ class _Request(BaseRequest):
def
traverse
(
self
,
*
unused
,
**
unused_kw
):
action
=
self
.
action
if
action
.
startswith
(
'fail'
):
raise
Exception
(
action
)
if
action
==
'conflict'
:
raise
ConflictError
()
if
action
==
'succeed'
:
return
_succeed
else
:
raise
ValueError
(
'unknown action: %s'
%
action
)
# override to get rid of the 'EndRequestEvent' notification
def
close
(
self
):
pass
if
action
.
startswith
(
'fail'
):
raise
Exception
(
action
)
if
action
==
'conflict'
:
raise
ConflictError
()
if
action
==
'succeed'
:
return
_succeed
else
:
raise
ValueError
(
'unknown action: %s'
%
action
)
def
close
(
self
):
# override to get rid of the 'EndRequestEvent' notification
pass
# define things necessary for publication
bobo_application
=
_Application
()
def
zpublisher_exception_hook
(
parent
,
request
,
*
unused
):
action
=
request
.
action
if
action
==
'fail_return'
:
return
0
if
action
==
'fail_exception'
:
raise
Exception
()
if
action
==
'conflict'
:
raise
Retry
()
if
action
==
'fail_return'
:
return
0
if
action
==
'fail_exception'
:
raise
Exception
()
if
action
==
'conflict'
:
raise
Retry
()
raise
ValueError
(
'unknown action: %s'
%
action
)
def
test_suite
():
return
TestSuite
((
makeSuite
(
c
)
for
c
in
(
TestPubEvents
,
TestInterface
)))
src/ZPublisher/xmlrpc.py
View file @
efe61189
...
...
@@ -33,6 +33,7 @@ from ZODB.POSException import ConflictError
from
DateTime.DateTime
import
DateTime
WRAPPERS
=
xmlrpclib
.
WRAPPERS
+
(
DateTime
,
)
def
dump_instance
(
self
,
value
,
write
):
# Check for special wrappers
if
value
.
__class__
in
WRAPPERS
:
...
...
@@ -95,6 +96,7 @@ def parse_input(data):
########################################################################
# Possible implementation helpers:
class
Response
:
"""Customized Response that handles XML-RPC-specific details.
...
...
@@ -108,23 +110,29 @@ class Response:
It's probably possible to improve the 'exception' method quite a bit.
The current implementation, however, should suffice for now.
"""
_error_format
=
'text/plain'
# No html in error values
_error_format
=
'text/plain'
# No html in error values
# Because we can't predict what kind of thing we're customizing,
# we have to use delegation, rather than inheritance to do the
# customization.
def
__init__
(
self
,
real
):
self
.
__dict__
[
'_real'
]
=
real
def
__init__
(
self
,
real
):
self
.
__dict__
[
'_real'
]
=
real
def
__getattr__
(
self
,
name
):
return
getattr
(
self
.
_real
,
name
)
def
__setattr__
(
self
,
name
,
v
):
return
setattr
(
self
.
_real
,
name
,
v
)
def
__getattr__
(
self
,
name
):
return
getattr
(
self
.
_real
,
name
)
def
__setattr__
(
self
,
name
,
v
):
return
setattr
(
self
.
_real
,
name
,
v
)
def
__delattr__
(
self
,
name
):
return
delattr
(
self
.
_real
,
name
)
def
__delattr__
(
self
,
name
):
return
delattr
(
self
.
_real
,
name
)
def
setBody
(
self
,
body
,
title
=
''
,
is_error
=
0
,
bogus_str_search
=
None
):
if
isinstance
(
body
,
xmlrpclib
.
Fault
):
# Convert Fault object to XML-RPC response.
body
=
xmlrpclib
.
dumps
(
body
,
methodresponse
=
1
,
allow_none
=
True
)
body
=
xmlrpclib
.
dumps
(
body
,
methodresponse
=
1
,
allow_none
=
True
)
else
:
# Marshall our body as an XML-RPC response. Strings will be sent
# strings, integers as integers, etc. We do *not* convert
...
...
@@ -161,8 +169,8 @@ class Response:
return
self
.
_real
.
exception
(
fatal
=
fatal
,
info
=
info
)
# Create an appropriate Fault object. Containing error information
Fault
=
xmlrpclib
.
Fault
f
=
None
Fault
=
xmlrpclib
.
Fault
f
=
None
try
:
# Strip HTML tags from the error value
vstr
=
str
(
v
)
...
...
@@ -175,15 +183,15 @@ class Response:
else
:
value
=
'%s - %s'
%
(
t
,
vstr
)
if
isinstance
(
v
,
Fault
):
f
=
v
f
=
v
elif
isinstance
(
v
,
Exception
):
f
=
Fault
(
-
1
,
'Unexpected Zope exception: %s'
%
value
)
f
=
Fault
(
-
1
,
'Unexpected Zope exception: %s'
%
value
)
else
:
f
=
Fault
(
-
2
,
'Unexpected Zope error value: %s'
%
value
)
f
=
Fault
(
-
2
,
'Unexpected Zope error value: %s'
%
value
)
except
ConflictError
:
raise
except
:
f
=
Fault
(
-
3
,
"Unknown Zope fault type"
)
except
Exception
:
f
=
Fault
(
-
3
,
"Unknown Zope fault type"
)
# Do the damage.
self
.
setBody
(
f
)
...
...
@@ -191,4 +199,4 @@ class Response:
return
tb
response
=
Response
response
=
Response
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