[Zope3-checkins] SVN: Zope3/trunk/ Implemented HTTP 405 Method Not
Allowed handling in HTTPPublication.
Albertas Agejevas
alga at pov.lt
Mon Apr 18 14:36:19 EDT 2005
Log message for revision 30025:
Implemented HTTP 405 Method Not Allowed handling in HTTPPublication.
This does not work for DELETE and PUT methods, which have views registered for
"*" and try to adapt context to IWriteFile.
Changed:
U Zope3/trunk/doc/CHANGES.txt
U Zope3/trunk/src/zope/app/http/exception/configure.zcml
A Zope3/trunk/src/zope/app/http/exception/methodnotallowed.py
A Zope3/trunk/src/zope/app/http/exception/tests/test_methodnotallowed.py
U Zope3/trunk/src/zope/app/publication/ftests.py
U Zope3/trunk/src/zope/app/publication/http.py
A Zope3/trunk/src/zope/app/publication/methodnotallowed.txt
-=-
Modified: Zope3/trunk/doc/CHANGES.txt
===================================================================
--- Zope3/trunk/doc/CHANGES.txt 2005-04-18 13:48:48 UTC (rev 30024)
+++ Zope3/trunk/doc/CHANGES.txt 2005-04-18 18:36:18 UTC (rev 30025)
@@ -10,6 +10,10 @@
New features
+ - Implemented proper HTTP 405 Method Not Allowed handling in the
+ HTTP publication if a requested method does not have a corresponding
+ view.
+
- Implemented a generic user preferences system.
* User preferences are combined in groups that are described by
Modified: Zope3/trunk/src/zope/app/http/exception/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/http/exception/configure.zcml 2005-04-18 13:48:48 UTC (rev 30024)
+++ Zope3/trunk/src/zope/app/http/exception/configure.zcml 2005-04-18 18:36:18 UTC (rev 30025)
@@ -28,4 +28,18 @@
name="index.html"
/>
+<view
+ for="zope.app.publication.http.IMethodNotAllowed"
+ factory="zope.app.http.exception.methodnotallowed.MethodNotAllowedView"
+ name="index.html"
+ type="zope.publisher.interfaces.http.IHTTPRequest"
+ permission="zope.Public"
+ />
+
+<defaultView
+ for="zope.app.publication.http.IMethodNotAllowed"
+ type="zope.publisher.interfaces.http.IHTTPRequest"
+ name="index.html"
+ />
+
</configure>
Added: Zope3/trunk/src/zope/app/http/exception/methodnotallowed.py
===================================================================
--- Zope3/trunk/src/zope/app/http/exception/methodnotallowed.py 2005-04-18 13:48:48 UTC (rev 30024)
+++ Zope3/trunk/src/zope/app/http/exception/methodnotallowed.py 2005-04-18 18:36:18 UTC (rev 30025)
@@ -0,0 +1,40 @@
+##############################################################################
+# Copyright (c) 2003 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.
+##############################################################################
+"""HTTP 405: Method Not Allowed view
+
+$Id$
+"""
+from zope.interface import Interface
+from zope.app import zapi
+from zope.app.publication.http import IMethodNotAllowed
+
+
+class MethodNotAllowedView(object):
+ """A view for MethodNotAllowed that renders a HTTP 405 response."""
+
+ __used_for__ = IMethodNotAllowed
+
+ def __init__(self, error, request):
+ self.error = error
+ self.request = request
+ self.allow = [
+ name for name, adapter
+ in zapi.getAdapters((error.object, error.request), Interface)
+ if hasattr(adapter, name)]
+ self.allow.sort()
+
+ def __call__(self):
+ self.request.response.setHeader('Allow', ', '.join(self.allow))
+ self.request.response.setStatus(405)
+ return 'Method Not Allowed'
+
+
Property changes on: Zope3/trunk/src/zope/app/http/exception/methodnotallowed.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: Zope3/trunk/src/zope/app/http/exception/tests/test_methodnotallowed.py
===================================================================
--- Zope3/trunk/src/zope/app/http/exception/tests/test_methodnotallowed.py 2005-04-18 13:48:48 UTC (rev 30024)
+++ Zope3/trunk/src/zope/app/http/exception/tests/test_methodnotallowed.py 2005-04-18 18:36:18 UTC (rev 30025)
@@ -0,0 +1,86 @@
+##############################################################################
+#
+# Copyright (c) 2003 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.
+#
+##############################################################################
+"""Tests for HTTP error views
+
+$Id$
+"""
+from unittest import TestCase, TestSuite, main, makeSuite
+from StringIO import StringIO
+
+from zope.interface import Interface, implements
+from zope.publisher.http import HTTPRequest
+from zope.publisher.interfaces.http import IHTTPRequest
+
+from zope.app.testing import ztapi
+from zope.app.testing.placelesssetup import PlacelessSetup
+
+
+class I(Interface):
+ pass
+
+
+class C(object):
+ implements(I)
+
+
+class GetView(object):
+ def __init__(self, context, request):
+ pass
+ def GET(self):
+ pass
+
+
+class DeleteView(object):
+ def __init__(self, context, request):
+ pass
+ def DELETE(self):
+ pass
+
+
+class TestMethodNotAllowedView(PlacelessSetup, TestCase):
+
+ def setUp(self):
+ from zope.publisher.interfaces.http import IHTTPRequest
+ PlacelessSetup.setUp(self)
+ ztapi.provideView(I, IHTTPRequest, Interface, 'GET', GetView)
+ ztapi.provideView(I, IHTTPRequest, Interface, 'DELETE', DeleteView)
+ ztapi.provideView(I, IHTTPRequest, Interface, 'irrelevant', GetView)
+ ztapi.provideView(I, IHTTPRequest, Interface, 'also_irr.', DeleteView)
+
+ def test(self):
+ from zope.app.publication.http import MethodNotAllowed
+ from zope.app.http.exception.methodnotallowed \
+ import MethodNotAllowedView
+ from zope.publisher.http import HTTPRequest
+
+ context = C()
+ request = HTTPRequest(StringIO('PUT /bla/bla HTTP/1.1\n\n'),
+ StringIO(), {})
+ error = MethodNotAllowed(context, request)
+ view = MethodNotAllowedView(error, request)
+
+ result = view()
+
+ self.assertEqual(request.response.getStatus(), 405)
+ self.assertEqual(request.response.getHeader('Allow'), 'DELETE, GET')
+ self.assertEqual(result, 'Method Not Allowed')
+
+
+def test_suite():
+ return TestSuite((
+ makeSuite(TestMethodNotAllowedView),
+ ))
+
+if __name__=='__main__':
+ main(defaultTest='test_suite')
Property changes on: Zope3/trunk/src/zope/app/http/exception/tests/test_methodnotallowed.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Modified: Zope3/trunk/src/zope/app/publication/ftests.py
===================================================================
--- Zope3/trunk/src/zope/app/publication/ftests.py 2005-04-18 13:48:48 UTC (rev 30024)
+++ Zope3/trunk/src/zope/app/publication/ftests.py 2005-04-18 18:36:18 UTC (rev 30025)
@@ -21,6 +21,7 @@
def test_suite():
return unittest.TestSuite((
functional.FunctionalDocFileSuite('notfound.txt'),
+ functional.FunctionalDocFileSuite('methodnotallowed.txt'),
))
if __name__ == '__main__':
Modified: Zope3/trunk/src/zope/app/publication/http.py
===================================================================
--- Zope3/trunk/src/zope/app/publication/http.py 2005-04-18 13:48:48 UTC (rev 30024)
+++ Zope3/trunk/src/zope/app/publication/http.py 2005-04-18 18:36:18 UTC (rev 30025)
@@ -19,9 +19,33 @@
from zope.publisher.publish import mapply
from zope.app import zapi
+from zope.interface import Interface, implements, Attribute
+from zope.interface.common.interfaces import IException
from zope.app.http.interfaces import IHTTPException
from zope.app.publication.zopepublication import ZopePublication
+
+class IMethodNotAllowed(IException):
+ """An exception that signals the 405 Method Not Allowed HTTP error"""
+
+ object = Attribute("""The object on which the error occured""")
+
+ request = Attribute("""The request in which the error occured""")
+
+
+class MethodNotAllowed(Exception):
+ """An exception that signals the 405 Method Not Allowed HTTP error"""
+
+ implements(IMethodNotAllowed)
+
+ def __init__(self, object, request):
+ self.object = object
+ self.request = request
+
+ def __str__(self):
+ return "%r, %r" % (object, request)
+
+
class BaseHTTPPublication(ZopePublication):
"""Base for HTTP-based protocol publications"""
@@ -32,12 +56,16 @@
txn.setExtendedInfo('request_info', request_info)
return txn
+
class HTTPPublication(BaseHTTPPublication):
"""HTTP-specific publication"""
def callObject(self, request, ob):
# Exception handling, dont try to call request.method
+ orig = ob
if not IHTTPException.providedBy(ob):
- ob = zapi.getMultiAdapter((ob, request), name=request.method)
- ob = getattr(ob, request.method)
+ ob = zapi.queryMultiAdapter((ob, request), name=request.method)
+ ob = getattr(ob, request.method, None)
+ if ob is None:
+ raise MethodNotAllowed(orig, request)
return mapply(ob, request.getPositionalArguments(), request)
Added: Zope3/trunk/src/zope/app/publication/methodnotallowed.txt
===================================================================
--- Zope3/trunk/src/zope/app/publication/methodnotallowed.txt 2005-04-18 13:48:48 UTC (rev 30024)
+++ Zope3/trunk/src/zope/app/publication/methodnotallowed.txt 2005-04-18 18:36:18 UTC (rev 30025)
@@ -0,0 +1,31 @@
+Method Not Allowed errors
+=========================
+
+If we get a request with a method that does not have a corresponding
+view, HTTP 405 Method Not Allowed response is returned:
+
+ >>> print http(r"""
+ ... FROG / HTTP/1.1
+ ... """)
+ HTTP/1.1 405 Method Not Allowed
+ Allow: DELETE, MKCOL, OPTIONS, PROPFIND, PROPPATCH, PUT
+ Content-Length: 18
+ <BLANKLINE>
+ Method Not Allowed
+
+The requests below should return 405, but instead crash with a TypeError,
+when the view tries to adapt context to IWriteFile.
+
+# >>> print http(r"""
+# ... DELETE / HTTP/1.1
+# ... Authorization: Basic mgr:mgrpw
+# ... """, handle_errors=False)
+# HTTP/1.1 405 Method Not Allowed
+# ...
+#
+# >>> print http(r"""
+# ... PUT / HTTP/1.1
+# ... Authorization: Basic mgr:mgrpw
+# ... """, handle_errors=False)
+# HTTP/1.1 405 Method Not Allowed
+# ...
Property changes on: Zope3/trunk/src/zope/app/publication/methodnotallowed.txt
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
More information about the Zope3-Checkins
mailing list