From 4355083f21aec8de8ae99f290a864d749deb3b44 Mon Sep 17 00:00:00 2001 From: Martin Ringehahn Date: Wed, 13 Jul 2016 17:07:30 -0400 Subject: [PATCH] Prevents crash when a route resolves to a 404 (#129) multiple issues: * resolve() might throw, handle that case * unhandled exception in `process_request` leads to last successful `request_model` remain in `DataCollector` and being used to create a response model for the current failed request, leading to a constraint violation thrown by the db (creating another response for the previously succesful request) resolution * handle 404 by saving NULL/None as view name * clean out `DataCollector` state when starting a request, before doing anything. Might help #26 --- silk/middleware.py | 25 +++++++++++++------------ silk/model_factory.py | 24 +++++++++++++++++------- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/silk/middleware.py b/silk/middleware.py index d3bcf180..17987ce5 100644 --- a/silk/middleware.py +++ b/silk/middleware.py @@ -85,18 +85,19 @@ def _apply_dynamic_mappings(self): @silk_meta_profiler() def process_request(self, request): - request_model = None - if _should_intercept(request): - Logger.debug('process_request') - request.silk_is_intercepted = True - self._apply_dynamic_mappings() - if not hasattr(SQLCompiler, '_execute_sql'): - SQLCompiler._execute_sql = SQLCompiler.execute_sql - SQLCompiler.execute_sql = execute_sql - request_model = RequestModelFactory(request).construct_request_model() - DataCollector().configure(request_model) - else: - DataCollector().clear() + DataCollector().clear() + + if not _should_intercept(request): + return + + Logger.debug('process_request') + request.silk_is_intercepted = True + self._apply_dynamic_mappings() + if not hasattr(SQLCompiler, '_execute_sql'): + SQLCompiler._execute_sql = SQLCompiler.execute_sql + SQLCompiler.execute_sql = execute_sql + request_model = RequestModelFactory(request).construct_request_model() + DataCollector().configure(request_model) @transaction.atomic() def _process_response(self, request, response): diff --git a/silk/model_factory.py b/silk/model_factory.py index c73cb8f7..27c7d885 100644 --- a/silk/model_factory.py +++ b/silk/model_factory.py @@ -5,7 +5,7 @@ import base64 from uuid import UUID -from django.core.urlresolvers import resolve +from django.core.urlresolvers import resolve, Resolver404 from silk import models from silk.collector import DataCollector @@ -155,20 +155,30 @@ def query_params(self): encoded_query_params = json.dumps(query_params_dict) return encoded_query_params - def construct_request_model(self): - body, raw_body = self.body() - query_params = self.query_params() - path = self.request.path - resolved = resolve(path) + def view_name(self): + try: + resolved = resolve(self.request.path) + except Resolver404: + return None + try: # view_name is set in Django >= 1.8 - view_name = resolved.view_name + return resolved.view_name except AttributeError: # support for Django 1.6 and 1.7 in which no view_name is set view_name = resolved.url_name namespace = resolved.namespace if namespace: view_name = namespace + ':' + view_name + + return view_name + + def construct_request_model(self): + body, raw_body = self.body() + query_params = self.query_params() + path = self.request.path + view_name = self.view_name() + request_model = models.Request.objects.create( path=path, encoded_headers=self.encoded_headers(),