Commit 9d17e061 authored by Gerhard Weis's avatar Gerhard Weis

Merge branch 'master' of https://github.com/zopefoundation/Zope

parents 5e26679d ce2086b5
*.egg-info
*.py?
/.installed.cfg
/.mr.developer.cfg
/bin
/build
/develop
/develop-eggs
/docs/_build
/include
/lib
/dist
/eggs
/parts
docs/.build/
.installed.cfg
.mr.developer.cfg
bin/
build/
develop/
develop-eggs/
dist/
eggs/
include/
lib/
parts/
docs/_build/
......@@ -11,6 +11,11 @@ http://docs.zope.org/zope2/
Bugs Fixed
++++++++++
- LP #789863: Ensure that Request objects cannot be published / traversed
directly via a URL.
- Document running Zope as a WSGI application.
- Queue additional warning filters at the beginning of the queue in order to
allow overrides.
......
Installing Zope with ``virtualenv``
===================================
.. highlight:: bash
This document describes how to install Zope into a ``virtualenv``.
Create a Virtual Environment
----------------------------
.. code-block:: sh
$ /opt/Python-2.7.9/bin/virtualenv z213
New python executable in z213/bin/python
Installing setuptools, pip, wheel...done.
$ cd z213
Install the Zope2 2.13.22 Software Packages
-------------------------------------------
.. code-block:: sh
$ bin/pip install \
--trusted-host download.zope.org \
--index http://download.zope.org/Zope2/index/2.13.22/ Zope2
Collecting Zope2
...
Successfully installed ...
Creating a Zope instance
------------------------
Once you've installed Zope, you will need to create an "instance
home". This is a directory that contains configuration and data for a
Zope server process. The instance home is created using the
``mkzopeinstance`` script:
.. code-block:: sh
$ bin/mkzopeinstance
You can specify the Python interpreter to use for the instance
explicitly:
.. code-block:: sh
$ bin/mkzopeinstance --python=bin/python
You will be asked to provide a user name and password for an
administrator's account during ``mkzopeinstance``. To see the available
command-line options, run the script with the ``--help`` option:
.. code-block:: sh
$ bin/mkzopeinstance --help
Using the ``virtualenv`` as the Zope Instance
---------------------------------------------
You can choose to use the ``virtualenv`` as your Zope instance:
.. code-block:: sh
$ bin/mkzopeinstance -d .
In this case, the instance files will be located in the
subdirectories of the ``virtualenv``:
- ``etc/`` will hold the configuration files.
- ``log/`` will hold the log files.
- ``var/`` will hold the database files.
......@@ -9,7 +9,7 @@ PAPER =
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d .build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html web pickle htmlhelp latex changes linkcheck
......@@ -24,52 +24,52 @@ help:
@echo " linkcheck to check all external links for integrity"
clean:
-rm -rf .build/*
-rm -rf _build/*
html:
mkdir -p .build/html .build/doctrees
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) .build/html
mkdir -p _build/html _build/doctrees
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html
@echo
@echo "Build finished. The HTML pages are in .build/html."
@echo "Build finished. The HTML pages are in _build/html."
pickle:
mkdir -p .build/pickle .build/doctrees
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) .build/pickle
mkdir -p _build/pickle _build/doctrees
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) _build/pickle
@echo
@echo "Build finished; now you can process the pickle files."
web: pickle
json:
mkdir -p .build/json .build/doctrees
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) .build/json
mkdir -p _build/json _build/doctrees
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) _build/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
mkdir -p .build/htmlhelp .build/doctrees
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) .build/htmlhelp
mkdir -p _build/htmlhelp _build/doctrees
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in .build/htmlhelp."
".hhp project file in _build/htmlhelp."
latex:
mkdir -p .build/latex .build/doctrees
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) .build/latex
mkdir -p _build/latex _build/doctrees
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex
@echo
@echo "Build finished; the LaTeX files are in .build/latex."
@echo "Build finished; the LaTeX files are in _build/latex."
@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
"run these through (pdf)latex."
changes:
mkdir -p .build/changes .build/doctrees
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) .build/changes
mkdir -p _build/changes _build/doctrees
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) _build/changes
@echo
@echo "The overview file is in .build/changes."
@echo "The overview file is in _build/changes."
linkcheck:
mkdir -p .build/linkcheck .build/doctrees
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) .build/linkcheck
mkdir -p _build/linkcheck _build/doctrees
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) _build/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in .build/linkcheck/output.txt."
"or in _build/linkcheck/output.txt."
Running Zope2 as a WSGI Application
===================================
This document assumes you have installed Zope into a ``virtualenv`` (see
:doc:`INSTALL-virtualenv`).
Install the Supporting Software
-------------------------------
To run as a WSGI application, you need to install some additional software.
.. code-block:: sh
$ bin/pip install \
--trusted-host download.zope.org \
--index http://download.zope.org/Zope2/index/2.13.22/ \
repoze.who repoze.tm2 repoze.retry Paste PasteDeploy PasteScript
Collecting repoze.who
...
Successfully installed Paste-1.7.5.1 PasteDeploy-1.3.4 PasteScript-1.7.5 repoze.retry-1.2 repoze.tm2-1.0 repoze.who-2.0
Update the Zope Application Configuration
-----------------------------------------
The generated ``etc/zope.conf`` file assumes that Zope will be running
using the built-in ``ZServer``.
.. code-block:: sh
$ vim etc/zope.conf
Update the contents as follows.
.. code-block:: apacheconf
%define INSTANCE /path/to/virtualenv
instancehome $INSTANCE
.. note::
The ``%define instance /path/to/virtualenv`` element must
point to the environment: there is no "relative to this file" support
built in.
Set up logging for the application.
.. code-block:: apacheconf
<eventlog>
level info
<logfile>
path $INSTANCE/log/event.log
level info
</logfile>
</eventlog>
<logger access>
level WARN
<logfile>
path $INSTANCE/log/Z2.log
format %(message)s
</logfile>
</logger>
Configure the database (note that you could use ``ZEO`` or ``Relstorage``
rather than a bare ``FileStorage``):
.. code-block:: apacheconf
<zodb_db main>
# Main FileStorage database
<filestorage>
# See .../ZODB/component.xml for directives (sectiontype
# "filestorage").
path $INSTANCE/var/Data.fs
</filestorage>
mount-point /
</zodb_db>
<zodb_db temporary>
# Temporary storage database (for sessions)
<temporarystorage>
name temporary storage for sessioning
</temporarystorage>
mount-point /temp_folder
container-class Products.TemporaryFolder.TemporaryContainer
</zodb_db>
Because we will be running a separately-configured WSGI server, remove any
``<http-server>`` configuration from the file.
Create the WSGI Server Configuration
------------------------------------
.. code-block:: sh
$ vim etc/zope.wsgi
First, configure the "application" endpoint for Zope:
.. code-block:: ini
[app:zope]
use = egg:Zope2#main
zope_conf = %(here)s/zope.conf
Next, set up the WSGI middleware pipeline:
.. code-block:: ini
[pipeline:main]
pipeline =
egg:paste#evalerror
egg:repoze.retry#retry
egg:repoze.tm2#tm
zope
The middleware layers are "wrapped" around the application endpoint as follows:
- ``paste#evalerror`` is debugging middleware, which shows tracebacks for
errors raised from the application. It should **not** be configured for
production use.
- ``repoze.retry#retry`` is middleware which retries requests when retriable
exceptions are raised. By default, it retries 3 times, and only for
requests which raise ``ZODB.ConflictError``. See
http://repozeretry.rtfd.org/ for details on configuring it otherwise.
- ``repoze.tm2#tm`` is middleware which begins a new transaction for each
request, and then either aborts the transaction (if the request raises an
exception) or commits it (if not). See
http://repozetm2.rtfd.org/ for details on configuring it.
Finally, configure the WSGI server:
.. code-block:: ini
[server:main]
use = egg:paste#http
host = localhost
port = 8080
.. note::
Any server conforming to PEP 333/3333 should work, although the parameters
could change.
Set up the Admin User
---------------------
Before starting the WSGI server, run the ``addzope2user`` script to configure
the administrative user.
.. code-block:: sh
$ bin/addzope2user admin <yourpasswordhere>
No handlers could be found for logger "ZODB.FileStorage"
User admin created.
Start the WSGI Server
---------------------
.. code-block:: sh
$ bin/paster serve etc/zope.wsgi
Starting server in PID 24934.
serving on http://127.0.0.1:8080
Running Other Applications in the same WSGI Server Process
----------------------------------------------------------
You can use any of the normal ``Paste`` WSGI features to combine Zope and
other WSGI applications inside the same server process. E.g., the following
configuration uses the
`composite application <http://pythonpaste.org/deploy/#composite-applications>`_
support offered by ``PasteDeploy`` to host Zope at the ``/`` prefix,
with static files served from disk at ``/static``:
.. code-block:: ini
[app:zope-app]
use = egg:Zope2#main
zope_conf = %(here)s/zope.conf
[pipeline:zope-pipeline]
pipeline =
egg:paste#evalerror
egg:repoze.retry#retry
egg:repoze.tm2#tm
zope-app
[app:static]
use = egg:Paste#static
document_root = %(here)s/static
[composite:main]
use = egg:Paste#urlmap
/ = zope-pipeline
/static = static
......@@ -6,13 +6,16 @@ Contents:
.. toctree::
:maxdepth: 2
WHATSNEW.rst
INSTALL.rst
operation.rst
USERS.rst
SECURITY.rst
SETUID.rst
SIGNALS.rst
DEBUGGING.rst
maintenance.rst
changes.rst
WHATSNEW
INSTALL
INSTALL-buildout
INSTALL-virtualenv
operation
WSGI
USERS
SECURITY
SETUID
SIGNALS
DEBUGGING
maintenance
changes
......@@ -4,8 +4,9 @@ Configuring and Running Zope
.. highlight:: bash
After installing Zope and create a server instance (see :doc:`INSTALL`), the
end result is configured and operated as follows.
Whichever method you used to install Zope and create a server instance (see
:doc:`INSTALL-buildout` and :doc:`INSTALL-virtualenv`), the end result is
configured and operated the same way.
Configuring Zope
......
......@@ -206,6 +206,7 @@ class BaseRequest:
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
......@@ -276,6 +277,9 @@ class BaseRequest:
raise KeyError, key
return v
def __bobo_traverse__(self, name):
raise KeyError(name)
def __getattr__(self, key, default=_marker):
v = self.get(key, default)
if v is _marker:
......
......@@ -313,6 +313,7 @@ class HTTPRequest(BaseRequest):
self._locale = locales.getLocale(None, None, None)
def __init__(self, stdin, environ, response, clean=0):
self.__doc__ = None # Make HTTPRequest objects unpublishable
self._orig_env = environ
# Avoid the overhead of scrubbing the environment in the
# case of request cloning for traversal purposes. If the
......
......@@ -189,6 +189,19 @@ class TestBaseRequest(unittest.TestCase, BaseRequest_factory):
folder = root._setObject('folder', self._makeBasicObject())
return root, folder
def test_no_docstring_on_instance(self):
root, folder = self._makeRootAndFolder()
r = self._makeOne(root)
self.assertTrue(r.__doc__ is None)
def test___bobo_traverse___raises(self):
root, folder = self._makeRootAndFolder()
folder._setObject('objBasic', self._makeBasicObject())
r = self._makeOne(root)
self.assertRaises(KeyError, r.__bobo_traverse__, 'REQUEST')
self.assertRaises(KeyError, r.__bobo_traverse__, 'BODY')
self.assertRaises(KeyError, r.__bobo_traverse__, 'BODYFILE')
def test_traverse_basic(self):
root, folder = self._makeRootAndFolder()
folder._setObject('objBasic', self._makeBasicObject())
......@@ -468,7 +481,7 @@ class TestBaseRequest(unittest.TestCase, BaseRequest_factory):
self.assertRaises(NotFound, r.traverse, 'not_found')
class TestBaseRequestZope3Views(unittest.TestCase, BaseRequest_factory):
class TestRequestZope3ViewsBase(unittest.TestCase, BaseRequest_factory):
_dummy_interface = None
......@@ -479,13 +492,27 @@ class TestBaseRequestZope3Views(unittest.TestCase, BaseRequest_factory):
def _makeOne(self, root):
from zope.interface import directlyProvides
from zope.publisher.browser import IDefaultBrowserLayer
request = super(TestBaseRequestZope3Views, self)._makeOne(root)
request = super(TestRequestZope3ViewsBase, self)._makeOne(root)
# The request needs to implement the proper interface
directlyProvides(request, IDefaultBrowserLayer)
return request
def _makeDummyAclUsers(self):
from Acquisition import Implicit
from AccessControl.ZopeSecurityPolicy import _noroles
class AclUsers(Implicit):
def validate(self, request, auth='', roles=_noroles):
# always validate access as anonymous, good for checking
# if things are publishable regardless of authorization
from AccessControl.SpecialUsers import nobody
return nobody.__of__(self)
acl_users = AclUsers()
return acl_users
def _makeRootAndFolder(self):
root = self._makeBasicObject()
root.__allow_groups__ = self._makeDummyAclUsers()
folder = root._setObject('folder', self._makeDummyObject('folder'))
return root, folder
......@@ -613,6 +640,9 @@ class TestBaseRequestZope3Views(unittest.TestCase, BaseRequest_factory):
gsm.registerAdapter(name, (self._dummyInterface(), IBrowserRequest),
IDefaultViewName, '')
class TestBaseRequestZope3Views(TestRequestZope3ViewsBase):
def test_traverse_view(self):
#simple view
root, folder = self._makeRootAndFolder()
......
import unittest
from ZPublisher.tests.testBaseRequest import TestRequestZope3ViewsBase
from zope.testing.cleanup import cleanUp
......@@ -15,7 +17,7 @@ class RecordTests(unittest.TestCase):
self.assertEqual(d, rec.__dict__)
class HTTPRequestTests(unittest.TestCase):
class HTTPRequestFactoryMixin(object):
def tearDown(self):
cleanUp()
......@@ -26,7 +28,7 @@ class HTTPRequestTests(unittest.TestCase):
def _makeOne(self, stdin=None, environ=None, response=None, clean=1):
from StringIO import StringIO
from ZPublisher import NotFound
from ZPublisher.HTTPResponse import HTTPResponse
if stdin is None:
stdin = StringIO()
......@@ -43,20 +45,12 @@ class HTTPRequestTests(unittest.TestCase):
environ['SERVER_PORT'] = '8080'
if response is None:
class _FauxResponse(object):
_auth = None
debug_mode = False
errmsg = 'OK'
def notFoundError(self, message):
raise NotFound, message
response = HTTPResponse(stdout=StringIO())
def exception(self, *args, **kw):
pass
return self._getTargetClass()(stdin, environ, response, clean)
response = _FauxResponse()
return self._getTargetClass()(stdin, environ, response, clean)
class HTTPRequestTests(unittest.TestCase, HTTPRequestFactoryMixin):
def _processInputs(self, inputs):
from urllib import quote_plus
......@@ -144,6 +138,19 @@ class HTTPRequestTests(unittest.TestCase):
"Key %s not correctly reproduced in tainted; expected %r, "
"got %r" % (key, req.form[key], req.taintedform[key]))
def test_no_docstring_on_instance(self):
env = {'SERVER_NAME': 'testingharnas', 'SERVER_PORT': '80'}
req = self._makeOne(environ=env)
self.assertTrue(req.__doc__ is None)
def test___bobo_traverse___raises(self):
env = {'SERVER_NAME': 'testingharnas', 'SERVER_PORT': '80'}
req = self._makeOne(environ=env)
self.assertRaises(KeyError, req.__bobo_traverse__, 'REQUEST')
self.assertRaises(KeyError, req.__bobo_traverse__, 'BODY')
self.assertRaises(KeyError, req.__bobo_traverse__, 'BODYFILE')
self.assertRaises(KeyError, req.__bobo_traverse__, 'RESPONSE')
def test_processInputs_wo_query_string(self):
env = {'SERVER_NAME': 'testingharnas', 'SERVER_PORT': '80'}
req = self._makeOne(environ=env)
......@@ -1078,6 +1085,34 @@ class HTTPRequestTests(unittest.TestCase):
req._script = ['foo', 'bar']
self.assertEquals(req.getVirtualRoot(), '/foo/bar')
class TestHTTPRequestZope3Views(TestRequestZope3ViewsBase,):
def _makeOne(self, root):
from zope.interface import directlyProvides
from zope.publisher.browser import IDefaultBrowserLayer
request = HTTPRequestFactoryMixin()._makeOne()
request['PARENTS'] = [root]
# The request needs to implement the proper interface
directlyProvides(request, IDefaultBrowserLayer)
return request
def test_no_traversal_of_view_request_attribute(self):
# make sure views don't accidentally publish the 'request' attribute
from ZPublisher import NotFound
root, _ = self._makeRootAndFolder()
# make sure the view itself is traversable:
view = self._makeOne(root).traverse('folder/@@meth')
from ZPublisher.HTTPRequest import HTTPRequest
self.assertEqual(view.request.__class__, HTTPRequest,)
# but not the request:
self.assertRaises(
NotFound,
self._makeOne(root).traverse, 'folder/@@meth/request'
)
TEST_ENVIRON = {
'CONTENT_TYPE': 'multipart/form-data; boundary=12345',
'REQUEST_METHOD': 'POST',
......@@ -1109,4 +1144,5 @@ def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(RecordTests))
suite.addTest(unittest.makeSuite(HTTPRequestTests))
suite.addTest(unittest.makeSuite(TestHTTPRequestZope3Views))
return suite
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment