Skip to content

Commit bdfc2e6

Browse files
committed
gh-137586: Replace _macos_default_browser_bundle_id with plistlib to address memory and os.fork() concerns
1 parent 98dd1d8 commit bdfc2e6

1 file changed

Lines changed: 17 additions & 64 deletions

File tree

Lib/webbrowser.py

Lines changed: 17 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -617,74 +617,27 @@ def open(self, url, new=0, autoraise=True):
617617

618618
if sys.platform == 'darwin':
619619
def _macos_default_browser_bundle_id():
620-
"""Return the bundle ID of the default web browser via NSWorkspace.
620+
"""Return the bundle ID of the default web browser.
621621
622-
Uses the Objective-C runtime directly to call
623-
NSWorkspace.sharedWorkspace().URLForApplicationToOpenURL() with a
624-
probe https:// URL, then reads the bundle identifier from the
625-
resulting NSBundle. Returns None if ctypes is unavailable or the
626-
lookup fails for any reason.
622+
Reads the LaunchServices preferences file that macOS maintains
623+
when the user sets a default browser. Returns None if the file
624+
is absent or no https handler is recorded.
627625
"""
626+
import plistlib, os
627+
plist = os.path.expanduser(
628+
'~/Library/Preferences/com.apple.LaunchServices/'
629+
'com.apple.launchservices.secure.plist'
630+
)
628631
try:
629-
from ctypes import cdll, c_void_p, c_char_p
630-
from ctypes.util import find_library
631-
632-
# NSWorkspace is an AppKit class; load AppKit to register it.
633-
cdll.LoadLibrary(
634-
'/System/Library/Frameworks/AppKit.framework/AppKit'
635-
)
636-
objc = cdll.LoadLibrary(find_library('objc'))
637-
objc.objc_getClass.restype = c_void_p
638-
objc.sel_registerName.restype = c_void_p
639-
objc.objc_msgSend.restype = c_void_p
640-
641-
def cls(name):
642-
return objc.objc_getClass(name)
643-
644-
def sel(name):
645-
return objc.sel_registerName(name)
646-
647-
# Build probe NSURL for "https://python.org"
648-
NSString = cls(b'NSString')
649-
objc.objc_msgSend.argtypes = [c_void_p, c_void_p, c_char_p]
650-
ns_str = objc.objc_msgSend(
651-
NSString, sel(b'stringWithUTF8String:'), b'https://python.org'
652-
)
653-
654-
NSURL = cls(b'NSURL')
655-
objc.objc_msgSend.argtypes = [c_void_p, c_void_p, c_void_p]
656-
probe_url = objc.objc_msgSend(NSURL, sel(b'URLWithString:'), ns_str)
657-
658-
# Ask NSWorkspace which app handles https://
659-
NSWorkspace = cls(b'NSWorkspace')
660-
objc.objc_msgSend.argtypes = [c_void_p, c_void_p]
661-
workspace = objc.objc_msgSend(NSWorkspace, sel(b'sharedWorkspace'))
662-
if not workspace:
663-
return None
664-
665-
objc.objc_msgSend.argtypes = [c_void_p, c_void_p, c_void_p]
666-
app_url = objc.objc_msgSend(
667-
workspace, sel(b'URLForApplicationToOpenURL:'), probe_url
668-
)
669-
if not app_url:
670-
return None
671-
672-
# Get bundle identifier from that app's NSBundle
673-
NSBundle = cls(b'NSBundle')
674-
bundle = objc.objc_msgSend(NSBundle, sel(b'bundleWithURL:'), app_url)
675-
if not bundle:
676-
return None
677-
678-
objc.objc_msgSend.argtypes = [c_void_p, c_void_p]
679-
bundle_id_ns = objc.objc_msgSend(bundle, sel(b'bundleIdentifier'))
680-
if not bundle_id_ns:
681-
return None
682-
683-
objc.objc_msgSend.restype = c_char_p
684-
bundle_id_bytes = objc.objc_msgSend(bundle_id_ns, sel(b'UTF8String'))
685-
return bundle_id_bytes.decode() if bundle_id_bytes else None
632+
with open(plist, 'rb') as f:
633+
data = plistlib.load(f)
634+
for handler in data.get('LSHandlers', []):
635+
if handler.get('LSHandlerURLScheme') == 'https':
636+
return (handler.get('LSHandlerRoleAll')
637+
or handler.get('LSHandlerRoleViewer'))
686638
except Exception:
687-
return None
639+
pass
640+
return None
688641

689642
class MacOSX(BaseBrowser):
690643
"""Launcher class for macOS browsers, using /usr/bin/open.

0 commit comments

Comments
 (0)