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 "chrome_frame/html_utils.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <atlbase.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <urlmon.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_tokenizer.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_version_info.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome_frame/utils.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_util.h"
1690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "webkit/common/user_agent/user_agent_util.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kQuotes[] = L"\"'";
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kXFrameOptionsHeader[] = "X-Frame-Options";
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kXFrameOptionsValueAllowAll[] = "allowall";
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HTMLScanner::StringRange::StringRange() {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HTMLScanner::StringRange::StringRange(StrPos start, StrPos end)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : start_(start), end_(end) {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HTMLScanner::StringRange::LowerCaseEqualsASCII(const char* other) const {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ::LowerCaseEqualsASCII(start_, end_, other);
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HTMLScanner::StringRange::Equals(const wchar_t* other) const {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int ret = wcsncmp(&start_[0], other, end_ - start_);
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ret == 0)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = (other[end_ - start_] == L'\0') ? 0 : -1;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ret == 0;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::wstring HTMLScanner::StringRange::Copy() const {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return std::wstring(start_, end_);
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HTMLScanner::StringRange::GetTagName(std::wstring* tag_name) const {
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (*start_ != L'<') {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Badly formatted tag found";
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StrPos name_start = start_;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  name_start++;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (name_start < end_ && IsWhitespace(*name_start))
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    name_start++;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (name_start >= end_) {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We seem to have a degenerate tag (i.e. <   >). Return false here.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StrPos name_end = name_start + 1;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (name_end < end_ && !IsWhitespace(*name_end))
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    name_end++;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (name_end > end_) {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This looks like an improperly formatted tab ('<foo'). Return false here.
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tag_name->assign(name_start, name_end);
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HTMLScanner::StringRange::GetTagAttribute(const wchar_t* attribute_name,
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    StringRange* attribute_value) const {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (NULL == attribute_name || NULL == attribute_value) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Use this so we can use the convenience method LowerCaseEqualsASCII()
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // from string_util.h.
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string search_name_ascii(WideToASCII(attribute_name));
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::WStringTokenizer tokenizer(start_, end_, L" =/");
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  tokenizer.set_options(base::WStringTokenizer::RETURN_DELIMS);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set up the quote chars so that we get quoted attribute values as single
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // tokens.
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tokenizer.set_quote_chars(L"\"'");
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const bool PARSE_STATE_NAME = true;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const bool PARSE_STATE_VALUE = false;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool parse_state = PARSE_STATE_NAME;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Used to skip the first token, which is the tag name.
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool first_token_skipped = false;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is set during a loop iteration in which an '=' sign was spotted.
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It is used to filter out degenerate tags such as:
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // <meta foo==bar>
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool last_token_was_delim = false;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set this if the attribute name has been found that we might then
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // pick up the value in the next loop iteration.
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool attribute_name_found = false;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (tokenizer.GetNext()) {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we have a whitespace delimiter, just keep going. Cases of this should
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // be reduced by the CollapseWhitespace call. If we have an '=' character,
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // we update our state and reiterate.
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (tokenizer.token_is_delim()) {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (*tokenizer.token_begin() == L'=') {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (last_token_was_delim) {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Looks like we have a badly formed tag, just stop parsing now.
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        parse_state = !parse_state;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        last_token_was_delim = true;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_token_was_delim = false;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The first non-delimiter token is the tag name, which we don't want.
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!first_token_skipped) {
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      first_token_skipped = true;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (PARSE_STATE_NAME == parse_state) {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We have a tag name, check to see if it matches our target name:
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (::LowerCaseEqualsASCII(tokenizer.token_begin(), tokenizer.token_end(),
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 search_name_ascii.c_str())) {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        attribute_name_found = true;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (PARSE_STATE_VALUE == parse_state && attribute_name_found) {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      attribute_value->start_ = tokenizer.token_begin();
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      attribute_value->end_ = tokenizer.token_end();
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Unquote the attribute value if need be.
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      attribute_value->UnQuote();
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (PARSE_STATE_VALUE == parse_state) {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If we haven't found the attribute name we want yet, ignore this token
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // and go back to looking for our name.
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parse_state = PARSE_STATE_NAME;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HTMLScanner::StringRange::UnQuote() {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (start_ + 2 > end_) {
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // String's too short to be quoted, bail.
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((*start_ == L'\'' && *(end_ - 1) == L'\'') ||
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (*start_ == L'"' && *(end_ - 1) == L'"')) {
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    start_ = start_ + 1;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    end_ = end_ - 1;
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HTMLScanner::HTMLScanner(const wchar_t* html_string)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : html_string_(CollapseWhitespace(html_string, true)),
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      quotes_(kQuotes) {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HTMLScanner::GetTagsByName(const wchar_t* name, StringRangeList* tag_list,
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const wchar_t* stop_tag) {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(NULL != name);
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(NULL != tag_list);
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(NULL != stop_tag);
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StringRange remaining_html(html_string_.begin(), html_string_.end());
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::wstring search_name(name);
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TrimWhitespace(search_name, TRIM_ALL, &search_name);
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Use this so we can use the convenience method LowerCaseEqualsASCII()
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // from string_util.h.
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string search_name_ascii(WideToASCII(search_name));
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string stop_tag_ascii(WideToASCII(stop_tag));
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StringRange current_tag;
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::wstring current_name;
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (NextTag(&remaining_html, &current_tag)) {
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (current_tag.GetTagName(&current_name)) {
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (LowerCaseEqualsASCII(current_name, search_name_ascii.c_str())) {
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        tag_list->push_back(current_tag);
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else if (LowerCaseEqualsASCII(current_name, stop_tag_ascii.c_str())) {
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // We hit the stop tag so it's time to go home.
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct ScanState {
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool in_quote;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool in_escape;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wchar_t quote_char;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScanState() : in_quote(false), in_escape(false) {}
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HTMLScanner::IsQuote(wchar_t c) {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return quotes_.find(c) != std::wstring::npos;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HTMLScanner::IsHTMLCommentClose(const StringRange* html_string,
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     StrPos pos) {
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pos < html_string->end_ && pos > html_string->start_ + 2 &&
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *pos == L'>') {
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return *(pos-1) == L'-' && *(pos-2) == L'-';
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HTMLScanner::IsIEConditionalCommentClose(const StringRange* html_string,
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              StrPos pos) {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pos < html_string->end_ && pos > html_string->start_ + 2 &&
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *pos == L'>') {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return *(pos-1) == L']';
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HTMLScanner::NextTag(StringRange* html_string, StringRange* tag) {
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(NULL != html_string);
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(NULL != tag);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tag->start_ = html_string->start_;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (tag->start_ < html_string->end_ && *tag->start_ != L'<') {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tag->start_++;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we went past the end of the string.
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (tag->start_ >= html_string->end_) {
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tag->end_ = tag->start_ + 1;
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the tag name to see if we are in an HTML comment. If we are, then
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // don't consider quotes. This should work for example:
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // <!-- foo ' --> <meta foo='bar'>
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::wstring tag_name;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StringRange start_range(tag->start_, html_string->end_);
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  start_range.GetTagName(&tag_name);
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (StartsWith(tag_name, L"!--[if", true)) {
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This looks like the beginning of an IE conditional comment, scan until
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // we hit the end which always looks like ']>'. For now we disregard the
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // contents of the condition, and always assume true.
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(robertshield): Optionally support the grammar defined by
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // http://msdn.microsoft.com/en-us/library/ms537512(VS.85).aspx#syntax.
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (tag->end_ < html_string->end_ &&
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           !IsIEConditionalCommentClose(html_string, tag->end_)) {
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tag->end_++;
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (StartsWith(tag_name, L"!--", true)) {
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We're inside a comment tag which ends in '-->'. Keep going until we
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // reach the end.
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (tag->end_ < html_string->end_ &&
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           !IsHTMLCommentClose(html_string, tag->end_)) {
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tag->end_++;
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (StartsWith(tag_name, L"![endif", true)) {
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We're inside the closing tag of an IE conditional comment which ends in
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // either '-->' of ']>'. Keep going until we reach the end.
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (tag->end_ < html_string->end_ &&
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           !IsIEConditionalCommentClose(html_string, tag->end_) &&
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           !IsHTMLCommentClose(html_string, tag->end_)) {
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tag->end_++;
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Properly handle quoted strings within non-comment tags by maintaining
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // some state while scanning. Specifically, we have to maintain state on
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // whether we are inside a string, what the string terminating character
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // will be and whether we are inside an escape sequence.
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScanState state;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (tag->end_ < html_string->end_) {
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (state.in_quote) {
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (state.in_escape) {
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          state.in_escape = false;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else if (*tag->end_ == '\\') {
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          state.in_escape = true;
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else if (*tag->end_ == state.quote_char) {
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          state.in_quote = false;
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        state.in_quote = IsQuote(state.quote_char = *tag->end_);
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!state.in_quote && *tag->end_ == L'>') {
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tag->end_++;
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We hit the end_ but found no matching tag closure. Consider this an
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // incomplete tag and do not report it.
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (tag->end_ >= html_string->end_)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Modify html_string to point to just beyond the end_ of the current tag.
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  html_string->start_ = tag->end_ + 1;
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace http_utils {
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kChromeFrameUserAgent[] = "chromeframe";
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static char g_cf_user_agent[100] = {0};
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static char g_chrome_user_agent[255] = {0};
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* GetChromeFrameUserAgent() {
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!g_cf_user_agent[0]) {
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    _pAtlModule->m_csStaticDataInitAndTypeInfo.Lock();
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!g_cf_user_agent[0]) {
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      uint32 high_version = 0, low_version = 0;
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetModuleVersion(reinterpret_cast<HMODULE>(&__ImageBase), &high_version,
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       &low_version);
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      wsprintfA(g_cf_user_agent, "%s/%i.%i.%i.%i", kChromeFrameUserAgent,
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                HIWORD(high_version), LOWORD(high_version),
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                HIWORD(low_version), LOWORD(low_version));
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    _pAtlModule->m_csStaticDataInitAndTypeInfo.Unlock();
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return g_cf_user_agent;
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string AddChromeFrameToUserAgentValue(const std::string& value) {
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (value.empty()) {
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return value;
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (value.find(kChromeFrameUserAgent) != std::string::npos) {
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Our user agent has already been added.
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return value;
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string ret(value);
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t insert_position = ret.find(')');
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (insert_position != std::string::npos) {
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (insert_position > 1 && isalnum(ret[insert_position - 1]))
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret.insert(insert_position++, ";");
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret.insert(insert_position++, " ");
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret.insert(insert_position, GetChromeFrameUserAgent());
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret += " ";
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret += GetChromeFrameUserAgent();
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ret;
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string RemoveChromeFrameFromUserAgentValue(const std::string& value) {
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t cf_start = value.find(kChromeFrameUserAgent);
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (cf_start == std::string::npos) {
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The user agent is not present.
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return value;
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t offset = 0;
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we prepended a '; ' or a ' ' then remove that in the output.
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (cf_start > 1 && value[cf_start - 1] == ' ')
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++offset;
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (cf_start > 3 &&
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      value[cf_start - 2] == ';' &&
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      isalnum(value[cf_start - 3])) {
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++offset;
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string ret(value, 0, std::max(cf_start - offset, 0U));
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cf_start += strlen(kChromeFrameUserAgent);
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (cf_start < value.length() &&
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         ((value[cf_start] >= '0' && value[cf_start] <= '9') ||
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          value[cf_start] == '.' ||
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          value[cf_start] == '/')) {
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ++cf_start;
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (cf_start < value.length())
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret.append(value, cf_start, std::string::npos);
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ret;
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GetDefaultUserAgentHeaderWithCFTag() {
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string ua(GetDefaultUserAgent());
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return "User-Agent: " + AddChromeFrameToUserAgentValue(ua);
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* GetChromeUserAgent() {
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!g_chrome_user_agent[0]) {
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    _pAtlModule->m_csStaticDataInitAndTypeInfo.Lock();
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!g_chrome_user_agent[0]) {
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string ua;
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chrome::VersionInfo version_info;
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string product("Chrome/");
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      product += version_info.is_valid() ? version_info.Version()
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         : "0.0.0.0";
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ua = webkit_glue::BuildUserAgentFromProduct(product);
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(ua.length() < arraysize(g_chrome_user_agent));
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      lstrcpynA(g_chrome_user_agent, ua.c_str(),
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                arraysize(g_chrome_user_agent) - 1);
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    _pAtlModule->m_csStaticDataInitAndTypeInfo.Unlock();
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return g_chrome_user_agent;
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GetDefaultUserAgent() {
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string ret;
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD size = MAX_PATH;
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = E_OUTOFMEMORY;
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int retries = 1; hr == E_OUTOFMEMORY && retries <= 10; ++retries) {
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = ::ObtainUserAgentString(0, WriteInto(&ret, size + 1), &size);
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (hr == E_OUTOFMEMORY) {
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      size = MAX_PATH * retries;
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (SUCCEEDED(hr)) {
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Truncate the extra allocation.
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK_GT(size, 0U);
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret.resize(size - 1);
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr)) {
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << base::StringPrintf("ObtainUserAgentString==0x%08X", hr);
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return std::string();
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ret;
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HasFrameBustingHeader(const std::string& http_headers) {
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE: We cannot use net::GetSpecificHeader() here since when there are
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // multiple instances of a header that returns the first value seen, and we
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // need to look at all instances.
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::HttpUtil::HeadersIterator it(http_headers.begin(), http_headers.end(),
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    "\r\n");
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (it.GetNext()) {
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!lstrcmpiA(it.name().c_str(), kXFrameOptionsHeader) &&
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        lstrcmpiA(it.values().c_str(), kXFrameOptionsValueAllowAll))
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GetHttpHeaderFromHeaderList(const std::string& header,
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        const std::string& headers) {
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n");
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (it.GetNext()) {
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!lstrcmpiA(it.name().c_str(), header.c_str()))
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return std::string(it.values_begin(), it.values_end());
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return std::string();
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace http_utils
476