JDK-8264698 : HostServices.showDocument() should throw exception if browser fails to launch
  • Type: Enhancement
  • Component: javafx
  • Sub-Component: other
  • Affected Version: openjfx11
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: linux
  • CPU: x86_64
  • Submitted: 2021-03-27
  • Updated: 2021-04-07
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdUnresolved
Description
ADDITIONAL SYSTEM INFORMATION :
From what I can tell, it is present on OSes and versions of JavaFX.

A DESCRIPTION OF THE PROBLEM :
If an exception occurs in the showDocument() method (e.g. SecurityException or Exception("No web browser found")), it is not passed to the caller. Instead, a stack trace is printed and execution proceeds.  A comment in the catch block states "should not happen" even though the method itself could raise an exception.  

Searching the bug database, I find a somewhat related bug (JDK-1262595) that stated:

"showDocument() calls the browser to display the URL, but the browser may not return any notification back when the URL is invalid or failed to be displayed. This is why showDocument() doesn't currently throw exception in the API. Will not fix."

I think this logic may have been approriate in 1996, but does not apply today--particularly with the SecurityException framework.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1) Create an application that uses a security controller that does not grant the execute permission or run on a system without a browser installed.

2) Call the HostServices.showDocument() method in a try/catch block.

3) Execute the application

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
A SecurityException or the "No web browser found" exceptions should be passed to the caller.
ACTUAL -
Execution proceeds without exception.

---------- BEGIN SOURCE ----------
package com.example.showdocbug;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

/**
 * JavaFX App
 */
public class App extends Application {

    @Override
    public void start(Stage stage) {
        var policy = App.class.getResource("demo.policy");
        System.setProperty(
                "java.security.policy",
                policy.toString());
        System.setSecurityManager(new SecurityManager());

        try {
            getHostServices().showDocument("irrelevant");

            var label = new Label("Should not see this");
            var scene = new Scene(new StackPane(label), 640, 480);
            stage.setScene(scene);
            stage.show();
        } catch (Exception e) {
            var label = new Label("Should see this");
            var scene = new Scene(new StackPane(label), 640, 480);
            stage.setScene(scene);
            stage.show();
        }
    }

    public static void main(String[] args) {
        launch();
    }
}

// put in the resources location
// demo.policy
// Security Policy for the Data Manager Tool

// NOTE: Some of the permissions may span grant {} blocks

// Debugging--might be able to turn off in production
grant {
  permission java.util.PropertyPermission "jdk.proxy.debug", "read";
};

// Access for files inside the JRE and other fundamental items
grant {
  // Allow reading of JRE files
  permission java.util.PropertyPermission "java.home",      "read";
  permission java.io.FilePermission       "${java.home}/-", "read";
  // System resources--OS dependent
  // Linux
  permission java.io.FilePermission       "/etc/-", "read";
  permission java.io.FilePermission       "/usr/share/-", "read";
  permission java.io.FilePermission       "/dev/random",  "read";
  permission java.io.FilePermission       "/dev/urandom", "read";
  // MacOS
  permission java.io.FilePermission       "/System/Library/Fonts/-", "read";
  // Windows
  // NOTE: Do not forget to escape the '\' character by using "\\"
  permission java.io.FilePermission       "C:\\WINDOWS\\Fonts\\-", "read";
  permission java.io.FilePermission       "${user.home}/.m2/-", "read";
};

// SecurityManager
grant {
  permission java.security.SecurityPermission "getPolicy";
};

