Bug 493544 - Don't decode the encoded text until it ends. r=smontagu

This commit is contained in:
Zane U. Ji 2012-12-22 17:54:00 +09:00
parent 20a6d96dc4
commit f3d486af9c

View File

@ -1091,6 +1091,43 @@ void CopyRawHeader(const char *aInput, uint32_t aLen,
} }
} }
nsresult DecodeQOrBase64Str(const char *aEncoded, size_t aLen, char aQOrBase64,
const char *aCharset, nsACString &aResult)
{
char *decodedText;
NS_ASSERTION(aQOrBase64 == 'Q' || aQOrBase64 == 'B', "Should be 'Q' or 'B'");
if(aQOrBase64 == 'Q')
decodedText = DecodeQ(aEncoded, aLen);
else if (aQOrBase64 == 'B') {
decodedText = PL_Base64Decode(aEncoded, aLen, nullptr);
} else {
return NS_ERROR_INVALID_ARG;
}
if (!decodedText) {
return NS_ERROR_INVALID_ARG;
}
nsresult rv;
nsCOMPtr<nsIUTF8ConverterService>
cvtUTF8(do_GetService(NS_UTF8CONVERTERSERVICE_CONTRACTID, &rv));
nsAutoCString utf8Text;
if (NS_SUCCEEDED(rv)) {
// skip ASCIIness/UTF8ness test if aCharset is 7bit non-ascii charset.
rv = cvtUTF8->ConvertStringToUTF8(nsDependentCString(decodedText),
aCharset,
IS_7BIT_NON_ASCII_CHARSET(aCharset),
true, 1, utf8Text);
}
PR_Free(decodedText);
if (NS_FAILED(rv)) {
return rv;
}
aResult.Append(utf8Text);
return NS_OK;
}
static const char especials[] = "()<>@,;:\\\"/[]?.="; static const char especials[] = "()<>@,;:\\\"/[]?.=";
// |decode_mime_part2_str| taken from comi18n.c // |decode_mime_part2_str| taken from comi18n.c
@ -1103,14 +1140,13 @@ nsresult DecodeRFC2047Str(const char *aHeader, const char *aDefaultCharset,
bool aOverrideCharset, nsACString &aResult) bool aOverrideCharset, nsACString &aResult)
{ {
const char *p, *q = nullptr, *r; const char *p, *q = nullptr, *r;
char *decodedText;
const char *begin; // tracking pointer for where we are in the input buffer const char *begin; // tracking pointer for where we are in the input buffer
int32_t isLastEncodedWord = 0; int32_t isLastEncodedWord = 0;
const char *charsetStart, *charsetEnd; const char *charsetStart, *charsetEnd;
char charset[80]; nsAutoCString prevCharset, curCharset;
nsAutoCString encodedText;
// initialize charset name to an empty string char prevEncoding = '\0', curEncoding;
charset[0] = '\0'; nsresult rv;
begin = aHeader; begin = aHeader;
@ -1155,15 +1191,9 @@ nsresult DecodeRFC2047Str(const char *aHeader, const char *aDefaultCharset,
charsetEnd = q; charsetEnd = q;
} }
// Check for too-long charset name
if (uint32_t(charsetEnd - charsetStart) >= sizeof(charset))
goto badsyntax;
memcpy(charset, charsetStart, charsetEnd - charsetStart);
charset[charsetEnd - charsetStart] = 0;
q++; q++;
if (*q != 'Q' && *q != 'q' && *q != 'B' && *q != 'b') curEncoding = nsCRT::ToUpper(*q);
if (curEncoding != 'Q' && curEncoding != 'B')
goto badsyntax; goto badsyntax;
if (q[1] != '?') if (q[1] != '?')
@ -1182,55 +1212,88 @@ nsresult DecodeRFC2047Str(const char *aHeader, const char *aDefaultCharset,
continue; continue;
} }
if(*q == 'Q' || *q == 'q') curCharset.Assign(charsetStart, charsetEnd - charsetStart);
decodedText = DecodeQ(q + 2, r - (q + 2)); // Override charset if requested. Never override labeled UTF-8.
else { // Use default charset instead of UNKNOWN-8BIT
if ((aOverrideCharset && 0 != nsCRT::strcasecmp(curCharset.get(), "UTF-8"))
|| (aDefaultCharset && 0 == nsCRT::strcasecmp(curCharset.get(), "UNKNOWN-8BIT"))
) {
curCharset = aDefaultCharset;
}
const char *R;
R = r;
if (curEncoding == 'B') {
// bug 227290. ignore an extraneous '=' at the end. // bug 227290. ignore an extraneous '=' at the end.
// (# of characters in B-encoded part has to be a multiple of 4) // (# of characters in B-encoded part has to be a multiple of 4)
int32_t n = r - (q + 2); int32_t n = r - (q + 2);
n -= (n % 4 == 1 && !PL_strncmp(r - 3, "===", 3)) ? 1 : 0; R -= (n % 4 == 1 && !PL_strncmp(r - 3, "===", 3)) ? 1 : 0;
decodedText = PL_Base64Decode(q + 2, n, nullptr); }
// Bug 493544. Don't decode the encoded text until it ends
if (R[-1] != '='
&& (prevCharset.IsEmpty()
|| (curCharset == prevCharset && curEncoding == prevEncoding))
) {
encodedText.Append(q + 2, R - (q + 2));
prevCharset = curCharset;
prevEncoding = curEncoding;
begin = r + 2;
isLastEncodedWord = 1;
continue;
} }
if (decodedText == nullptr) bool bDecoded; // If the current line has been decoded.
goto badsyntax; bDecoded = false;
if (!encodedText.IsEmpty()) {
// Override charset if requested. Never override labeled UTF-8. if (curCharset == prevCharset && curEncoding == prevEncoding) {
// Use default charset instead of UNKNOWN-8BIT encodedText.Append(q + 2, R - (q + 2));
if ((aOverrideCharset && 0 != nsCRT::strcasecmp(charset, "UTF-8")) || bDecoded = true;
(aDefaultCharset && 0 == nsCRT::strcasecmp(charset, "UNKNOWN-8BIT"))) { }
PL_strncpy(charset, aDefaultCharset, sizeof(charset) - 1); rv = DecodeQOrBase64Str(encodedText.get(), encodedText.Length(),
charset[sizeof(charset) - 1] = '\0'; prevEncoding, prevCharset.get(), aResult);
if (NS_FAILED(rv)) {
aResult.Append(encodedText);
}
encodedText.Truncate();
prevCharset.Truncate();
} }
if (!bDecoded) {
{ rv = DecodeQOrBase64Str(q + 2, R - (q + 2), curEncoding,
nsCOMPtr<nsIUTF8ConverterService> curCharset.get(), aResult);
cvtUTF8(do_GetService(NS_UTF8CONVERTERSERVICE_CONTRACTID)); if (NS_FAILED(rv)) {
nsAutoCString utf8Text; aResult.Append(encodedText);
// skip ASCIIness/UTF8ness test if aCharset is 7bit non-ascii charset.
if (cvtUTF8 &&
NS_SUCCEEDED(
cvtUTF8->ConvertStringToUTF8(nsDependentCString(decodedText),
charset,
IS_7BIT_NON_ASCII_CHARSET(charset),
true, 1, utf8Text))) {
aResult.Append(utf8Text);
} else {
aResult.Append(REPLACEMENT_CHAR);
} }
} }
PR_Free(decodedText);
begin = r + 2; begin = r + 2;
isLastEncodedWord = 1; isLastEncodedWord = 1;
continue; continue;
badsyntax: badsyntax:
if (!encodedText.IsEmpty()) {
rv = DecodeQOrBase64Str(encodedText.get(), encodedText.Length(),
prevEncoding, prevCharset.get(), aResult);
if (NS_FAILED(rv)) {
aResult.Append(encodedText);
}
encodedText.Truncate();
prevCharset.Truncate();
}
// copy the part before the encoded-word // copy the part before the encoded-word
aResult.Append(begin, p - begin); aResult.Append(begin, p - begin);
begin = p; begin = p;
isLastEncodedWord = 0; isLastEncodedWord = 0;
} }
if (!encodedText.IsEmpty()) {
rv = DecodeQOrBase64Str(encodedText.get(), encodedText.Length(),
prevEncoding, prevCharset.get(), aResult);
if (NS_FAILED(rv)) {
aResult.Append(encodedText);
}
}
// put the tail back // put the tail back
CopyRawHeader(begin, strlen(begin), aDefaultCharset, aResult); CopyRawHeader(begin, strlen(begin), aDefaultCharset, aResult);