Index: net/http/http_content_disposition.cc |
diff --git a/net/http/http_content_disposition.cc b/net/http/http_content_disposition.cc |
index 0726e93ee477b1a1ab3bf6a50b97fe49c773a664..35ace84511dbfaac659f7a2a8906e407b5cf07a8 100644 |
--- a/net/http/http_content_disposition.cc |
+++ b/net/http/http_content_disposition.cc |
@@ -95,7 +95,8 @@ bool DecodeBQEncoding(const std::string& part, |
bool DecodeWord(const std::string& encoded_word, |
const std::string& referrer_charset, |
bool* is_rfc2047, |
- std::string* output) { |
+ std::string* output, |
+ int* parse_result_flags) { |
*is_rfc2047 = false; |
output->clear(); |
if (encoded_word.empty()) |
@@ -117,6 +118,7 @@ bool DecodeWord(const std::string& encoded_word, |
} |
} |
+ *parse_result_flags |= net::HttpContentDisposition::HAS_NON_ASCII_STRINGS; |
return true; |
} |
@@ -125,7 +127,7 @@ bool DecodeWord(const std::string& encoded_word, |
// =?charset?<E>?<encoded string>?= where '<E>' is either 'B' or 'Q'. |
// We don't care about the length restriction (72 bytes) because |
// many web servers generate encoded words longer than the limit. |
- std::string tmp; |
+ std::string decoded_word; |
*is_rfc2047 = true; |
int part_index = 0; |
std::string charset; |
@@ -158,7 +160,7 @@ bool DecodeWord(const std::string& encoded_word, |
++part_index; |
break; |
case 3: |
- *is_rfc2047 = DecodeBQEncoding(part, enc_type, charset, &tmp); |
+ *is_rfc2047 = DecodeBQEncoding(part, enc_type, charset, &decoded_word); |
if (!*is_rfc2047) { |
// Last minute failure. Invalid B/Q encoding. Rather than |
// passing it through, return now. |
@@ -186,7 +188,9 @@ bool DecodeWord(const std::string& encoded_word, |
if (*is_rfc2047) { |
if (*(encoded_word.end() - 1) == '=') { |
- output->swap(tmp); |
+ output->swap(decoded_word); |
+ *parse_result_flags |= |
+ net::HttpContentDisposition::HAS_RFC2047_ENCODED_STRINGS; |
return true; |
} |
// encoded_word ending prematurelly with '?' or extra '?' |
@@ -199,9 +203,13 @@ bool DecodeWord(const std::string& encoded_word, |
// web browser. |
// What IE6/7 does: %-escaped UTF-8. |
- tmp = net::UnescapeURLComponent(encoded_word, net::UnescapeRule::SPACES); |
- if (IsStringUTF8(tmp)) { |
- output->swap(tmp); |
+ decoded_word = net::UnescapeURLComponent(encoded_word, |
+ net::UnescapeRule::SPACES); |
+ if (decoded_word != encoded_word) |
+ *parse_result_flags |= |
+ net::HttpContentDisposition::HAS_PERCENT_ENCODED_STRINGS; |
+ if (IsStringUTF8(decoded_word)) { |
+ output->swap(decoded_word); |
return true; |
// We can try either the OS default charset or 'origin charset' here, |
// As far as I can tell, IE does not support it. However, I've seen |
@@ -221,19 +229,21 @@ bool DecodeWord(const std::string& encoded_word, |
// strings. Non-ASCII strings are interpreted based on |referrer_charset|. |
bool DecodeFilenameValue(const std::string& input, |
const std::string& referrer_charset, |
- std::string* output) { |
- std::string tmp; |
+ std::string* output, |
+ int* parse_result_flags) { |
+ int current_parse_result_flags = 0; |
+ std::string decoded_value; |
+ bool is_previous_token_rfc2047 = true; |
+ |
// Tokenize with whitespace characters. |
StringTokenizer t(input, " \t\n\r"); |
t.set_options(StringTokenizer::RETURN_DELIMS); |
- bool is_previous_token_rfc2047 = true; |
while (t.GetNext()) { |
if (t.token_is_delim()) { |
// If the previous non-delimeter token is not RFC2047-encoded, |
// put in a space in its place. Otheriwse, skip over it. |
- if (!is_previous_token_rfc2047) { |
- tmp.push_back(' '); |
- } |
+ if (!is_previous_token_rfc2047) |
+ decoded_value.push_back(' '); |
continue; |
} |
// We don't support a single multibyte character split into |
@@ -243,11 +253,13 @@ bool DecodeFilenameValue(const std::string& input, |
// it, either. |
std::string decoded; |
if (!DecodeWord(t.token(), referrer_charset, &is_previous_token_rfc2047, |
- &decoded)) |
+ &decoded, ¤t_parse_result_flags)) |
return false; |
- tmp.append(decoded); |
+ decoded_value.append(decoded); |
} |
- output->swap(tmp); |
+ output->swap(decoded_value); |
+ if (parse_result_flags && !output->empty()) |
+ *parse_result_flags |= current_parse_result_flags; |
return true; |
} |
@@ -339,7 +351,8 @@ namespace net { |
HttpContentDisposition::HttpContentDisposition( |
const std::string& header, const std::string& referrer_charset) |
- : type_(INLINE) { |
+ : type_(INLINE), |
+ parse_result_flags_(INVALID) { |
Parse(header, referrer_charset); |
} |
@@ -361,10 +374,18 @@ std::string::const_iterator HttpContentDisposition::ConsumeDispositionType( |
if (!HttpUtil::IsToken(type_begin, type_end)) |
return begin; |
+ parse_result_flags_ |= HAS_DISPOSITION_TYPE; |
+ |
DCHECK(std::find(type_begin, type_end, '=') == type_end); |
- if (!LowerCaseEqualsASCII(type_begin, type_end, "inline")) |
+ if (LowerCaseEqualsASCII(type_begin, type_end, "inline")) { |
+ type_ = INLINE; |
+ } else if (LowerCaseEqualsASCII(type_begin, type_end, "attachment")) { |
+ type_ = ATTACHMENT; |
+ } else { |
+ parse_result_flags_ |= HAS_UNKNOWN_DISPOSITION_TYPE; |
type_ = ATTACHMENT; |
+ } |
return delimiter; |
} |
@@ -404,15 +425,22 @@ void HttpContentDisposition::Parse(const std::string& header, |
if (filename.empty() && LowerCaseEqualsASCII(iter.name_begin(), |
iter.name_end(), |
"filename")) { |
- DecodeFilenameValue(iter.value(), referrer_charset, &filename); |
+ DecodeFilenameValue(iter.value(), referrer_charset, &filename, |
+ &parse_result_flags_); |
+ if (!filename.empty()) |
+ parse_result_flags_ |= HAS_FILENAME; |
} else if (name.empty() && LowerCaseEqualsASCII(iter.name_begin(), |
iter.name_end(), |
"name")) { |
- DecodeFilenameValue(iter.value(), referrer_charset, &name); |
+ DecodeFilenameValue(iter.value(), referrer_charset, &name, NULL); |
+ if (!name.empty()) |
+ parse_result_flags_ |= HAS_NAME; |
} else if (ext_filename.empty() && LowerCaseEqualsASCII(iter.name_begin(), |
iter.name_end(), |
"filename*")) { |
DecodeExtValue(iter.raw_value(), &ext_filename); |
+ if (!ext_filename.empty()) |
+ parse_result_flags_ |= HAS_EXT_FILENAME; |
} |
} |