// JavaFX
grant {
  permission java.util.PropertyPermission "javafx.*",              "read,write";
  permission java.util.PropertyPermission "com.sun.javafx.*",      "read";
  permission java.util.PropertyPermission "embedded",              "read";
  permission java.util.PropertyPermission "use.*",                 "read";
  permission java.util.PropertyPermission "quantum.*",             "read";
  permission java.util.PropertyPermission "glass.*",               "read";
  permission java.util.PropertyPermission "decora.*",              "read";
  permission java.util.PropertyPermission "prism.*",               "read";
  permission java.util.PropertyPermission "java.library.path",     "read";
  permission java.util.PropertyPermission "javax.xml.*",           "read";
  permission java.util.PropertyPermission "jdk.xml.*",             "read";
  permission java.util.PropertyPermission "binary.css",            "read";
  permission java.util.PropertyPermission "entityExpansionLimit",  "read";
  permission java.util.PropertyPermission "maxOccurLimit",         "read";
  permission java.util.PropertyPermission "elementAttributeLimit", "read";

  permission java.lang.RuntimePermission  "modifyThread";
  permission java.lang.RuntimePermission  "shutdownHooks";
  permission java.lang.RuntimePermission  "getStackWalkerWithClassReference";
  permission java.lang.RuntimePermission  "loadLibrary.*";
  permission java.lang.RuntimePermission  "getClassLoader";
  permission java.lang.RuntimePermission  "accessDeclaredMembers";
  permission java.lang.RuntimePermission  "getProtectionDomain";
  permission java.lang.RuntimePermission  "modifyThreadGroup";
  permission java.lang.RuntimePermission  "setContextClassLoader";
  permission java.lang.RuntimePermission  "accessSystemModules";
  permission java.lang.RuntimePermission  "createClassLoader";
  permission java.lang.RuntimePermission  "localeServiceProvider";
  permission java.lang.RuntimePermission  "enableContextClassLoaderOverride";
  permission java.lang.RuntimePermission  "accessClassInPackage.sun.misc";
  permission java.lang.RuntimePermission  "getenv.glass.*";

  permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
  
  permission javafx.util.FXPermission     "createTransparentWindow";
  permission javafx.util.FXPermission     "accessWindowList";

  // Are these JavaFX?
  permission java.security.SecurityPermission "getProperty.security.provider.*";
  permission java.security.SecurityPermission "getProperty.jdk.security.provider.preferred";
  permission java.security.SecurityPermission "getProperty.securerandom.source";
  permission java.security.SecurityPermission "putProviderProperty.SUN";

  // Are these only needed when running with the JDK?
  permission java.util.PropertyPermission "jdk.proxy.ProxyGenerator.saveGeneratedFiles", "read";
  permission java.util.PropertyPermission "sun.reflect.debugModuleAccessChecks", "read";
};


// File and Network I/O
grant {
  permission java.util.PropertyPermission "file.encoding", "read";

  permission java.lang.RuntimePermission  "readFileDescriptor";
  permission java.lang.RuntimePermission  "writeFileDescriptor";
  permission java.lang.RuntimePermission  "selectorProvider";

  // Needed for ACL permissions
  permission java.lang.RuntimePermission  "lookupUserInformation";

  // Allow access to the user properties
  permission java.util.PropertyPermission "user.*", "read";

  // Enable access to logging
  permission java.util.logging.LoggingPermission "control";
  permission java.lang.RuntimePermission  "loggerFinder";

  permission java.io.FilePermission       "${user.home}",   "read,write,delete";
  permission java.io.FilePermission       "${user.home}/-", "read,write,delete";
};

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Need to wrap the showDocument() to check for security permission, but that does not help with the browser not found exception.

FREQUENCY : always



Comments
JDK-1262595 refers to AppletContent::showDocument in AWT, so it isn't directly relevant. As noted in that issue, we can't do anything about any error condition that the browser itself might encounter after it is launched. Leaving that aside, this issue (JDK-8264698) is about errors that occur while launching the browser. Worth noting is that the HostServices::showDocument method is not documented to throw any exceptions, so the fact that the implementation swallows any exceptions that happen while launching the browser, rather than throwing them back to the user (in those cases where it is even possible), is therefore an Enhancement request not a Bug. This will require a CSR to change the API docs for showDocument to indicate that it might throw an exception if the browser cannot be located or if launching the browser fails for some reason. I am changing the issue type to Enhancement and lowering it to P4. There are currently no plans to implement this.
07-04-2021

Checked with attached testcase in ubuntu 20.04, caught with following exception- at java.base/java.security.AccessControlContext.checkPermission(AccessControlContext.java:472) at java.base/java.security.AccessController.checkPermission(AccessController.java:1036) at java.base/java.lang.SecurityManager.checkPermission(SecurityManager.java:408) at java.base/java.lang.SecurityManager.checkExec(SecurityManager.java:658) at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1098) at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1073) at java.base/java.lang.Runtime.exec(Runtime.java:590) at java.base/java.lang.Runtime.exec(Runtime.java:449) at javafx.graphics/com.sun.javafx.application.HostServicesDelegate$StandaloneHostService.showDocument(HostServicesDelegate.java:146) at javafx.graphics/javafx.application.HostServices.showDocument(HostServices.java:115) at App.start(App.java:22) at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846) at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:474) at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:447) at java.base/java.security.AccessController.doPrivileged(AccessController.java:391) at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:446) at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96) at javafx.graphics/com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method) at javafx.graphics/com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$11(GtkApplication.java:277) at java.base/java.lang.Thread.run(Thread.java:831)
05-04-2021