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, &current_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