diff options
author | avi@chromium.org <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-06 19:33:07 +0000 |
---|---|---|
committer | avi@chromium.org <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-06 19:33:07 +0000 |
commit | 98299483b0b891bc245c946b5bf2608e5904db25 (patch) | |
tree | dd5368ae5e49127d21eb3db2210a8610d8b3b441 /chrome/browser | |
parent | 3d9d4558ac5f0e5f34269f37c5e5536bf221eb87 (diff) | |
download | chromium_src-98299483b0b891bc245c946b5bf2608e5904db25.zip chromium_src-98299483b0b891bc245c946b5bf2608e5904db25.tar.gz chromium_src-98299483b0b891bc245c946b5bf2608e5904db25.tar.bz2 |
External protocol dialog support for the Mac.
BUG=http://crbug.com/15546
TEST=try to use an external protocol; it should put up a dialog
Review URL: http://codereview.chromium.org/256065
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@28145 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/cocoa/external_protocol_dialog.h | 19 | ||||
-rw-r--r-- | chrome/browser/cocoa/external_protocol_dialog.mm | 148 | ||||
-rw-r--r-- | chrome/browser/external_protocol_handler.cc | 27 | ||||
-rw-r--r-- | chrome/browser/external_protocol_handler.h | 3 |
4 files changed, 193 insertions, 4 deletions
diff --git a/chrome/browser/cocoa/external_protocol_dialog.h b/chrome/browser/cocoa/external_protocol_dialog.h new file mode 100644 index 0000000..224c280 --- /dev/null +++ b/chrome/browser/cocoa/external_protocol_dialog.h @@ -0,0 +1,19 @@ +// Copyright (c) 2009 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 <Cocoa/Cocoa.h> + +#include "base/time.h" +#include "googleurl/src/gurl.h" + +@interface ExternalProtocolDialogController : NSObject { + @private + NSAlert* alert_; + GURL url_; + base::Time creation_time_; +}; + +- (id)initWithGURL:(const GURL*)url; + +@end diff --git a/chrome/browser/cocoa/external_protocol_dialog.mm b/chrome/browser/cocoa/external_protocol_dialog.mm new file mode 100644 index 0000000..444cd2c --- /dev/null +++ b/chrome/browser/cocoa/external_protocol_dialog.mm @@ -0,0 +1,148 @@ +// Copyright (c) 2009 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 "chrome/browser/cocoa/external_protocol_dialog.h" + +#include "app/l10n_util_mac.h" +#include "base/message_loop.h" +#include "base/sys_string_conversions.h" +#include "chrome/browser/external_protocol_handler.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" + +/////////////////////////////////////////////////////////////////////////////// +// ExternalProtocolHandler + +// static +void ExternalProtocolHandler::RunExternalProtocolDialog( + const GURL& url, int render_process_host_id, int routing_id) { + [[ExternalProtocolDialogController alloc] initWithGURL:&url]; +} + +/////////////////////////////////////////////////////////////////////////////// +// ExternalProtocolDialogController + +@interface ExternalProtocolDialogController(Private) +- (void)alertEnded:(NSAlert *)alert + returnCode:(int)returnCode + contextInfo:(void*)contextInfo; +- (string16)appNameForProtocol; +@end + +@implementation ExternalProtocolDialogController +- (id)initWithGURL:(const GURL*)url { + DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type()); + + url_ = *url; + creation_time_ = base::Time::Now(); + + string16 appName = [self appNameForProtocol]; + if (appName.length() == 0) { + // No registered apps for this protocol; give up and go home. + [self autorelease]; + return nil; + } + + alert_ = [[NSAlert alloc] init]; + + [alert_ setMessageText: + l10n_util::GetNSStringWithFixup(IDS_EXTERNAL_PROTOCOL_TITLE)]; + + NSButton* allowButton = [alert_ addButtonWithTitle: + l10n_util::GetNSStringWithFixup(IDS_EXTERNAL_PROTOCOL_OK_BUTTON_TEXT)]; + [allowButton setKeyEquivalent:@""]; // disallow as default + [alert_ addButtonWithTitle: + l10n_util::GetNSStringWithFixup(IDS_CANCEL)]; + + NSString* urlString = l10n_util::GetNSStringFWithFixup( + IDS_EXTERNAL_PROTOCOL_INFORMATION, + ASCIIToUTF16(url_.scheme() + ":"), + ASCIIToUTF16(url_.possibly_invalid_spec())); + NSString* appString = l10n_util::GetNSStringFWithFixup( + IDS_EXTERNAL_PROTOCOL_APPLICATION_TO_LAUNCH, + appName); + NSString* warningString = + l10n_util::GetNSStringWithFixup(IDS_EXTERNAL_PROTOCOL_WARNING); + NSString* informativeText = + [NSString stringWithFormat:@"%@\n\n%@\n\n%@", + urlString, + appString, + warningString]; + + [alert_ setInformativeText:informativeText]; + + [alert_ setShowsSuppressionButton:YES]; + [[alert_ suppressionButton] setTitle: + l10n_util::GetNSStringWithFixup(IDS_EXTERNAL_PROTOCOL_CHECKBOX_TEXT)]; + + [alert_ beginSheetModalForWindow:nil // nil here makes it app-modal + modalDelegate:self + didEndSelector:@selector(alertEnded:returnCode:contextInfo:) + contextInfo:nil]; + + return self; +} + +- (void)dealloc { + [alert_ release]; + + [super dealloc]; +} + +- (void)alertEnded:(NSAlert *)alert + returnCode:(int)returnCode + contextInfo:(void*)contextInfo { + ExternalProtocolHandler::BlockState blockState = + ExternalProtocolHandler::UNKNOWN; + switch (returnCode) { + case NSAlertFirstButtonReturn: + blockState = ExternalProtocolHandler::DONT_BLOCK; + break; + case NSAlertSecondButtonReturn: + blockState = ExternalProtocolHandler::BLOCK; + break; + default: + NOTREACHED(); + } + + // Set the "don't warn me again" info if the protocol was blocked ("cancel" + // always means "make this dialog go away with no permanent effect" no matter + // what). + if ([[alert_ suppressionButton] state] == NSOnState && + blockState == ExternalProtocolHandler::BLOCK) { + ExternalProtocolHandler::SetBlockState(UTF8ToWide(url_.scheme()), + blockState); + } + + if (blockState == ExternalProtocolHandler::DONT_BLOCK) { + UMA_HISTOGRAM_LONG_TIMES("clickjacking.launch_url", + base::Time::Now() - creation_time_); + + ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(url_); + } + + [self autorelease]; +} + +- (string16)appNameForProtocol { + NSURL* url = [NSURL URLWithString: + base::SysUTF8ToNSString(url_.possibly_invalid_spec())]; + CFURLRef openingApp = NULL; + OSStatus status = LSGetApplicationForURL((CFURLRef)url, + kLSRolesAll, + NULL, + &openingApp); + if (status != noErr) { + // likely kLSApplicationNotFoundErr + return string16(); + } + NSString* appPath = [(NSURL*)openingApp path]; + CFRelease(openingApp); // NOT A BUG; LSGetApplicationForURL retains for us + NSString* appDisplayName = + [[NSFileManager defaultManager] displayNameAtPath:appPath]; + + return base::SysNSStringToUTF16(appDisplayName); +} + +@end diff --git a/chrome/browser/external_protocol_handler.cc b/chrome/browser/external_protocol_handler.cc index b16c081..7a960c9 100644 --- a/chrome/browser/external_protocol_handler.cc +++ b/chrome/browser/external_protocol_handler.cc @@ -90,7 +90,7 @@ ExternalProtocolHandler::BlockState ExternalProtocolHandler::GetBlockState( } // Check the stored prefs. - // TODO(pkasting): http://b/119651 This kind of thing should go in the + // TODO(pkasting): http://b/1119651 This kind of thing should go in the // preferences on the profile, not in the local state. PrefService* pref = g_browser_process->local_state(); if (pref) { // May be NULL during testing. @@ -110,6 +110,25 @@ ExternalProtocolHandler::BlockState ExternalProtocolHandler::GetBlockState( } // static +void ExternalProtocolHandler::SetBlockState(const std::wstring& scheme, + BlockState state) { + // Set in the stored prefs. + // TODO(pkasting): http://b/1119651 This kind of thing should go in the + // preferences on the profile, not in the local state. + PrefService* pref = g_browser_process->local_state(); + if (pref) { // May be NULL during testing. + DictionaryValue* win_pref = + pref->GetMutableDictionary(prefs::kExcludedSchemes); + CHECK(win_pref); + + if (state == UNKNOWN) + win_pref->Remove(scheme, NULL); + else + win_pref->SetBoolean(scheme, state == BLOCK ? true : false); + } +} + +// static void ExternalProtocolHandler::LaunchUrl(const GURL& url, int render_process_host_id, int tab_contents_id) { @@ -124,7 +143,7 @@ void ExternalProtocolHandler::LaunchUrl(const GURL& url, return; if (block_state == UNKNOWN) { -#if defined(OS_WIN) || defined(TOOLKIT_GTK) +#if defined(OS_WIN) || defined(TOOLKIT_GTK) || defined(OS_MACOSX) g_accept_requests = false; // Ask the user if they want to allow the protocol. This will call // LaunchUrlWithoutSecurityCheck if the user decides to accept the protocol. @@ -132,8 +151,8 @@ void ExternalProtocolHandler::LaunchUrl(const GURL& url, render_process_host_id, tab_contents_id); #endif - // For now, allow only whitelisted protocols to fire on Mac and Linux/Views. - // See http://crbug.com/15546. + // For now, allow only whitelisted protocols to fire on Linux/Views. + // See http://crbug.com/23853 . return; } diff --git a/chrome/browser/external_protocol_handler.h b/chrome/browser/external_protocol_handler.h index 5f3a078..20c82bc 100644 --- a/chrome/browser/external_protocol_handler.h +++ b/chrome/browser/external_protocol_handler.h @@ -23,6 +23,9 @@ class ExternalProtocolHandler { // Returns whether we should block a given scheme. static BlockState GetBlockState(const std::wstring& scheme); + // Sets whether we should block a given scheme. + static void SetBlockState(const std::wstring& scheme, BlockState state); + // Checks to see if the protocol is allowed, if it is whitelisted, // the application associated with the protocol is launched on the io thread, // if it is blacklisted, returns silently. Otherwise, an |