go-rod / rod

A Chrome DevTools Protocol driver for web automation and scraping.
https://go-rod.github.io
MIT License
5k stars 328 forks source link

Using go-rod with firefox, failing to start new instance of firefox #1060

Open chmike opened 1 month ago

chmike commented 1 month ago

Rod Version: v0.116.0

I’m desperately trying to start a new instance of firefox with go-rod while another one is running. I keep getting the error message that firefox is running and launching firefox fails.

The code to demonstrate your question

    l := launcher.New()
    defaultFlagsToRemove := []flags.Flag{
        "disable-background-networking",
        "disable-background-timer-throttling",
        "disable-backgrounding-occluded-windows",
        "disable-breakpad",
        "disable-client-side-phishing-detection",
        "disable-component-extensions-with-background-pages",
        "disable-default-apps",
        "disable-dev-shm-usage",
        "disable-features",
        "disable-hang-monitor",
        "disable-ipc-flooding-protection",
        "disable-popup-blocking",
        "disable-prompt-on-repost",
        "disable-renderer-backgrounding",
        "disable-sync",
        "enable-automation",
        "enable-features",
        "force-color-profile",
        "metrics-recording-only",
        "no-first-run",
        "no-startup-window",
        "use-mock-keychain",
        "headless",
    }
    for _, flag := range defaultFlagsToRemove {
        l.Delete(flag)
    }
    fmt.Printf("u after del: %v\n", l.Flags)
    l.Bin(pathToFirefoxBin).
        Set("profile", profileDir).
        Set("new-instance").
        Set("remote-debugging-port", "9333").
        Headless(false).
        Leakless(true)
    fmt.Printf("u after set: %v\n", l.Flags)
    u := l.MustLaunch()

What you got

The program fails at MustLaunch by claiming that firefox is already running. I do indeed have a running instance of firefox. I want to start a new instance with the given profile which I created manually.

When I execute the command in the bash shell, it works.

firefox --profile /home/.../Data/nz5ijj7z.profile  --new-instance --remote-debugging-port 9333

This is the output I get

5:25 $ firefox --profile /home/.../Data/nz5ijj7z.profile  --new-instance --remote-debugging-port 9333
Gtk-Message: 15:32:13.732: Not loading module "atk-bridge": The functionality is provided by GTK natively. Please try to not load it.
[76355, Main Thread] WARNING: GTK+ module /snap/firefox/4173/gnome-platform/usr/lib/gtk-2.0/modules/libcanberra-gtk-module.so cannot be loaded.
GTK+ 2.x symbols detected. Using GTK+ 2.x and GTK+ 3 in the same process is not supported.: 'glib warning', file /build/firefox/parts/firefox/build/toolkit/xre/nsSigHandlers.cpp:187

(firefox:76355): Gtk-WARNING **: 15:32:13.775: GTK+ module /snap/firefox/4173/gnome-platform/usr/lib/gtk-2.0/modules/libcanberra-gtk-module.so cannot be loaded.
GTK+ 2.x symbols detected. Using GTK+ 2.x and GTK+ 3 in the same process is not supported.
Gtk-Message: 15:32:13.775: Failed to load module "canberra-gtk-module"
[76355, Main Thread] WARNING: GTK+ module /snap/firefox/4173/gnome-platform/usr/lib/gtk-2.0/modules/libcanberra-gtk-module.so cannot be loaded.
GTK+ 2.x symbols detected. Using GTK+ 2.x and GTK+ 3 in the same process is not supported.: 'glib warning', file /build/firefox/parts/firefox/build/toolkit/xre/nsSigHandlers.cpp:187

(firefox:76355): Gtk-WARNING **: 15:32:13.776: GTK+ module /snap/firefox/4173/gnome-platform/usr/lib/gtk-2.0/modules/libcanberra-gtk-module.so cannot be loaded.
GTK+ 2.x symbols detected. Using GTK+ 2.x and GTK+ 3 in the same process is not supported.
Gtk-Message: 15:32:13.776: Failed to load module "canberra-gtk-module"
WebDriver BiDi listening on ws://127.0.0.1:9333
DevTools listening on ws://127.0.0.1:9333/devtools/browser/d195eb77-9ea9-4c6b-a489-5a3627f3a73b
-

A new instance of firefox is thus started without problem manually.

What have you tried to solve the question

I tried to start a new instance of firefox myself with the following code and it succeeds.

func startFirefox() {
    err := exec.Command("/usr/bin/firefox", "--profile", "/home/.../Data/nz5ijj7z.profile", "--new-instance").Run()
    if err != nil {
        panic(err)
    }
}

Thus go-rod is doing something that prohibits firefox to start.

Maybe my startFirefox() function is different from what go-doc is doing. I saw for instance that input and output pipes are redirected.

chmike commented 1 month ago

The following code uses os.StartProcess as go-rod and succeeds in starting an independent instance.

// From https://gist.github.com/lee8oi/ec404fa99ea0f6efd9d1
func Start(args ...string) (p *os.Process, err error) {
    if args[0], err = exec.LookPath(args[0]); err == nil {
        var procAttr os.ProcAttr
        procAttr.Files = []*os.File{os.Stdin,
            os.Stdout, os.Stderr}
        p, err := os.StartProcess(args[0], args, &procAttr)
        if err == nil {
            return p, nil
        }
    }
    return nil, err
}

func startFirefox2() {
    p, err := Start("firefox", "--profile", "/home/.../Data/nz5ijj7z.profile", "--new-instance")
    if err != nil {
        panic(err)
    }
    p.Wait()
}

Trying to start firefox with go-rod and Leakless(false) fails. I still get the error that firefox is already running. But getting the debug port given in the parameters succeeds.

ysmood commented 1 month ago

https://go-rod.github.io/#/compatibility?id=supported-browsers

https://github.com/go-rod/rod/issues/193

chmike commented 1 month ago

I finally identified the cause.

Firefox ignores the argument --profile if its value is attached with =. Surprisingly, it doesn’t ignore the --remote-debugging-port=9333 argument. It does open the port 9333.

This is a limitation of firefox with the --profile parameter. There may be other parameters like that.

The following code does nearly everything like go-rod except that the profile parameter is properly separated. It then works and port 9333 is opened.

func Start(bin string, args ...string) (p *os.Process, err error) {
    cmd := exec.Command(bin, args...)
    cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
    cmd.Stdout = io.MultiWriter(io.Discard, launcher.NewURLParser())
    cmd.Stderr = io.MultiWriter(io.Discard, launcher.NewURLParser())
    err = cmd.Start()
    if err != nil {
        return
    }
    return cmd.Process, err
}

func startFirefox2() {
    p, err := Start("/usr/bin/firefox", "--new-instance", "--profile", profileDir, "--remote-debugging-port=9333")
    if err != nil {
        panic(err)
    }
    p.Wait()
}

I don’t know if there can be a quick fix to use go-rod with firefox. As I can’t test the code beyond that I don’t know.

chmike commented 1 month ago

Bug filed at bugzilla

chmike commented 1 month ago

So apparently, firefox is not supported by go-rod because of another problem. Sorry to hear that.

chmike commented 1 month ago

I’m in the process to fix the firefox command line limitation myself so that it will support "--option=param" arguments as needed for go-rod. The code fix is written and going through the review process.