RFC 2046[1] is somewhat ambiguous on whether or not it's valid to omit the
preceding CRLF for the first boundary. The prose on page 19 suggests
that it is not:
> The boundary delimiter MUST occur at the beginning of a line, i.e.,
> following a CRLF, and the initial CRLF is considered to be attached
> to the boundary delimiter line rather than part of the preceding
> part. The boundary may be followed by zero or more characters of
> linear whitespace. It is then terminated by either another CRLF and
> the header fields for the next part, or by two CRLFs, in which case
> there are no header fields for the next part. If no Content-Type
> field is present it is assumed to be "message/rfc822" in a
> "multipart/digest" and "text/plain" otherwise.
>
> NOTE: The CRLF preceding the boundary delimiter line is conceptually
> attached to the boundary so that it is possible to have a part that
> does not end with a CRLF (line break). Body parts that must be
> considered to end with line breaks, therefore, must have two CRLFs
> preceding the boundary delimiter line, the first of which is part of
> the preceding body part, and the second of which is part of the
> encapsulation boundary.
But the BNF on page 22 suggests that it is, as long as there is no
preamble:
> dash-boundary := "--" boundary
> ; boundary taken from the value of
> ; boundary parameter of the
> ; Content-Type field.
>
> multipart-body := [preamble CRLF]
> dash-boundary transport-padding CRLF
> body-part *encapsulation
> close-delimiter transport-padding
> [CRLF epilogue]
Dendrite currently generates multipart responses without a preceding CRLF
for the first boundary[2], which were rejected by the previous ruma
parsing logic.
[1]: https://datatracker.ietf.org/doc/html/rfc2046
[2]: https://github.com/matrix-org/dendrite/issues/3414