| 269 | ) |
| 270 | |
| 271 | def match(self, req): |
| 272 | # NOTE: webob.url_unquote doesn't work correctly under Python 3 when paths contain non-ascii |
| 273 | # characters. That method supposed to handle Python 2 and Python 3 compatibility, but it |
| 274 | # doesn't work correctly under Python 3. |
| 275 | try: |
| 276 | path = urllib.parse.unquote(req.path) |
| 277 | except Exception as e: |
| 278 | # This exception being thrown indicates that the URL / path contains bad or incorrectly |
| 279 | # URL escaped characters. Instead of returning this stack track + 500 error to the |
| 280 | # user we return a friendly and more correct exception |
| 281 | # NOTE: We should not access or log req.path here since it's a property which results |
| 282 | # in exception and if we try to log it, it will fail. |
| 283 | try: |
| 284 | path = req.environ["PATH_INFO"] |
| 285 | except Exception: |
| 286 | path = "unknown" |
| 287 | |
| 288 | LOG.error('Failed to parse request URL / path "%s": %s' % (path, str(e))) |
| 289 | |
| 290 | abort( |
| 291 | 400, |
| 292 | 'Failed to parse request path "%s". URL likely contains invalid or incorrectly ' |
| 293 | "URL encoded values." % (path), |
| 294 | ) |
| 295 | return |
| 296 | |
| 297 | LOG.debug("Match path: %s", path) |
| 298 | |
| 299 | if len(path) > 1 and path.endswith("/"): |
| 300 | path = path[:-1] |
| 301 | |
| 302 | match = self.routes.match(path, req.environ) |
| 303 | |
| 304 | if match is None: |
| 305 | raise NotFoundException('No route matches "%s" path' % req.path) |
| 306 | |
| 307 | # To account for situation when match may return multiple values |
| 308 | try: |
| 309 | path_vars = match[0] |
| 310 | except KeyError: |
| 311 | path_vars = match |
| 312 | |
| 313 | path_vars = dict(path_vars) |
| 314 | |
| 315 | path = path_vars.pop("_api_path") |
| 316 | method = path_vars.pop("_api_method") |
| 317 | endpoint = self.spec["paths"][path][method] |
| 318 | |
| 319 | return endpoint, path_vars |
| 320 | |
| 321 | def __call__(self, req): |
| 322 | """ |