about summary refs log tree commit diff
path: root/third_party/lisp/mime4cl/mime.lisp
diff options
context:
space:
mode:
authorsterni <sternenseemann@systemli.org>2024-12-02T17·46+0100
committerclbot <clbot@tvl.fyi>2024-12-02T18·09+0000
commit3398c2ab7fbbc4d22a2c4540518ffe293ba9dc1c (patch)
tree4784cdba10d759ae96326c293d40d869bffe8fad /third_party/lisp/mime4cl/mime.lisp
parentdb2fa5b3c8fada85de8bff6be7ef1312d7b45ef1 (diff)
fix(3p/lisp/mime4cl): don't store redundant headers in MIME-MESSAGE r/8975
MIME-MESSAGE has a HEADERS slot which is an alist of all headers. Some
of those headers will be parsed again and stored in MIME-PART (or a
subclass of it). Having the header content stored in the HEADERS alist
and in MIME-PART causes problems:

- Requires extra knowledge about how messages are parsed when rendering
  messages.
- Makes MIME= depend on the specific whitespace and quoting in those
  headers which isn't preserved by how mime4cl parses e.g. Content-Type.
- Gives users two ways that slightly diverge to access the same thing.

To avoid this, we remove these headers after the MIME-PARTs contained in
MIME-MESSAGE have been initialized (since they reuse the HEADERS slot).

Change-Id: I5b221f88bbac47dd81db369e3c1d5881a5a50e5e
Reviewed-on: https://cl.tvl.fyi/c/depot/+/12858
Tested-by: BuildkiteCI
Reviewed-by: sterni <sternenseemann@systemli.org>
Autosubmit: sterni <sternenseemann@systemli.org>
Diffstat (limited to 'third_party/lisp/mime4cl/mime.lisp')
-rw-r--r--third_party/lisp/mime4cl/mime.lisp31
1 files changed, 24 insertions, 7 deletions
diff --git a/third_party/lisp/mime4cl/mime.lisp b/third_party/lisp/mime4cl/mime.lisp
index ead6108fc668..eeddea970603 100644
--- a/third_party/lisp/mime4cl/mime.lisp
+++ b/third_party/lisp/mime4cl/mime.lisp
@@ -67,6 +67,15 @@
   (:documentation
    "Abstract base class for all types of MIME parts."))
 
+(defparameter +redundant-headers+ '(:mime-version
+                                    :content-type
+                                    :content-id
+                                    :content-description
+                                    :content-disposition
+                                    :content-transfer-encoding)
+  "Headers that don't need to be preserved in the  HEADERS slot of MIME-MESSAGE
+because they are stored in dedicated slots in MIME-PART.")
+
 (defclass mime-bodily-part (mime-part)
   ((body
     :initarg :body
@@ -131,11 +140,20 @@
   ;; Allow a list of mime parts to be specified as body of a
   ;; mime-message.  In that case we implicitly create a mime-multipart
   ;; and assign to the body slot.
-  (with-slots (real-message) part
+  (with-slots (real-message headers) part
     (when (and (slot-boundp part 'real-message)
                (consp real-message))
       (setf real-message
-            (make-instance 'mime-multipart :parts real-message)))))
+            (make-instance 'mime-multipart :parts real-message)))
+    ;; Remove headers that are parsed and stored in MIME-PART (i.e.
+    ;; REAL-MESSAGE). This prevents redundant storage and rendering of these
+    ;; headers as well as MIME= depending on the specific rendering of these
+    ;; headers which may diverge between mime4cl and other software. We do this
+    ;; here since construction of REAL-MESSAGE may access the HEADERS slot.
+    (setf headers
+          (delete-if (lambda (h)
+                       (member (car h) +redundant-headers+ :test #'string-equal))
+                     headers))))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
@@ -471,15 +489,14 @@ separated by PART-BOUNDARY."
   (encode-mime-body part stream))
 
 (defmethod encode-mime-part ((part mime-message) stream)
-  ;; tricky: we have to mix the MIME headers with the message headers
+  ;; tricky: we have to mix the MIME headers with the message headers, i.e.
+  ;; ENCODE-MIME-PART will output additional headers
   (dolist (h (mime-message-headers part))
     (unless (stringp (car h))
       (setf (car h)
             (string-capitalize (car h))))
-    (unless (or (string-starts-with "content-" (car h) #'string-equal)
-                (string-equal "mime-version" (car h)))
-      (format stream "~A: ~A~%"
-              (car h) (cdr h))))
+    (format stream "~A: ~A~%"
+            (car h) (cdr h)))
   (encode-mime-part (mime-body part) stream))
 
 (defmethod encode-mime-part ((part mime-multipart) stream)