diff --git a/netbox/extras/events.py b/netbox/extras/events.py index e2912758a..6f4854ff3 100644 --- a/netbox/extras/events.py +++ b/netbox/extras/events.py @@ -119,7 +119,9 @@ def process_event_rules(event_rules, object_type, event_type, data, username=Non if snapshots: params["snapshots"] = snapshots if request: - params["request"] = copy_safe_request(request) + # Exclude FILES - webhooks don't need uploaded files, + # which can cause pickle errors with Pillow. + params["request"] = copy_safe_request(request, include_files=False) # Enqueue the task rq_queue.enqueue( diff --git a/netbox/utilities/request.py b/netbox/utilities/request.py index eadbe0f5c..92b879139 100644 --- a/netbox/utilities/request.py +++ b/netbox/utilities/request.py @@ -35,27 +35,34 @@ class NetBoxFakeRequest: # Utility functions # -def copy_safe_request(request): +def copy_safe_request(request, include_files=True): """ Copy selected attributes from a request object into a new fake request object. This is needed in places where thread safe pickling of the useful request data is needed. + + Args: + request: The original request object + include_files: Whether to include request.FILES. """ meta = { k: request.META[k] for k in HTTP_REQUEST_META_SAFE_COPY if k in request.META and isinstance(request.META[k], str) } - return NetBoxFakeRequest({ + data = { 'META': meta, 'COOKIES': request.COOKIES, 'POST': request.POST, 'GET': request.GET, - 'FILES': request.FILES, 'user': request.user, 'method': request.method, 'path': request.path, 'id': getattr(request, 'id', None), # UUID assigned by middleware - }) + } + if include_files: + data['FILES'] = request.FILES + + return NetBoxFakeRequest(data) def get_client_ip(request, additional_headers=()):