# HG changeset patch
# User Elodie Thieblin <ethieblin@logilab.fr>
# Date 1611659491 -3600
# Tue Jan 26 12:11:31 2021 +0100
# Node ID caa6a76fcc94a369b43055a4a7e40aa6a48e4f82
# Parent 28bdd6431c6924b143cf8c1ee3e059f19fac513c
fix(urlpublisher): raise a 404 when a URL rewrite with rql has no rset
fix #199
# User Elodie Thieblin <ethieblin@logilab.fr>
# Date 1611659491 -3600
# Tue Jan 26 12:11:31 2021 +0100
# Node ID caa6a76fcc94a369b43055a4a7e40aa6a48e4f82
# Parent 28bdd6431c6924b143cf8c1ee3e059f19fac513c
fix(urlpublisher): raise a 404 when a URL rewrite with rql has no rset
fix #199
@@ -338,17 +338,21 @@
1 tstart = process_time() 2 commited = False 3 try: 4 # standard processing of the request 5 try: 6 + # The process function update the req according rewrites rules. 7 + # It stores in req._rql_rewritten if the rql comes from the endUser. 8 ctrlid, rset = self.url_resolver.process(req, path) 9 try: 10 controller = self.vreg['controllers'].select(ctrlid, req, 11 appli=self) 12 except NoSelectableObject: 13 raise Unauthorized(req._('not authorized')) 14 req.update_search_state() 15 + # In case of rewritten rql, controller.publish directly raises 16 + # notFound if the rset is empty. 17 result = controller.publish(rset=rset) 18 except Redirect as ex: 19 # Redirect may be raised by edit controller when everything went 20 # fine, so attempt to commit 21 result = self.redirect_handler(req, ex)
@@ -756,8 +756,22 @@
22 with self.admin_access.web_request() as req: 23 # expect a rset with None in [0][0] 24 req.form['rql'] = 'rql:Any OV1, X WHERE X custom_workflow OV1?' 25 self.app_handle_request(req) 26 27 + def test_notfound_raised_on_empty_underlying_rset(self): 28 + """tests URLs that are rewritten with an underlying rqlquery. 29 + If the rql query is empty, a NotFound error should be raised.""" 30 + 31 + with self.new_access('anon').web_request('schema/CWUser') as req: 32 + self.app_handle_request(req) 33 + self.assertEqual(req.status_out, 200) 34 + 35 + # There is an underlying rql to fetch the schema of cwetype. 36 + # As there is no entity «pouet», it should raise NotFound. 37 + with self.new_access('anon').web_request('schema/pouet') as req: 38 + self.app_handle_request(req) 39 + self.assertEqual(req.status_out, 404) 40 + 41 42 if __name__ == '__main__': 43 unittest_main()
@@ -25,11 +25,11 @@
44 AuthenticationError, UndoTransactionException, 45 Forbidden, rdf) 46 from cubicweb.utils import json_dumps 47 from cubicweb.predicates import (authenticated_user, anonymous_user, 48 match_form_params) 49 -from cubicweb.web import Redirect 50 +from cubicweb.web import Redirect, NotFound 51 from cubicweb.web.controller import Controller 52 from cubicweb.web.views import vid_from_rset 53 from cubicweb._exceptions import NotAnEntity 54 55
@@ -82,12 +82,17 @@
56 """ 57 __regid__ = 'view' 58 template = 'main-template' 59 60 def publish(self, rset=None): 61 - """publish a request, returning an encoded string""" 62 + """publish a request, returning an encoded string. 63 + 64 + :raise NotFound: if the rql has been rewritten (rewrite rules) and the 65 + resulting rset is empty""" 66 view, rset = self._select_view_and_rset(rset) 67 + if not rset and getattr(self._cw, '_rql_rewritten', False): 68 + raise NotFound(self._cw._url) 69 view.set_http_cache_headers() 70 if self._cw.is_client_cache_valid(): 71 return b'' 72 template = self.appli.main_template_id(self._cw) 73 return self._cw.vreg['views'].main_template(self._cw, template,
@@ -128,11 +128,12 @@
74 elif language_mode in ('http-negotiation', 'url-prefix'): 75 # negotiated language 76 lang = req.negotiated_language() 77 if lang: 78 req.set_language(lang) 79 - if req.form.get('rql'): 80 + origin_rql = req.form.get('rql') 81 + if origin_rql: 82 if parts[0] in self.vreg['controllers']: 83 return parts[0], None 84 return 'view', None 85 for evaluator in self.evaluators: 86 try:
@@ -140,10 +141,17 @@
87 break 88 except PathDontMatch: 89 continue 90 else: 91 raise NotFound(path) 92 + 93 + # Store if the final rql (changed by evaluator.evaluate_path) comes from 94 + # the end user (?rql=Any X Where is CWUser) or comes from a rewrite rule 95 + # such as SimpleReqRewriter. 96 + new_rql = req.form.get("rql") 97 + req._rql_rewritten = origin_rql != new_rql 98 + 99 if pmid is None: 100 pmid = self.default_method 101 return pmid, rset 102 103