jakartaee / mail-api

Jakarta Mail Specification project
https://jakartaee.github.io/mail-api
Other
247 stars 101 forks source link

Unfolding Outlook generated headers sometimes gives invalid results #259

Closed glassfishrobot closed 7 years ago

glassfishrobot commented 7 years ago

Outlook/Exchange can generate Mime messages with headers like this:

Content-Type: application/pdf; name= "This-is-a-very-long-filename-to-prove-Outlook-has-real-erroneous-folding-strategies.pdf" Content-Disposition: attachment; filename= "This-is-a-very-long-filename-to-prove-Outlook-has-real-erroneous-folding-strategies.pdf"; size=1260276; creation-date="Tue, 16 May 2017 12:52:32 GMT"; modification-date="Tue, 16 May 2017 12:45:50 GMT"

The folding is done within the parameters immediately after the "name=" and "filename=". This only happens with long filenames. Unfolding this lines with the current unfolding code of javax.mail.internet.MimeUtility results in a line with at least a space after the '='. This space violates the https://www.ietf.org/rfc/rfc2045.txt specification clause 5.1:

    parameter := attribute "=" value

And this violation can cause problems, e.g. when parsing the line using Springs org.springframework.util.MimeType.MimeType.valueOf method.

For me it's clear the folding done by Outlook is strange and seems invalid compared to clause 2.2.3 in https://www.ietf.org/rfc/rfc5322.txt . But because Outlook/Exchange is a big player I guess it will be a good idea to take into account their folding strategy.

A simple solution can be to change in method unfold:

if (i >= slen || (c = s.charAt(i)) == ' ' || c == '\t') {
   if (sb == null)
      sb = new StringBuffer(s.length());
   sb.append(s.substring(0, start));
   s = s.substring(i);
} else {

to:

if (i >= slen || (c = s.charAt(i)) == ' ' || c == '\t') {
   if (sb == null)
      sb = new StringBuffer(s.length());
   if (s.charAt(i - 2) != '=')
      sb.append(s.substring(0, start));
   s = s.substring(i);
} else {

For now I have the following workaround for content-type, but that's not ideal:

import javax.mail.internet.ContentType;
import javax.mail.internet.ParameterList;
import org.apache.commons.lang3.StringUtils;
....
    private String cleanContentType(String headerValue) {
        try {
            ContentType contentType = new ContentType(headerValue);
            ParameterList parameterList = contentType.getParameterList();
            ParameterList cleanParameterList = new ParameterList();
            Enumeration<?> names = parameterList.getNames();
            while (names.hasMoreElements()) {
                String parameterName = (String) names.nextElement();
                cleanParameterList.set(parameterName.trim(), StringUtils.trimToEmpty(contentType.getParameter(parameterName)));
            }
            contentType.setParameterList(cleanParameterList);
            return contentType.toString();
        } catch (ParseException e) {
            log.warn("Unparsable content-Type; fallback to text/plain", e);
            return MessageConstants.CONTENT_TYPE_TEXT_PLAIN;
        }
    }
glassfishrobot commented 6 years ago
glassfishrobot commented 7 years ago

@bshannon Commented Actually, whitespace is allowed. RFC 2045 references RFC 822, which says:

     3.1.4.  STRUCTURED FIELD BODIES

        To aid in the creation and reading of structured  fields,  the
        free  insertion   of linear-white-space (which permits folding
        by inclusion of CRLFs)  is  allowed  between  lexical  tokens.
        ...

JavaMail ignores whitespace when parsing these parameter lists. Perhaps the Spring MimeType class is not ignoring whitespace like it should? This doesn't look like a bug in JavaMail, but let me know if I missed something.