From ffcf9a0e31b08e3b705f7668f80d350a5483615c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Bisinger?= Date: Thu, 23 Apr 2015 22:10:41 +0200 Subject: [PATCH] Implement the correct HTTP status codes Use the correct HTTP status codes for Accept or Content-Type headers checks still mantaining the multi-protocol handling. Change-Id: I3992a90625e6114ee18e26e4f3e03c7c11efebff --- wsme/protocol.py | 7 +++---- wsme/rest/protocol.py | 18 +----------------- wsme/root.py | 31 ++++++++++++++++++++++++------- wsme/tests/test_api.py | 3 ++- wsme/tests/test_root.py | 2 +- 5 files changed, 31 insertions(+), 30 deletions(-) diff --git a/wsme/protocol.py b/wsme/protocol.py index e8ee1f7..b0107ab 100644 --- a/wsme/protocol.py +++ b/wsme/protocol.py @@ -123,9 +123,6 @@ def media_type_accept(request, content_types): When request.method is POST, PUT or PATCH compare with the Content-Type header. When request.method is DELETE media type is irrelevant, so return True. - - The return value is unused, we either make it through or have an - exception. """ if request.method in ['GET', 'HEAD']: if request.accept: @@ -145,4 +142,6 @@ def media_type_accept(request, content_types): raise ClientSideError(error_message, status_code=415) else: raise ClientSideError('missing Content-Type header') - return True + elif request.method in ['DELETE']: + return True + return False diff --git a/wsme/rest/protocol.py b/wsme/rest/protocol.py index 336c6aa..5201ccf 100644 --- a/wsme/rest/protocol.py +++ b/wsme/rest/protocol.py @@ -23,7 +23,6 @@ class RestProtocol(Protocol): self.dataformats = OrderedDict() self.content_types = [] - self.dataformat_override = False for dataformat in dataformats: __import__('wsme.rest.' + dataformat) @@ -34,25 +33,10 @@ class RestProtocol(Protocol): def accept(self, request): for dataformat in self.dataformats: if request.path.endswith('.' + dataformat): - self.dataformat_override = True return True - if request.accept: - if request.accept.best_match(self.content_types): - print 'accepting' - return True - for ct in self.content_types: - print 'ct', ct - if request.headers.get('Content-Type', '').startswith(ct): - return True - return False + return media_type_accept(request, self.content_types) def iter_calls(self, request): - - # Control for proper media type handling. A 406 or 415 - # ClientSideError will be raise if there is no match. - if not self.dataformat_override: - media_type_accept(request, self.content_types) - context = CallContext(request) context.outformat = None ext = os.path.splitext(request.path.split('/')[-1])[1] diff --git a/wsme/root.py b/wsme/root.py index 482fa98..1ccfbdf 100644 --- a/wsme/root.py +++ b/wsme/root.py @@ -149,6 +149,7 @@ class WSRoot(object): request.body[:512] or request.body) or '') protocol = None + error = ClientSideError(status_code=406) path = str(request.path) assert path.startswith(self._webpath) path = path[len(self._webpath) + 1:] @@ -157,9 +158,16 @@ class WSRoot(object): else: for p in self.protocols: - if p.accept(request): - protocol = p - break + try: + if p.accept(request): + protocol = p + break + except ClientSideError as e: + error = e + # If we could not select a protocol, we raise the last exception + # that we got, or the default one. + if not protocol: + raise error return protocol def _do_call(self, protocol, context): @@ -230,20 +238,29 @@ class WSRoot(object): try: msg = None + error_status = 500 protocol = self._select_protocol(request) + except ClientSideError as e: + error_status = e.code + msg = e.faultstring + protocol = None except Exception as e: - msg = ("Error while selecting protocol: %s" % str(e)) + msg = ("Unexpected error while selecting protocol: %s" % str(e)) log.exception(msg) protocol = None + error_status = 500 if protocol is None: - if msg is None: + if not msg: msg = ("None of the following protocols can handle this " "request : %s" % ','.join(( p.name for p in self.protocols))) - res.status = 500 + res.status = error_status res.content_type = 'text/plain' - res.text = u(msg) + try: + res.text = u(msg) + except TypeError: + res.text = msg log.error(msg) return res diff --git a/wsme/tests/test_api.py b/wsme/tests/test_api.py index 6c48e1e..b99b20a 100644 --- a/wsme/tests/test_api.py +++ b/wsme/tests/test_api.py @@ -201,7 +201,8 @@ Value should be one of:")) app = webtest.TestApp(r.wsgiapp()) res = app.get('/', expect_errors=True) - assert res.status_int == 500 + print(res.status_int) + assert res.status_int == 406 print(res.body) assert res.body.find( b("None of the following protocols can handle this request")) != -1 diff --git a/wsme/tests/test_root.py b/wsme/tests/test_root.py index 9dee35d..1b32f99 100644 --- a/wsme/tests/test_root.py +++ b/wsme/tests/test_root.py @@ -39,7 +39,7 @@ class TestRoot(unittest.TestCase): assert res.status_int == 500 assert res.content_type == 'text/plain' assert (res.text == - 'Error while selecting protocol: test'), req.text + 'Unexpected error while selecting protocol: test'), req.text def test_protocol_selection_post_method(self): import wsme.rest.protocol -- 2.3.6