summaryrefslogtreecommitdiffstats
path: root/chrome/renderer/safe_browsing/phishing_classifier_delegate.cc
blob: 612eb4d7da63a32e6b37fdcb3e3c0bf655817da0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// Copyright (c) 2010 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/renderer/safe_browsing/phishing_classifier_delegate.h"

#include "base/callback.h"
#include "base/logging.h"
#include "chrome/renderer/navigation_state.h"
#include "chrome/renderer/render_view.h"
#include "chrome/renderer/safe_browsing/feature_extractor_clock.h"
#include "chrome/renderer/safe_browsing/phishing_classifier.h"
#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h"
#include "third_party/WebKit/WebKit/chromium/public/WebURL.h"
#include "third_party/WebKit/WebKit/chromium/public/WebView.h"

namespace safe_browsing {

PhishingClassifierDelegate::PhishingClassifierDelegate(
    RenderView* render_view,
    PhishingClassifier* classifier)
    : render_view_(render_view),
      last_page_id_sent_to_classifier_(-1),
      pending_classification_(false) {
  if (!classifier) {
    classifier = new PhishingClassifier(render_view_,
                                        new FeatureExtractorClock());
  }
  classifier_.reset(classifier);
}

PhishingClassifierDelegate::~PhishingClassifierDelegate() {
  CancelPendingClassification();
}

void PhishingClassifierDelegate::SetPhishingScorer(
    const safe_browsing::Scorer* scorer) {
  classifier_->set_phishing_scorer(scorer);

  if (pending_classification_) {
    pending_classification_ = false;
    // If we have a pending classificaton, it should always be true that the
    // main frame URL and page id have not changed since we queued the
    // classification.  This is because we stop any pending classification on
    // main frame loads in RenderView::didCommitProvisionalLoad().
    DCHECK_EQ(StripToplevelUrl(), last_url_sent_to_classifier_);
    DCHECK_EQ(render_view_->page_id(), last_page_id_sent_to_classifier_);
    classifier_->BeginClassification(
        &classifier_page_text_,
        NewCallback(this, &PhishingClassifierDelegate::ClassificationDone));
  }
}

void PhishingClassifierDelegate::CommittedLoadInFrame(
    WebKit::WebFrame* frame) {
  // A new page is starting to load.  Unless the load is a navigation within
  // the same page, we need to cancel classification since the content will
  // now be inconsistent with the phishing model.
  NavigationState* state = NavigationState::FromDataSource(
      frame->dataSource());
  if (!state->was_within_same_page()) {
    CancelPendingClassification();
  }
}

void PhishingClassifierDelegate::FinishedLoad(string16* page_text) {
  // We check that the page id has incremented so that we don't reclassify
  // pages as the user moves back and forward in session history.  Note: we
  // don't send every page id to the classifier, only those where the toplevel
  // URL changed.
  int load_id = render_view_->page_id();
  if (load_id <= last_page_id_sent_to_classifier_) {
    return;
  }

  GURL url_without_ref = StripToplevelUrl();
  if (url_without_ref == last_url_sent_to_classifier_) {
    // The toplevle URL is the same, except for the ref.
    // Update the last page id we sent, but don't trigger a new classification.
    last_page_id_sent_to_classifier_ = load_id;
    return;
  }

  last_url_sent_to_classifier_ = url_without_ref;
  last_page_id_sent_to_classifier_ = load_id;
  classifier_page_text_.swap(*page_text);

  if (classifier_->is_ready()) {
    classifier_->BeginClassification(
        &classifier_page_text_,
        NewCallback(this, &PhishingClassifierDelegate::ClassificationDone));
  } else {
    // If there is no phishing classifier yet, we'll begin classification once
    // SetPhishingScorer() is called by the RenderView.
    pending_classification_ = true;
  }
}

void PhishingClassifierDelegate::CancelPendingClassification() {
  if (classifier_->is_ready()) {
    classifier_->CancelPendingClassification();
  }
  classifier_page_text_.clear();
  pending_classification_ = false;
}

void PhishingClassifierDelegate::ClassificationDone(bool is_phishy,
                                                    double phishy_score) {
  // We no longer need the page text.
  classifier_page_text_.clear();
  VLOG(2) << "Phishy verdict = " << is_phishy << " score = " << phishy_score;

  // TODO(bryner): Grab a snapshot and send a DetectedPhishingSite message
  // to the browser.
}

GURL PhishingClassifierDelegate::StripToplevelUrl() {
  GURL toplevel_url = render_view_->webview()->mainFrame()->url();
  GURL::Replacements replacements;
  replacements.ClearRef();
  return toplevel_url.ReplaceComponents(replacements);
}

}  // namespace safe_browsing