15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_content_disposition.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/base64.h" 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/i18n/icu_string_conversions.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_tokenizer.h" 117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/string_util.h" 12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/sys_string_conversions.h" 13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_util.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_util.h" 16ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "third_party/icu/source/common/unicode/ucnv.h" 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace { 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)enum RFC2047EncodingType { 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Q_ENCODING, 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) B_ENCODING 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Decodes a "Q" encoded string as described in RFC 2047 section 4.2. Similar to 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// decoding a quoted-printable string. Returns true if the input was valid. 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool DecodeQEncoding(const std::string& input, std::string* output) { 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string temp; 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) temp.reserve(input.size()); 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (std::string::const_iterator it = input.begin(); it != input.end(); 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ++it) { 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (*it == '_') { 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) temp.push_back(' '); 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (*it == '=') { 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if ((input.end() - it < 3) || 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) !IsHexDigit(static_cast<unsigned char>(*(it + 1))) || 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) !IsHexDigit(static_cast<unsigned char>(*(it + 2)))) 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unsigned char ch = HexDigitToInt(*(it + 1)) * 16 + 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HexDigitToInt(*(it + 2)); 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) temp.push_back(static_cast<char>(ch)); 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ++it; 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ++it; 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (0x20 < *it && *it < 0x7F && *it != '?') { 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // In a Q-encoded word, only printable ASCII characters 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // represent themselves. Besides, space, '=', '_' and '?' are 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // not allowed, but they're already filtered out. 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_NE('=', *it); 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_NE('?', *it); 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_NE('_', *it); 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) temp.push_back(*it); 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) output->swap(temp); 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Decodes a "Q" or "B" encoded string as per RFC 2047 section 4. The encoding 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// type is specified in |enc_type|. 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool DecodeBQEncoding(const std::string& part, 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RFC2047EncodingType enc_type, 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& charset, 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string* output) { 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string decoded; 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!((enc_type == B_ENCODING) ? 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Base64Decode(part, &decoded) : DecodeQEncoding(part, &decoded))) 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (decoded.empty()) { 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) output->clear(); 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UErrorCode err = U_ZERO_ERROR; 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UConverter* converter(ucnv_open(charset.c_str(), &err)); 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (U_FAILURE(err)) 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // A single byte in a legacy encoding can be expanded to 3 bytes in UTF-8. 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // A 'two-byte character' in a legacy encoding can be expanded to 4 bytes 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // in UTF-8. Therefore, the expansion ratio is 3 at most. Add one for a 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // trailing '\0'. 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) size_t output_length = decoded.length() * 3 + 1; 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) char* buf = WriteInto(output, output_length); 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) output_length = ucnv_toAlgorithmic(UCNV_UTF8, converter, buf, output_length, 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) decoded.data(), decoded.length(), &err); 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ucnv_close(converter); 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (U_FAILURE(err)) 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) output->resize(output_length); 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool DecodeWord(const std::string& encoded_word, 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& referrer_charset, 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool* is_rfc2047, 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string* output, 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int* parse_result_flags) { 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *is_rfc2047 = false; 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) output->clear(); 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (encoded_word.empty()) 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!IsStringASCII(encoded_word)) { 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Try UTF-8, referrer_charset and the native OS default charset in turn. 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (IsStringUTF8(encoded_word)) { 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *output = encoded_word; 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::string16 utf16_output; 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!referrer_charset.empty() && 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::CodepageToUTF16(encoded_word, referrer_charset.c_str(), 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::OnStringConversionError::FAIL, 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &utf16_output)) { 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *output = UTF16ToUTF8(utf16_output); 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *output = WideToUTF8(base::SysNativeMBToWide(encoded_word)); 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *parse_result_flags |= net::HttpContentDisposition::HAS_NON_ASCII_STRINGS; 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // RFC 2047 : one of encoding methods supported by Firefox and relatively 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // widely used by web servers. 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // =?charset?<E>?<encoded string>?= where '<E>' is either 'B' or 'Q'. 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We don't care about the length restriction (72 bytes) because 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // many web servers generate encoded words longer than the limit. 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string decoded_word; 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *is_rfc2047 = true; 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int part_index = 0; 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string charset; 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::StringTokenizer t(encoded_word, "?"); 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RFC2047EncodingType enc_type = Q_ENCODING; 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while (*is_rfc2047 && t.GetNext()) { 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string part = t.token(); 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) switch (part_index) { 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case 0: 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (part != "=") { 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *is_rfc2047 = false; 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ++part_index; 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case 1: 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Do we need charset validity check here? 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) charset = part; 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ++part_index; 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case 2: 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (part.size() > 1 || 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) part.find_first_of("bBqQ") == std::string::npos) { 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *is_rfc2047 = false; 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (part[0] == 'b' || part[0] == 'B') { 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) enc_type = B_ENCODING; 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ++part_index; 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case 3: 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *is_rfc2047 = DecodeBQEncoding(part, enc_type, charset, &decoded_word); 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!*is_rfc2047) { 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Last minute failure. Invalid B/Q encoding. Rather than 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // passing it through, return now. 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ++part_index; 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case 4: 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (part != "=") { 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Another last minute failure ! 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Likely to be a case of two encoded-words in a row or 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // an encoded word followed by a non-encoded word. We can be 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // generous, but it does not help much in terms of compatibility, 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // I believe. Return immediately. 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *is_rfc2047 = false; 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ++part_index; 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) default: 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *is_rfc2047 = false; 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (*is_rfc2047) { 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (*(encoded_word.end() - 1) == '=') { 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) output->swap(decoded_word); 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *parse_result_flags |= 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) net::HttpContentDisposition::HAS_RFC2047_ENCODED_STRINGS; 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // encoded_word ending prematurelly with '?' or extra '?' 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *is_rfc2047 = false; 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We're not handling 'especial' characters quoted with '\', but 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // it should be Ok because we're not an email client but a 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // web browser. 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // What IE6/7 does: %-escaped UTF-8. 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) decoded_word = net::UnescapeURLComponent(encoded_word, 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) net::UnescapeRule::SPACES); 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (decoded_word != encoded_word) 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *parse_result_flags |= 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) net::HttpContentDisposition::HAS_PERCENT_ENCODED_STRINGS; 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (IsStringUTF8(decoded_word)) { 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) output->swap(decoded_word); 2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We can try either the OS default charset or 'origin charset' here, 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // As far as I can tell, IE does not support it. However, I've seen 2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // web servers emit %-escaped string in a legacy encoding (usually 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // origin charset). 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(jungshik) : Test IE further and consider adding a fallback here. 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Decodes the value of a 'filename' or 'name' parameter given as |input|. The 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// value is supposed to be of the form: 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// value = token | quoted-string 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// However we currently also allow RFC 2047 encoding and non-ASCII 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// strings. Non-ASCII strings are interpreted based on |referrer_charset|. 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool DecodeFilenameValue(const std::string& input, 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& referrer_charset, 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string* output, 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int* parse_result_flags) { 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int current_parse_result_flags = 0; 2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string decoded_value; 2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool is_previous_token_rfc2047 = true; 2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Tokenize with whitespace characters. 2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::StringTokenizer t(input, " \t\n\r"); 2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) t.set_options(base::StringTokenizer::RETURN_DELIMS); 2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while (t.GetNext()) { 2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (t.token_is_delim()) { 2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If the previous non-delimeter token is not RFC2047-encoded, 2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // put in a space in its place. Otheriwse, skip over it. 2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!is_previous_token_rfc2047) 2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) decoded_value.push_back(' '); 2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We don't support a single multibyte character split into 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // adjacent encoded words. Some broken mail clients emit headers 2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // with that problem, but most web servers usually encode a filename 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // in a single encoded-word. Firefox/Thunderbird do not support 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // it, either. 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string decoded; 2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!DecodeWord(t.token(), referrer_charset, &is_previous_token_rfc2047, 2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &decoded, ¤t_parse_result_flags)) 2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) decoded_value.append(decoded); 2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) output->swap(decoded_value); 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (parse_result_flags && !output->empty()) 2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *parse_result_flags |= current_parse_result_flags; 2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Parses the charset and value-chars out of an ext-value string. 2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ext-value = charset "'" [ language ] "'" value-chars 2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ParseExtValueComponents(const std::string& input, 2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string* charset, 2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string* value_chars) { 2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::StringTokenizer t(input, "'"); 2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) t.set_options(base::StringTokenizer::RETURN_DELIMS); 2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string temp_charset; 2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string temp_value; 2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int numDelimsSeen = 0; 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while (t.GetNext()) { 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (t.token_is_delim()) { 2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ++numDelimsSeen; 2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) switch (numDelimsSeen) { 2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case 0: 2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) temp_charset = t.token(); 2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case 1: 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Language is ignored. 2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case 2: 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) temp_value = t.token(); 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) default: 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (numDelimsSeen != 2) 2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (temp_charset.empty() || temp_value.empty()) 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) charset->swap(temp_charset); 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) value_chars->swap(temp_value); 3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// http://tools.ietf.org/html/rfc5987#section-3.2 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ext-value = charset "'" [ language ] "'" value-chars 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// charset = "UTF-8" / "ISO-8859-1" / mime-charset 3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// mime-charset = 1*mime-charsetc 3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// mime-charsetc = ALPHA / DIGIT 3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// / "!" / "#" / "$" / "%" / "&" 3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// / "+" / "-" / "^" / "_" / "`" 3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// / "{" / "}" / "~" 3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// language = <Language-Tag, defined in [RFC5646], Section 2.1> 3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// value-chars = *( pct-encoded / attr-char ) 3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// pct-encoded = "%" HEXDIG HEXDIG 3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// attr-char = ALPHA / DIGIT 3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// / "!" / "#" / "$" / "&" / "+" / "-" / "." 3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// / "^" / "_" / "`" / "|" / "~" 3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool DecodeExtValue(const std::string& param_value, std::string* decoded) { 3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (param_value.find('"') != std::string::npos) 3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string charset; 3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string value; 3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!ParseExtValueComponents(param_value, &charset, &value)) 3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // RFC 5987 value should be ASCII-only. 3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!IsStringASCII(value)) { 3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) decoded->clear(); 3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::string unescaped = net::UnescapeURLComponent( 3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) value, net::UnescapeRule::SPACES | net::UnescapeRule::URL_SPECIAL_CHARS); 3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return base::ConvertToUtf8AndNormalize(unescaped, charset, decoded); 3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpContentDisposition::HttpContentDisposition( 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& header, const std::string& referrer_charset) 3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : type_(INLINE), 3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) parse_result_flags_(INVALID) { 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Parse(header, referrer_charset); 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HttpContentDisposition::~HttpContentDisposition() { 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string::const_iterator HttpContentDisposition::ConsumeDispositionType( 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator begin, std::string::const_iterator end) { 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(type_ == INLINE); 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator delimiter = std::find(begin, end, ';'); 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator type_begin = begin; 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator type_end = delimiter; 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpUtil::TrimLWS(&type_begin, &type_end); 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the disposition-type isn't a valid token the then the 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Content-Disposition header is malformed, and we treat the first bytes as 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a parameter rather than a disposition-type. 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!HttpUtil::IsToken(type_begin, type_end)) 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return begin; 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) parse_result_flags_ |= HAS_DISPOSITION_TYPE; 3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(std::find(type_begin, type_end, '=') == type_end); 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (LowerCaseEqualsASCII(type_begin, type_end, "inline")) { 3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) type_ = INLINE; 3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (LowerCaseEqualsASCII(type_begin, type_end, "attachment")) { 3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) type_ = ATTACHMENT; 3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) parse_result_flags_ |= HAS_UNKNOWN_DISPOSITION_TYPE; 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type_ = ATTACHMENT; 3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return delimiter; 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://tools.ietf.org/html/rfc6266 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// content-disposition = "Content-Disposition" ":" 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// disposition-type *( ";" disposition-parm ) 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// disposition-type = "inline" | "attachment" | disp-ext-type 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ; case-insensitive 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// disp-ext-type = token 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// disposition-parm = filename-parm | disp-ext-parm 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// filename-parm = "filename" "=" value 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// | "filename*" "=" ext-value 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// disp-ext-parm = token "=" value 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// | ext-token "=" ext-value 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ext-token = <the characters in token, followed by "*"> 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HttpContentDisposition::Parse(const std::string& header, 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& referrer_charset) { 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(type_ == INLINE); 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(filename_.empty()); 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator pos = header.begin(); 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::const_iterator end = header.end(); 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pos = ConsumeDispositionType(pos, end); 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string name; 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string filename; 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string ext_filename; 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HttpUtil::NameValuePairsIterator iter(pos, end, ';'); 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (iter.GetNext()) { 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (filename.empty() && LowerCaseEqualsASCII(iter.name_begin(), 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iter.name_end(), 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "filename")) { 4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DecodeFilenameValue(iter.value(), referrer_charset, &filename, 4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &parse_result_flags_); 4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!filename.empty()) 4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) parse_result_flags_ |= HAS_FILENAME; 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (name.empty() && LowerCaseEqualsASCII(iter.name_begin(), 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iter.name_end(), 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "name")) { 4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DecodeFilenameValue(iter.value(), referrer_charset, &name, NULL); 4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!name.empty()) 4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) parse_result_flags_ |= HAS_NAME; 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (ext_filename.empty() && LowerCaseEqualsASCII(iter.name_begin(), 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) iter.name_end(), 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "filename*")) { 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DecodeExtValue(iter.raw_value(), &ext_filename); 4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!ext_filename.empty()) 4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) parse_result_flags_ |= HAS_EXT_FILENAME; 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ext_filename.empty()) 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) filename_ = ext_filename; 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (!filename.empty()) 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) filename_ = filename; 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) filename_ = name; 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace net 457