root/chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. original_response_headers
  2. original_response_headers
  3. applicable_request_stages_
  4. IsFulfilled
  5. GetURLMatcherConditionSets
  6. Create

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition.h"

#include "base/bind.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "chrome/browser/extensions/api/declarative_webrequest/request_stage.h"
#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_condition_attribute.h"
#include "chrome/browser/extensions/api/declarative_webrequest/webrequest_constants.h"
#include "components/url_matcher/url_matcher_factory.h"
#include "net/url_request/url_request.h"

using url_matcher::URLMatcherConditionFactory;
using url_matcher::URLMatcherConditionSet;
using url_matcher::URLMatcherFactory;

namespace keys = extensions::declarative_webrequest_constants;

namespace {
static URLMatcherConditionSet::ID g_next_id = 0;

// TODO(battre): improve error messaging to give more meaningful messages
// to the extension developer.
// Error messages:
const char kExpectedDictionary[] = "A condition has to be a dictionary.";
const char kConditionWithoutInstanceType[] = "A condition had no instanceType";
const char kExpectedOtherConditionType[] = "Expected a condition of type "
    "declarativeWebRequest.RequestMatcher";
const char kInvalidTypeOfParamter[] = "Attribute '%s' has an invalid type";
const char kConditionCannotBeFulfilled[] = "A condition can never be "
    "fulfilled because its attributes cannot all be tested at the "
    "same time in the request life-cycle.";
}  // namespace

namespace extensions {

namespace keys = declarative_webrequest_constants;

//
// WebRequestData
//

WebRequestData::WebRequestData(net::URLRequest* request, RequestStage stage)
    : request(request),
      stage(stage),
      original_response_headers(NULL) {}

WebRequestData::WebRequestData(
    net::URLRequest* request,
    RequestStage stage,
    const net::HttpResponseHeaders* original_response_headers)
    : request(request),
      stage(stage),
      original_response_headers(original_response_headers) {}

WebRequestData::~WebRequestData() {}

//
// WebRequestDataWithMatchIds
//

WebRequestDataWithMatchIds::WebRequestDataWithMatchIds(
    const WebRequestData* request_data)
    : data(request_data) {}

WebRequestDataWithMatchIds::~WebRequestDataWithMatchIds() {}

//
// WebRequestCondition
//

WebRequestCondition::WebRequestCondition(
    scoped_refptr<URLMatcherConditionSet> url_matcher_conditions,
    scoped_refptr<URLMatcherConditionSet> first_party_url_matcher_conditions,
    const WebRequestConditionAttributes& condition_attributes)
    : url_matcher_conditions_(url_matcher_conditions),
      first_party_url_matcher_conditions_(first_party_url_matcher_conditions),
      condition_attributes_(condition_attributes),
      applicable_request_stages_(~0) {
  for (WebRequestConditionAttributes::const_iterator i =
       condition_attributes_.begin(); i != condition_attributes_.end(); ++i) {
    applicable_request_stages_ &= (*i)->GetStages();
  }
}

WebRequestCondition::~WebRequestCondition() {}

bool WebRequestCondition::IsFulfilled(
    const MatchData& request_data) const {
  if (!(request_data.data->stage & applicable_request_stages_)) {
    // A condition that cannot be evaluated is considered as violated.
    return false;
  }

  // Check URL attributes if present.
  if (url_matcher_conditions_.get() &&
      !ContainsKey(request_data.url_match_ids, url_matcher_conditions_->id()))
    return false;
  if (first_party_url_matcher_conditions_.get() &&
      !ContainsKey(request_data.first_party_url_match_ids,
                   first_party_url_matcher_conditions_->id()))
    return false;

  // All condition attributes must be fulfilled for a fulfilled condition.
  for (WebRequestConditionAttributes::const_iterator i =
           condition_attributes_.begin();
       i != condition_attributes_.end(); ++i) {
    if (!(*i)->IsFulfilled(*(request_data.data)))
      return false;
  }
  return true;
}

void WebRequestCondition::GetURLMatcherConditionSets(
    URLMatcherConditionSet::Vector* condition_sets) const {
  if (url_matcher_conditions_.get())
    condition_sets->push_back(url_matcher_conditions_);
  if (first_party_url_matcher_conditions_.get())
    condition_sets->push_back(first_party_url_matcher_conditions_);
}

// static
scoped_ptr<WebRequestCondition> WebRequestCondition::Create(
    const Extension* extension,
    URLMatcherConditionFactory* url_matcher_condition_factory,
    const base::Value& condition,
    std::string* error) {
  const base::DictionaryValue* condition_dict = NULL;
  if (!condition.GetAsDictionary(&condition_dict)) {
    *error = kExpectedDictionary;
    return scoped_ptr<WebRequestCondition>();
  }

  // Verify that we are dealing with a Condition whose type we understand.
  std::string instance_type;
  if (!condition_dict->GetString(keys::kInstanceTypeKey, &instance_type)) {
    *error = kConditionWithoutInstanceType;
    return scoped_ptr<WebRequestCondition>();
  }
  if (instance_type != keys::kRequestMatcherType) {
    *error = kExpectedOtherConditionType;
    return scoped_ptr<WebRequestCondition>();
  }

  WebRequestConditionAttributes attributes;
  scoped_refptr<URLMatcherConditionSet> url_matcher_condition_set;
  scoped_refptr<URLMatcherConditionSet> first_party_url_matcher_condition_set;

  for (base::DictionaryValue::Iterator iter(*condition_dict);
       !iter.IsAtEnd(); iter.Advance()) {
    const std::string& condition_attribute_name = iter.key();
    const base::Value& condition_attribute_value = iter.value();
    const bool name_is_url = condition_attribute_name == keys::kUrlKey;
    if (condition_attribute_name == keys::kInstanceTypeKey) {
      // Skip this.
    } else if (name_is_url ||
               condition_attribute_name == keys::kFirstPartyForCookiesUrlKey) {
      const base::DictionaryValue* dict = NULL;
      if (!condition_attribute_value.GetAsDictionary(&dict)) {
        *error = base::StringPrintf(kInvalidTypeOfParamter,
                                    condition_attribute_name.c_str());
      } else {
        if (name_is_url) {
          url_matcher_condition_set =
              URLMatcherFactory::CreateFromURLFilterDictionary(
                  url_matcher_condition_factory, dict, ++g_next_id, error);
        } else {
          first_party_url_matcher_condition_set =
              URLMatcherFactory::CreateFromURLFilterDictionary(
                  url_matcher_condition_factory, dict, ++g_next_id, error);
        }
      }
    } else {
      scoped_refptr<const WebRequestConditionAttribute> attribute =
          WebRequestConditionAttribute::Create(
              condition_attribute_name,
              &condition_attribute_value,
              error);
      if (attribute.get())
        attributes.push_back(attribute);
    }
    if (!error->empty())
      return scoped_ptr<WebRequestCondition>();
  }

  scoped_ptr<WebRequestCondition> result(
      new WebRequestCondition(url_matcher_condition_set,
                              first_party_url_matcher_condition_set,
                              attributes));

  if (!result->stages()) {
    *error = kConditionCannotBeFulfilled;
    return scoped_ptr<WebRequestCondition>();
  }

  return result.Pass();
}

}  // namespace extensions

/* [<][>][^][v][top][bottom][index][help] */