Commit 8eca0885 authored by Kurt Horimoto's avatar Kurt Horimoto Committed by Commit Bot

[iOS] Reset OverlayRequestMediator.request when it's cancelled.

A destruction callback is used to reset the reference to a
mediator's OverlayRequest upon destruction.  When a request
is cancelled, it is immediately removed from its queue and
destroyed, but it's possible for the UI to outlive the request
while it's being dismissed.  This CL adds early returns to
prevent accessing the request after destruction.

Bug: none
Change-Id: I256f17e35572c168aecf8c714601ceb17153ceb8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1963439
Commit-Queue: Kurt Horimoto <kkhorimoto@chromium.org>
Reviewed-by: default avatarMike Dougherty <michaeldo@chromium.org>
Auto-Submit: Kurt Horimoto <kkhorimoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#726063}
parent ae311dd1
......@@ -65,6 +65,7 @@ source_set("coordinators") {
deps = [
"//base",
"//ios/chrome/browser/overlays",
"//ios/chrome/browser/ui/coordinators:chrome_coordinators",
]
}
......@@ -72,6 +73,7 @@ source_set("coordinators") {
source_set("unit_tests") {
testonly = true
sources = [
"overlay_request_mediator_unittest.mm",
"overlay_request_ui_state_unittest.mm",
]
......
......@@ -21,7 +21,8 @@ class OverlayRequest;
NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
// The request passed on initialization.
// The request passed on initialization. Reset to nullptr if the request is
// cancelled while its overlay UI is still visible.
@property(nonatomic, readonly) OverlayRequest* request;
// The delegate.
......
......@@ -4,20 +4,42 @@
#import "ios/chrome/browser/ui/overlays/overlay_request_mediator.h"
#include "base/bind.h"
#include "base/logging.h"
#include "ios/chrome/browser/overlays/public/overlay_callback_manager.h"
#include "ios/chrome/browser/overlays/public/overlay_request.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@interface OverlayRequestMediator ()
// Redefine property as readwrite.
@property(nonatomic, readwrite) OverlayRequest* request;
@end
@implementation OverlayRequestMediator
- (instancetype)initWithRequest:(OverlayRequest*)request {
if (self = [super init]) {
_request = request;
DCHECK(_request);
_request->GetCallbackManager()->AddCompletionCallback(
[self requestCompletionCallback]);
}
return self;
}
#pragma mark - Private
// Returns an OverlayCompletionCallback to reset the request pointer upon
// destruction to prevent it from being used in the event of overlay UI user
// interaction events that occur during dismissal after a request has been
// cancelled.
- (OverlayCompletionCallback)requestCompletionCallback {
__weak __typeof(self) weakSelf = self;
return base::BindOnce(^(OverlayResponse*) {
weakSelf.request = nullptr;
});
}
@end
// Copyright 2019 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.
#import "ios/chrome/browser/ui/overlays/overlay_request_mediator.h"
#include "ios/chrome/browser/overlays/public/overlay_request.h"
#include "ios/chrome/browser/overlays/test/fake_overlay_user_data.h"
#include "testing/platform_test.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
// Test fixture for OverlayRequestMediator.
using OverlayRequestMediatorTest = PlatformTest;
// Tests that the mediator's request is reset after destruction.
TEST_F(OverlayRequestMediatorTest, ResetRequestAfterDestruction) {
std::unique_ptr<OverlayRequest> request =
OverlayRequest::CreateWithConfig<FakeOverlayUserData>(nullptr);
OverlayRequestMediator* mediator =
[[OverlayRequestMediator alloc] initWithRequest:request.get()];
EXPECT_EQ(request.get(), mediator.request);
request = nullptr;
EXPECT_EQ(nullptr, mediator.request);
}
......@@ -41,12 +41,16 @@
#pragma mark - Accessors
- (AppLauncherAlertOverlayRequestConfig*)config {
return self.request->GetConfig<AppLauncherAlertOverlayRequestConfig>();
return self.request
? self.request->GetConfig<AppLauncherAlertOverlayRequestConfig>()
: nullptr;
}
#pragma mark - Response helpers
- (void)updateResponseAllowingAppLaunch:(BOOL)allowAppLaunch {
if (!self.request)
return;
self.request->GetCallbackManager()->SetCompletionResponse(
OverlayResponse::CreateWithInfo<AppLauncherAlertOverlayResponseInfo>(
allowAppLaunch));
......
......@@ -44,12 +44,15 @@
#pragma mark - Accessors
- (HTTPAuthOverlayRequestConfig*)config {
return self.request->GetConfig<HTTPAuthOverlayRequestConfig>();
return self.request ? self.request->GetConfig<HTTPAuthOverlayRequestConfig>()
: nullptr;
}
#pragma mark - Response helpers
- (void)updateResponseCancelled:(BOOL)cancelled {
if (!self.request)
return;
std::unique_ptr<OverlayResponse> response;
if (!cancelled) {
std::string user =
......
......@@ -39,7 +39,9 @@
#pragma mark - Accessors
- (JavaScriptAlertOverlayRequestConfig*)config {
return self.request->GetConfig<JavaScriptAlertOverlayRequestConfig>();
return self.request
? self.request->GetConfig<JavaScriptAlertOverlayRequestConfig>()
: nullptr;
}
@end
......
......@@ -42,13 +42,18 @@
#pragma mark - Accessors
- (JavaScriptConfirmationOverlayRequestConfig*)config {
return self.request->GetConfig<JavaScriptConfirmationOverlayRequestConfig>();
return self.request
? self.request
->GetConfig<JavaScriptConfirmationOverlayRequestConfig>()
: nullptr;
}
#pragma mark - Response helpers
// Sets the OverlayResponse using the user's selection from the confirmation UI.
- (void)setConfirmationResponse:(BOOL)dialogConfirmed {
if (!self.request)
return;
self.request->GetCallbackManager()->SetCompletionResponse(
OverlayResponse::CreateWithInfo<
JavaScriptConfirmationOverlayResponseInfo>(dialogConfirmed));
......
......@@ -46,12 +46,16 @@
#pragma mark - Accessors
- (JavaScriptPromptOverlayRequestConfig*)config {
return self.request->GetConfig<JavaScriptPromptOverlayRequestConfig>();
return self.request
? self.request->GetConfig<JavaScriptPromptOverlayRequestConfig>()
: nullptr;
}
#pragma mark - Response helpers
- (void)setPromptResponse:(NSString*)textInput {
if (!self.request)
return;
self.request->GetCallbackManager()->SetCompletionResponse(
OverlayResponse::CreateWithInfo<JavaScriptPromptOverlayResponseInfo>(
base::SysNSStringToUTF8(textInput)));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment