0

Prevent guest views from issuing a search for empty text.

Do the same for Android webview.

Set up roadblocks along the way to prevent this from happening again.

BUG=535086

Review URL: https://codereview.chromium.org/1365563003

Cr-Commit-Position: refs/heads/master@{#359419}
This commit is contained in:
thestig
2015-11-12 15:01:33 -08:00
committed by Commit bot
parent 3e70670d66
commit 6057a6b26a
13 changed files with 88 additions and 42 deletions
android_webview/browser
chrome/test/data/extensions/platform_apps/web_view/shim
content
browser
public
renderer
extensions
browser
guest_view
test
data
web_view
apitest
pdf
ppapi/cpp/private

@ -18,14 +18,12 @@ namespace android_webview {
FindHelper::FindHelper(WebContents* web_contents)
: WebContentsObserver(web_contents),
listener_(NULL),
listener_(nullptr),
async_find_started_(false),
sync_find_started_(false),
find_request_id_counter_(0),
current_request_id_(0),
last_match_count_(-1),
last_active_ordinal_(-1),
weak_factory_(this) {
last_active_ordinal_(-1) {
}
FindHelper::~FindHelper() {
@ -39,32 +37,36 @@ void FindHelper::FindAllAsync(const base::string16& search_string) {
// Stop any ongoing asynchronous request.
web_contents()->StopFinding(content::STOP_FIND_ACTION_KEEP_SELECTION);
sync_find_started_ = false;
async_find_started_ = true;
StartNewRequest(search_string);
if (MaybeHandleEmptySearch(search_string))
return;
WebFindOptions options;
options.forward = true;
options.matchCase = false;
options.findNext = false;
StartNewRequest(search_string);
web_contents()->Find(current_request_id_, search_string, options);
}
void FindHelper::HandleFindReply(int request_id,
int match_count,
int active_ordinal,
bool finished) {
if ((!async_find_started_ && !sync_find_started_) ||
request_id != current_request_id_) {
int match_count,
int active_ordinal,
bool finished) {
if (!async_find_started_ || request_id != current_request_id_)
return;
}
NotifyResults(active_ordinal, match_count, finished);
}
void FindHelper::FindNext(bool forward) {
if (!sync_find_started_ && !async_find_started_)
if (!async_find_started_)
return;
if (MaybeHandleEmptySearch(last_search_string_))
return;
WebFindOptions options;
@ -78,13 +80,21 @@ void FindHelper::FindNext(bool forward) {
void FindHelper::ClearMatches() {
web_contents()->StopFinding(content::STOP_FIND_ACTION_CLEAR_SELECTION);
sync_find_started_ = false;
async_find_started_ = false;
last_search_string_.clear();
last_match_count_ = -1;
last_active_ordinal_ = -1;
}
bool FindHelper::MaybeHandleEmptySearch(const base::string16& search_string) {
if (!search_string.empty())
return false;
web_contents()->StopFinding(content::STOP_FIND_ACTION_CLEAR_SELECTION);
NotifyResults(0, 0, true);
return true;
}
void FindHelper::StartNewRequest(const base::string16& search_string) {
current_request_id_ = find_request_id_counter_++;
last_search_string_ = search_string;
@ -93,9 +103,9 @@ void FindHelper::StartNewRequest(const base::string16& search_string) {
}
void FindHelper::NotifyResults(int active_ordinal,
int match_count,
bool finished) {
// Match count or ordinal values set to -1 refer to the received replies.
int match_count,
bool finished) {
// Match count or ordinal values set to -1 refer to received replies.
if (match_count == -1)
match_count = last_match_count_;
else

@ -5,7 +5,6 @@
#ifndef ANDROID_WEBVIEW_BROWSER_FIND_HELPER_H_
#define ANDROID_WEBVIEW_BROWSER_FIND_HELPER_H_
#include "base/memory/weak_ptr.h"
#include "content/public/browser/web_contents_observer.h"
namespace android_webview {
@ -28,7 +27,7 @@ class FindHelper : public content::WebContentsObserver {
~FindHelper() override;
// Sets the listener to receive find result updates.
// Does not own the listener and must set to NULL when invalid.
// Does not own the listener and must set to nullptr when invalid.
void SetListener(Listener* listener);
// Asynchronous API.
@ -44,6 +43,7 @@ class FindHelper : public content::WebContentsObserver {
private:
void StartNewRequest(const base::string16& search_string);
bool MaybeHandleEmptySearch(const base::string16& search_string);
void NotifyResults(int active_ordinal, int match_count, bool finished);
// Listener results are reported to.
@ -51,7 +51,6 @@ class FindHelper : public content::WebContentsObserver {
// Used to check the validity of FindNext operations.
bool async_find_started_;
bool sync_find_started_;
// Used to provide different ids to each request and for result
// verification in asynchronous calls.
@ -63,9 +62,6 @@ class FindHelper : public content::WebContentsObserver {
int last_match_count_;
int last_active_ordinal_;
// Used to post synchronous result notifications to ourselves.
base::WeakPtrFactory<FindHelper> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(FindHelper);
};

@ -2477,13 +2477,22 @@ function testFindAPI() {
var loadstopListener2 = function(e) {
embedder.test.assertEq(webview.src, "about:blank");
embedder.test.succeed();
// Test find results when looking for nothing.
webview.find("", {}, function(results) {
embedder.test.assertEq(results.numberOfMatches, 0);
embedder.test.assertEq(results.activeMatchOrdinal, 0);
embedder.test.assertEq(results.selectionRect.left, 0);
embedder.test.assertEq(results.selectionRect.top, 0);
embedder.test.assertEq(results.selectionRect.width, 0);
embedder.test.assertEq(results.selectionRect.height, 0);
embedder.test.succeed();
});
}
var loadstopListener1 = function(e) {
// Test find results.
webview.find("dog", {}, function(results) {
callbackTest = true;
embedder.test.assertEq(results.numberOfMatches, 100);
embedder.test.assertTrue(results.selectionRect.width > 0);
embedder.test.assertTrue(results.selectionRect.height > 0);

@ -2774,6 +2774,12 @@ bool WebContentsImpl::IsSubframe() const {
void WebContentsImpl::Find(int request_id,
const base::string16& search_text,
const blink::WebFindOptions& options) {
// Cowardly refuse to search for no text.
if (search_text.empty()) {
NOTREACHED();
return;
}
// See if a top level browser plugin handles the find request first.
if (browser_plugin_embedder_ &&
browser_plugin_embedder_->Find(request_id, search_text, options)) {

@ -640,7 +640,7 @@ class WebContents : public PageNavigator,
// removed since we can then embed iframes in different processes.
virtual bool IsSubframe() const = 0;
// Finds text on a page.
// Finds text on a page. |search_text| should not be empty.
virtual void Find(int request_id,
const base::string16& search_text,
const blink::WebFindOptions& options) = 0;

@ -364,7 +364,6 @@ static bool DeviceScaleEnsuresTextQuality(float device_scale_factor) {
// devices main thread antialiasing is a heavy burden.
return device_scale_factor >= 1.5f;
#endif
}
static bool PreferCompositingToLCDText(CompositorDependencies* compositor_deps,
@ -672,7 +671,7 @@ void RenderViewImpl::Initialize(const ViewMsg_New_Params& params,
if (opener_view_routing_id != MSG_ROUTING_NONE && was_created_by_renderer)
opener_id_ = opener_view_routing_id;
display_mode_= params.initial_size.display_mode;
display_mode_ = params.initial_size.display_mode;
// Ensure we start with a valid next_page_id_ from the browser.
DCHECK_GE(next_page_id_, 0);
@ -2269,6 +2268,8 @@ blink::WebPlugin* RenderViewImpl::GetWebPluginForFind() {
void RenderViewImpl::OnFind(int request_id,
const base::string16& search_text,
const WebFindOptions& options) {
DCHECK(!search_text.empty());
WebFrame* main_frame = webview()->mainFrame();
blink::WebPlugin* plugin = GetWebPluginForFind();
// Check if the plugin still exists in the document.
@ -3042,7 +3043,7 @@ void RenderViewImpl::OnWasHidden() {
(*plugin_it)->SetContainerVisibility(false);
}
#endif // OS_MACOSX
#endif // ENABLE_PLUGINS
#endif // ENABLE_PLUGINS
}
void RenderViewImpl::OnWasShown(bool needs_repainting,

@ -132,6 +132,13 @@ void WebViewFindHelper::Find(
if (!full_options->findNext)
current_find_session_ = insert_result.first->second;
// Handle the empty |search_text| case internally.
if (search_text.empty()) {
guest_web_contents->StopFinding(content::STOP_FIND_ACTION_CLEAR_SELECTION);
FindReply(current_find_request_id_, 0, gfx::Rect(), 0, true);
return;
}
guest_web_contents->Find(current_find_request_id_,
search_text, *full_options);
}

@ -739,13 +739,22 @@ function testFindAPI() {
var loadstopListener2 = function(e) {
embedder.test.assertEq(webview.src, "about:blank");
embedder.test.succeed();
// Test find results when looking for nothing.
webview.find("", {}, function(results) {
embedder.test.assertEq(results.numberOfMatches, 0);
embedder.test.assertEq(results.activeMatchOrdinal, 0);
embedder.test.assertEq(results.selectionRect.left, 0);
embedder.test.assertEq(results.selectionRect.top, 0);
embedder.test.assertEq(results.selectionRect.width, 0);
embedder.test.assertEq(results.selectionRect.height, 0);
embedder.test.succeed();
});
}
var loadstopListener1 = function(e) {
// Test find results.
webview.find("dog", {}, function(results) {
callbackTest = true;
embedder.test.assertEq(results.numberOfMatches, 100);
embedder.test.assertTrue(results.selectionRect.width > 0);
embedder.test.assertTrue(results.selectionRect.height > 0);

@ -664,8 +664,8 @@ bool OutOfProcessInstance::IsPrintScalingDisabled() {
}
bool OutOfProcessInstance::StartFind(const std::string& text,
bool case_sensitive) {
engine_->StartFind(text.c_str(), case_sensitive);
bool case_sensitive) {
engine_->StartFind(text, case_sensitive);
return true;
}

@ -209,7 +209,7 @@ class PDFEngine {
uint32_t page_range_count,
const PP_PrintSettings_Dev& print_settings) = 0;
virtual void PrintEnd() = 0;
virtual void StartFind(const char* text, bool case_sensitive) = 0;
virtual void StartFind(const std::string& text, bool case_sensitive) = 0;
virtual bool SelectFindResult(bool forward) = 0;
virtual void StopFind() = 0;
virtual void ZoomUpdated(double new_zoom_level) = 0;

@ -1232,7 +1232,7 @@ void PDFiumEngine::UnsupportedFeature(int type) {
}
void PDFiumEngine::ContinueFind(int32_t result) {
StartFind(current_find_text_.c_str(), !!result);
StartFind(current_find_text_, result != 0);
}
bool PDFiumEngine::HandleEvent(const pp::InputEvent& event) {
@ -1909,16 +1909,20 @@ bool PDFiumEngine::OnChar(const pp::KeyboardInputEvent& event) {
event.GetModifiers());
}
void PDFiumEngine::StartFind(const char* text, bool case_sensitive) {
// We can get a call to StartFind before we have any page information (i.e.
void PDFiumEngine::StartFind(const std::string& text, bool case_sensitive) {
// If the caller asks StartFind() to search for no text, then this is an
// error on the part of the caller. The PPAPI Find_Private interface
// guarantees it is not empty, so this should never happen.
DCHECK(!text.empty());
// If StartFind() gets called before we have any page information (i.e.
// before the first call to LoadDocument has happened). Handle this case.
if (pages_.empty())
return;
bool first_search = false;
bool first_search = (current_find_text_ != text);
int character_to_start_searching_from = 0;
if (current_find_text_ != text) { // First time we search for this text.
first_search = true;
if (first_search) {
std::vector<PDFiumRange> old_selection = selection_;
StopFind();
current_find_text_ = text;
@ -3432,7 +3436,7 @@ void PDFiumEngine::RotateInternal() {
if (!current_find_text.empty()) {
// Clear the UI.
client_->NotifyNumberOfFindResultsChanged(0, false);
StartFind(current_find_text.c_str(), false);
StartFind(current_find_text, false);
}
}

@ -66,7 +66,7 @@ class PDFiumEngine : public PDFEngine,
uint32_t page_range_count,
const PP_PrintSettings_Dev& print_settings);
virtual void PrintEnd();
virtual void StartFind(const char* text, bool case_sensitive);
virtual void StartFind(const std::string& text, bool case_sensitive);
virtual bool SelectFindResult(bool forward);
virtual void StopFind();
virtual void ZoomUpdated(double new_zoom_level);

@ -26,6 +26,10 @@ PP_Bool StartFind(PP_Instance instance,
void* object = Instance::GetPerInstanceObject(instance, kPPPFindInterface);
if (!object)
return PP_FALSE;
if (!text || text[0] == '\0') {
PP_NOTREACHED();
return PP_FALSE;
}
bool return_value = static_cast<Find_Private*>(object)->StartFind(
text, PP_ToBool(case_sensitive));
return PP_FromBool(return_value);