@@ -20,9 +20,6 @@ def __init__(self, get_response):
2020 tracemalloc .start () # Start tracing memory allocation
2121
2222 def __call__ (self , request ):
23- # Get the list of excluded paths from settings
24- excluded_paths = settings .DJANGO_SONAR .get ('excludes' , [])
25-
2623 # Check if the request path is excluded
2724 if self ._should_exclude (request .path ):
2825 return self .get_response (request )
@@ -47,7 +44,7 @@ def __call__(self, request):
4744
4845 # Capture GET/POST data
4946 get_payload = request .GET .dict ()
50- post_payload = self .get_post_payload (request )
47+ post_payload = self .get_body_payload (request )
5148
5249 # Process the request
5350 response = self .get_response (request )
@@ -152,9 +149,65 @@ def get_client_ip(self, request):
152149 def is_ajax (self , request ):
153150 return request .headers .get ('X-Requested-With' ) == 'XMLHttpRequest'
154151
155- def get_post_payload (self , request ):
156- post_data = request .POST .copy ()
157- return post_data
152+ def get_body_payload (self , request ):
153+ """Get request body data for all HTTP methods (POST, PUT, PATCH, etc.)"""
154+ if request .method == 'GET' :
155+ return {}
156+
157+ # For POST requests, use the standard request.POST
158+ if request .method == 'POST' :
159+ return request .POST .copy ()
160+
161+ # For PUT, PATCH, and other methods, parse the request body
162+ try :
163+ content_type = request .content_type .lower ()
164+
165+ # Handle JSON content
166+ if 'application/json' in content_type :
167+ if hasattr (request , 'body' ) and request .body :
168+ return json .loads (request .body .decode ('utf-8' ))
169+ return {}
170+
171+ # Handle form-encoded content
172+ elif 'application/x-www-form-urlencoded' in content_type :
173+ if hasattr (request , 'body' ) and request .body :
174+ parsed_data = parse_qs (request .body .decode ('utf-8' ))
175+ # Convert lists to single values for consistency with request.POST
176+ return {k : v [0 ] if len (v ) == 1 else v for k , v in parsed_data .items ()}
177+ return {}
178+
179+ # Handle multipart form data (files)
180+ elif 'multipart/form-data' in content_type :
181+ # For multipart, try to get data from request.FILES and any parsed data
182+ data = {}
183+ if hasattr (request , 'FILES' ) and request .FILES :
184+ data ['_files' ] = list (request .FILES .keys ())
185+ # Note: Django doesn't populate request.POST for PUT/PATCH multipart,
186+ # so we'd need custom parsing for complex multipart PUT/PATCH requests
187+ return data
188+
189+ # For other content types, store raw body (truncated for safety)
190+ else :
191+ if hasattr (request , 'body' ) and request .body :
192+ body_str = request .body .decode ('utf-8' , errors = 'ignore' )
193+ # Truncate large bodies to avoid storage issues
194+ if len (body_str ) > 10000 :
195+ body_str = body_str [:10000 ] + '... (truncated)'
196+ return {'_raw_body' : body_str , '_content_type' : content_type }
197+ return {}
198+
199+ except (json .JSONDecodeError , UnicodeDecodeError , Exception ) as e :
200+ # If parsing fails, store error info and raw body (truncated)
201+ try :
202+ body_str = request .body .decode ('utf-8' , errors = 'ignore' )[:1000 ]
203+ except :
204+ body_str = '<unable to decode>'
205+
206+ return {
207+ '_parse_error' : str (e ),
208+ '_raw_body' : body_str ,
209+ '_content_type' : getattr (request , 'content_type' , 'unknown' )
210+ }
158211
159212 def process_exception (self , request , exception ):
160213 """Process the exception and keep it in local storage."""
0 commit comments