Index: src/zope/app/http/tests/test_options.py
===================================================================
--- src/zope/app/http/tests/test_options.py (revision 0)
+++ src/zope/app/http/tests/test_options.py (revision 0)
@@ -0,0 +1,66 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# 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.
+#
+##############################################################################
+"""Test HTTP OPTIONS verb
+
+$Id$
+"""
+from unittest import TestCase, TestSuite, makeSuite
+
+from zope.publisher.browser import TestRequest
+
+import zope.app.http.put
+import zope.app.http.options
+from zope.app.testing.placelesssetup import PlacelessSetup
+
+
+class TestNullOPTIONS(PlacelessSetup, TestCase):
+
+ def test(self):
+ request = TestRequest()
+ null = zope.app.http.put.NullResource(object(), 'spam')
+ options = zope.app.http.options.NullOPTIONS(null, request)
+ self.assertEqual(options.OPTIONS(), '')
+
+ # Check HTTP Response
+ self.assertEqual(request.response.getStatus(), 200)
+ self.assertEqual(
+ request.response.getHeader("DAV", literal=True), "1,2")
+ self.assertEqual(
+ request.response.getHeader("MS-Author-Via", literal=True), "DAV")
+ self.assertEqual(
+ request.response.getHeader("Allow"), "")
+
+
+class TestOPTIONS(PlacelessSetup, TestCase):
+
+ def test(self):
+ request = TestRequest()
+ options = zope.app.http.options.OPTIONS(object(), request)
+ self.assertEqual(options.OPTIONS(), '')
+
+ # Check HTTP Response
+ self.assertEqual(request.response.getStatus(), 200)
+ self.assertEqual(
+ request.response.getHeader("DAV", literal=True), "1,2")
+ self.assertEqual(
+ request.response.getHeader("MS-Author-Via", literal=True), "DAV")
+ self.assertEqual(
+ request.response.getHeader("Allow"), "GET, HEAD, POST")
+
+
+def test_suite():
+ return TestSuite((
+ makeSuite(TestNullOPTIONS),
+ makeSuite(TestOPTIONS),
+ ))
Property changes on: src/zope/app/http/tests/test_options.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Index: src/zope/app/http/tests/test_functional_options.py
===================================================================
--- src/zope/app/http/tests/test_functional_options.py (revision 0)
+++ src/zope/app/http/tests/test_functional_options.py (revision 0)
@@ -0,0 +1,57 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# 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.
+#
+##############################################################################
+"""Test HTTP OPTIONS verb
+
+$Id$
+"""
+
+from unittest import TestSuite, makeSuite
+
+from zope.app.testing.functional import FunctionalTestCase, HTTPCaller
+from zope.app.http.testing import AppHttpLayer
+
+class TestOPTIONS(FunctionalTestCase):
+
+ def test_options(self):
+ # First test an existing resource
+ response = HTTPCaller()(r"""OPTIONS / HTTP/1.1
+Authorization: Basic bWdyOm1ncnB3""")
+ self.assertEquals(response._response.getStatus(), 200)
+ self.assertEquals(
+ response._response.getHeader("DAV", literal=True), "1,2")
+ self.assertEquals(
+ response._response.getHeader("MS-Author-Via", literal=True), "DAV")
+ self.assertEquals(
+ response._response.getHeader("Allow"),
+ "GET, HEAD, POST, PUT, DELETE, OPTIONS")
+ self.assertEquals(response.getBody(), "")
+
+ # Then a NullResource
+ response = HTTPCaller()(r"""OPTIONS /foo HTTP/1.1
+Authorization: Basic bWdyOm1ncnB3""")
+ self.assertEquals(response._response.getStatus(), 200)
+ self.assertEquals(
+ response._response.getHeader("DAV", literal=True), "1,2")
+ self.assertEquals(
+ response._response.getHeader("MS-Author-Via", literal=True), "DAV")
+ self.assertEquals(
+ response._response.getHeader("Allow"), "PUT, OPTIONS")
+ self.assertEquals(response.getBody(), "")
+
+
+def test_suite():
+ TestOPTIONS.layer = AppHttpLayer
+ return TestSuite((
+ makeSuite(TestOPTIONS),
+ ))
Property changes on: src/zope/app/http/tests/test_functional_options.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Index: src/zope/app/http/tests/test_traversers.py
===================================================================
--- src/zope/app/http/tests/test_traversers.py (revision 81891)
+++ src/zope/app/http/tests/test_traversers.py (working copy)
@@ -52,9 +52,8 @@
traverser = self.Traverser(container, request)
self.assertRaises(NotFound,
traverser.publishTraverse, request, 'bar')
-
- def testNull(self):
+ def testNullPUT(self):
container = self.Container({'foo': 42})
request = TestRequest()
request.method = 'PUT'
@@ -63,8 +62,38 @@
self.assertEqual(null.__class__, NullResource)
self.assertEqual(null.container, container)
self.assertEqual(null.name, 'bar')
-
+ def testNullMKCOL(self):
+ container = self.Container({'foo': 42})
+ request = TestRequest()
+ request.method = 'MKCOL'
+ traverser = self.Traverser(container, request)
+ null = traverser.publishTraverse(request, 'bar')
+ self.assertEqual(null.__class__, NullResource)
+ self.assertEqual(null.container, container)
+ self.assertEqual(null.name, 'bar')
+
+ def testNullOPTIONS(self):
+ container = self.Container({'foo': 42})
+ request = TestRequest()
+ request.method = 'OPTIONS'
+ traverser = self.Traverser(container, request)
+ null = traverser.publishTraverse(request, 'bar')
+ self.assertEqual(null.__class__, NullResource)
+ self.assertEqual(null.container, container)
+ self.assertEqual(null.name, 'bar')
+
+ def testNullLOCK(self):
+ container = self.Container({'foo': 42})
+ request = TestRequest()
+ request.method = 'LOCK'
+ traverser = self.Traverser(container, request)
+ null = traverser.publishTraverse(request, 'bar')
+ self.assertEqual(null.__class__, NullResource)
+ self.assertEqual(null.container, container)
+ self.assertEqual(null.name, 'bar')
+
+
class TestItem(TestContainer):
Container = Items
Index: src/zope/app/http/options.py
===================================================================
--- src/zope/app/http/options.py (revision 81891)
+++ src/zope/app/http/options.py (working copy)
@@ -20,6 +20,8 @@
'COPY', 'MOVE', 'LOCK', 'UNLOCK', 'TRACE']
# 'GET', 'HEAD', 'POST' are always available. See OPTIONS() method.
+_null_methods = ['PUT', 'MKCOL', 'OPTIONS', 'LOCK']
+
from zope.app import zapi
class OPTIONS(object):
@@ -30,7 +32,7 @@
self.context = context
self.request = request
- def OPTIONS(self):
+ def Allow(self):
allowed = ['GET', 'HEAD', 'POST']
# TODO: This could be cleaned up by providing special target
# interfaces for HTTP methods. This way we can even list verbs that
@@ -39,8 +41,10 @@
view = zapi.queryMultiAdapter((self.context, self.request), name=m)
if view is not None:
allowed.append(m)
+ return allowed
- self.request.response.setHeader('Allow', ', '.join(allowed))
+ def OPTIONS(self):
+ self.request.response.setHeader('Allow', ', '.join(self.Allow()))
# TODO: Most of the time, this is a lie. We not fully support
# DAV 2 on all objects, so probably an interface check is needed.
self.request.response.setHeader('DAV', '1,2', literal=True)
@@ -49,3 +53,18 @@
self.request.response.setStatus(200)
return ''
+
+class NullOPTIONS(OPTIONS):
+ """`OPTIONS` handler for NullResource objects
+ """
+
+ def Allow(self):
+ allowed = []
+ # TODO: This could be cleaned up by providing special target
+ # interfaces for HTTP methods. This way we can even list verbs that
+ # are not in the lists above.
+ for m in _null_methods:
+ view = zapi.queryMultiAdapter((self.context, self.request), name=m)
+ if view is not None:
+ allowed.append(m)
+ return allowed
Index: src/zope/app/http/configure.zcml
===================================================================
--- src/zope/app/http/configure.zcml (revision 81891)
+++ src/zope/app/http/configure.zcml (working copy)
@@ -50,6 +50,15 @@
/>
+
+