This source file includes following definitions.
- StripRef
- Create
- OnControlMessageReceived
- OnSetPhishingModel
- Create
- is_classifying_
- SetPhishingScorer
- OnStartPhishingDetection
- DidCommitProvisionalLoad
- PageCaptured
- CancelPendingClassification
- OnMessageReceived
- ClassificationDone
- GetToplevelUrl
- MaybeStartClassification
#include "chrome/renderer/safe_browsing/phishing_classifier_delegate.h"
#include <set>
#include "base/bind.h"
#include "base/callback.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "chrome/common/safe_browsing/csd.pb.h"
#include "chrome/common/safe_browsing/safebrowsing_messages.h"
#include "chrome/renderer/safe_browsing/feature_extractor_clock.h"
#include "chrome/renderer/safe_browsing/phishing_classifier.h"
#include "chrome/renderer/safe_browsing/scorer.h"
#include "content/public/renderer/document_state.h"
#include "content/public/renderer/navigation_state.h"
#include "content/public/renderer/render_thread.h"
#include "content/public/renderer/render_view.h"
#include "third_party/WebKit/public/platform/WebURL.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/WebKit/public/web/WebView.h"
using content::DocumentState;
using content::NavigationState;
using content::RenderThread;
namespace safe_browsing {
static GURL StripRef(const GURL& url) {
GURL::Replacements replacements;
replacements.ClearRef();
return url.ReplaceComponents(replacements);
}
typedef std::set<PhishingClassifierDelegate*> PhishingClassifierDelegates;
static base::LazyInstance<PhishingClassifierDelegates>
g_delegates = LAZY_INSTANCE_INITIALIZER;
static base::LazyInstance<scoped_ptr<const safe_browsing::Scorer> >
g_phishing_scorer = LAZY_INSTANCE_INITIALIZER;
PhishingClassifierFilter* PhishingClassifierFilter::Create() {
return new PhishingClassifierFilter();
}
PhishingClassifierFilter::PhishingClassifierFilter()
: RenderProcessObserver() {}
PhishingClassifierFilter::~PhishingClassifierFilter() {}
bool PhishingClassifierFilter::OnControlMessageReceived(
const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(PhishingClassifierFilter, message)
IPC_MESSAGE_HANDLER(SafeBrowsingMsg_SetPhishingModel, OnSetPhishingModel)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void PhishingClassifierFilter::OnSetPhishingModel(const std::string& model) {
safe_browsing::Scorer* scorer = NULL;
if (!model.empty()) {
scorer = safe_browsing::Scorer::Create(model);
if (!scorer) {
DLOG(ERROR) << "Unable to create a PhishingScorer - corrupt model?";
return;
}
}
PhishingClassifierDelegates::iterator i;
for (i = g_delegates.Get().begin(); i != g_delegates.Get().end(); ++i) {
(*i)->SetPhishingScorer(scorer);
}
g_phishing_scorer.Get().reset(scorer);
}
PhishingClassifierDelegate* PhishingClassifierDelegate::Create(
content::RenderView* render_view, PhishingClassifier* classifier) {
return new PhishingClassifierDelegate(render_view, classifier);
}
PhishingClassifierDelegate::PhishingClassifierDelegate(
content::RenderView* render_view,
PhishingClassifier* classifier)
: content::RenderViewObserver(render_view),
last_main_frame_transition_(content::PAGE_TRANSITION_LINK),
have_page_text_(false),
is_classifying_(false) {
g_delegates.Get().insert(this);
if (!classifier) {
classifier = new PhishingClassifier(render_view,
new FeatureExtractorClock());
}
classifier_.reset(classifier);
if (g_phishing_scorer.Get().get())
SetPhishingScorer(g_phishing_scorer.Get().get());
}
PhishingClassifierDelegate::~PhishingClassifierDelegate() {
CancelPendingClassification(SHUTDOWN);
g_delegates.Get().erase(this);
}
void PhishingClassifierDelegate::SetPhishingScorer(
const safe_browsing::Scorer* scorer) {
if (!render_view()->GetWebView())
return;
if (is_classifying_) {
CancelPendingClassification(NEW_PHISHING_SCORER);
}
classifier_->set_phishing_scorer(scorer);
MaybeStartClassification();
}
void PhishingClassifierDelegate::OnStartPhishingDetection(const GURL& url) {
last_url_received_from_browser_ = StripRef(url);
MaybeStartClassification();
}
void PhishingClassifierDelegate::DidCommitProvisionalLoad(
blink::WebFrame* frame, bool is_new_navigation) {
DocumentState* document_state = DocumentState::FromDataSource(
frame->dataSource());
NavigationState* navigation_state = document_state->navigation_state();
CancelPendingClassification(navigation_state->was_within_same_page() ?
NAVIGATE_WITHIN_PAGE : NAVIGATE_AWAY);
if (frame == render_view()->GetWebView()->mainFrame()) {
last_main_frame_transition_ = navigation_state->transition_type();
}
}
void PhishingClassifierDelegate::PageCaptured(base::string16* page_text,
bool preliminary_capture) {
if (preliminary_capture) {
return;
}
CancelPendingClassification(PAGE_RECAPTURED);
last_finished_load_url_ = GetToplevelUrl();
classifier_page_text_.swap(*page_text);
have_page_text_ = true;
MaybeStartClassification();
}
void PhishingClassifierDelegate::CancelPendingClassification(
CancelClassificationReason reason) {
if (is_classifying_) {
UMA_HISTOGRAM_ENUMERATION("SBClientPhishing.CancelClassificationReason",
reason,
CANCEL_CLASSIFICATION_MAX);
is_classifying_ = false;
}
if (classifier_->is_ready()) {
classifier_->CancelPendingClassification();
}
classifier_page_text_.clear();
have_page_text_ = false;
}
bool PhishingClassifierDelegate::OnMessageReceived(
const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(PhishingClassifierDelegate, message)
IPC_MESSAGE_HANDLER(SafeBrowsingMsg_StartPhishingDetection,
OnStartPhishingDetection)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void PhishingClassifierDelegate::ClassificationDone(
const ClientPhishingRequest& verdict) {
classifier_page_text_.clear();
VLOG(2) << "Phishy verdict = " << verdict.is_phishing()
<< " score = " << verdict.client_score();
if (verdict.client_score() != PhishingClassifier::kInvalidScore) {
DCHECK_EQ(last_url_sent_to_classifier_.spec(), verdict.url());
RenderThread::Get()->Send(new SafeBrowsingHostMsg_PhishingDetectionDone(
routing_id(), verdict.SerializeAsString()));
}
}
GURL PhishingClassifierDelegate::GetToplevelUrl() {
return render_view()->GetWebView()->mainFrame()->document().url();
}
void PhishingClassifierDelegate::MaybeStartClassification() {
if (!classifier_->is_ready()) {
VLOG(2) << "Not starting classification, no Scorer created.";
return;
}
if (last_main_frame_transition_ & content::PAGE_TRANSITION_FORWARD_BACK) {
VLOG(2) << "Not starting classification for back/forward navigation";
last_url_sent_to_classifier_ = last_finished_load_url_;
classifier_page_text_.clear();
have_page_text_ = false;
return;
}
GURL stripped_last_load_url(StripRef(last_finished_load_url_));
if (stripped_last_load_url == StripRef(last_url_sent_to_classifier_)) {
VLOG(2) << "Toplevel URL is unchanged, not starting classification.";
classifier_page_text_.clear();
have_page_text_ = false;
return;
}
if (!have_page_text_) {
VLOG(2) << "Not starting classification, there is no page text ready.";
return;
}
if (last_url_received_from_browser_ != stripped_last_load_url) {
VLOG(2) << "Not starting classification, last url from browser is "
<< last_url_received_from_browser_ << ", last finished load is "
<< last_finished_load_url_;
return;
}
VLOG(2) << "Starting classification for " << last_finished_load_url_;
last_url_sent_to_classifier_ = last_finished_load_url_;
is_classifying_ = true;
classifier_->BeginClassification(
&classifier_page_text_,
base::Bind(&PhishingClassifierDelegate::ClassificationDone,
base::Unretained(this)));
}
}