Firefox-Marionette

 view release on metacpan or  search on metacpan

t/stub.pl  view on Meta::CPAN

#! /usr/bin/env perl

use strict;
use warnings;
use Getopt::Long();
use File::Spec();
use FileHandle();
use Fcntl();
use Socket();
use JSON();

MAIN: {
	my %options;
	Getopt::Long::GetOptions(\%options, 'version', 'marionette', 'headless', 'profile:s', 'no-remote', 'new-instance', 'devtools', 'safe-mode');
	my $browser_version = "112.0.2";
	if ($options{version}) {
                $| = 1;
		print "Mozilla Firefox $browser_version\n";
		exit 0;
	}
	socket my $server, Socket::PF_INET(), Socket::SOCK_STREAM(), 0 or die "Failed to create a socket:$!";
	bind $server, Socket::sockaddr_in( 0, Socket::INADDR_LOOPBACK() ) or die "Failed to bind socket:$!";
	listen $server, Socket::SOMAXCONN() or die "Failed to listen:$!";
	my $port = ( Socket::sockaddr_in( getsockname $server ) )[0];
	my $prefs_path = File::Spec->catfile($options{profile}, 'prefs.js');
	my $old_prefs_handle = FileHandle->new($prefs_path, Fcntl::O_RDONLY()) or die "Failed to open $prefs_path for reading:$!";
	my $new_prefs_path = File::Spec->catfile($options{profile}, 'prefs.new');
	my $new_prefs_handle = FileHandle->new($new_prefs_path, Fcntl::O_CREAT() | Fcntl::O_EXCL() | Fcntl::O_WRONLY(), Fcntl::S_IRUSR() | Fcntl::S_IWUSR()) or die "Failed to open $new_prefs_path for writing:$!";
	while(my $line = <$old_prefs_handle>) {
		if ($line =~ /^user_pref\("marionette.port",[ ]0\);/smx) {
			print {$new_prefs_handle} qq[user_pref("marionette.port", $port);\n] or die "Failed to write to $new_prefs_path:$!";	
		} else {
			print {$new_prefs_handle} $line or die "Failed to write to $new_prefs_path:$!";	
		}
	}
	close $new_prefs_handle or die "Failed to close $new_prefs_path:$!";
	close $old_prefs_handle or die "Failed to close $prefs_path:$!";
	rename $new_prefs_path, $prefs_path or die "Failed to rename $new_prefs_path to $prefs_path:$!";
	my $paddr = accept(my $client, $server);
	my $old = select $client; $| = 1; select $old;
	syswrite $client, qq[50:{"applicationType":"gecko","marionetteProtocol":3}] or die "Failed to write to socket:$!";
	my $request = _get_request($client);
	my $platform = $^O;
	my $headless = $options{headless} ? 'true' : 'false';
	my $response_type = 1;
	my $profile_path = $options{profile};
	$profile_path =~ s/\\/\\\\/smxg;
	my $capabilities = qq([1,1,null,{"sessionId":"5a5f9a08-0faa-4794-aa85-ee85980ce422","capabilities":{"browserName":"firefox","browserVersion":"$browser_version","platformName":"$platform","acceptInsecureCerts":false,"pageLoadStrategy":"normal","setWi...
	my $capability_length = length $capabilities;
	syswrite $client, $capability_length . q[:] . $capabilities or die "Failed to write to socket:$!";
	my $context = "content";
	my $addon_number = 0;
	while(1) {
		$request = _get_request($client);
		my $message_id = $request->[1];
		if ($request->[2] eq 'Marionette:Quit') {
			my $response_body = qq([$response_type,$message_id,null,{"cause":"shutdown","forced":false,"in_app":true}]);
			_send_response_body($client, $response_body);
			last;
		} elsif ($request->[2] eq 'Addon:Install') {
			$addon_number += 1;
			my $response_body = qq([$response_type,$message_id,null,{"value":"6eea9fdc37a5d8fbcbbecd57ee7272669e828a3${addon_number}\@temporary-addon"}]);
			_send_response_body($client, $response_body);
		} elsif ($request->[2] eq 'Addon:Uninstall') {
			$addon_number += 1;
			my $response_body = qq([$response_type,$message_id,null,{"value":null}]);
			_send_response_body($client, $response_body);
		} elsif ($request->[2] eq 'WebDriver:Print') {
			syswrite $client, qq(1475:[$response_type,$message_id,null,{"value":"JVBERi0xLjUKJbXtrvsKNCAwIG9iago8PCAvTGVuZ3RoIDUgMCBSCiAgIC9GaWx0ZXIgL0ZsYXRlRGVjb2RlCj4+CnN0cmVhbQp4nDNUMABCXUMgYW5ppJCcy1XIFahQyGVkoWdsaqQApUxNTfWMDQwVzI0hdFGqQrhCHpehAggWpSvoJx...
		} elsif ($request->[2] eq 'WebDriver:TakeScreenshot') {
			syswrite $client, qq(423:[$response_type,$message_id,null,{"value":"iVBORw0KGgoAAAANSUhEUgAABVYAAAAICAYAAAAShaQyAAAA8UlEQVR4Xu3YsQ0AIAwEMbL/0ICYgOud+isr1c2+txwBAgQIECBAgAABAgQIECBAgAABAgQIfAuMsPptZUiAAAECBAgQIECAAAECBAgQIECAAIEnIKx6BAIECBAgQIAAAQI...
		} elsif ($request->[2] eq 'Marionette:GetContext') {
			my $response_body = qq([$response_type,$message_id,null,{"value":"$context"}]);
			_send_response_body($client, $response_body);
		} elsif ($request->[2] eq 'Marionette:SetContext') {
			my $response_body = qq([$response_type,$message_id,null,{"value":null}]);
			_send_response_body($client, $response_body);
		} elsif ($request->[2] eq 'WebDriver:ExecuteScript') {
			my $response_body;
			if ($request->[3]->{script} eq 'return navigator.userAgent') {
				my $trimmed_browser_version = $browser_version;
				$trimmed_browser_version =~ s/^(\d+(?:[.]\d+)?).*$/$1/smx;
				$response_body = qq([$response_type,$message_id,null,{"value":"Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/$trimmed_browser_version"}]);
			} else {
				my $now = time;
				$response_body = qq([$response_type,$message_id,null,{"value":{"guid":"root________","index":0,"type":2,"title":"","dateAdded":$now,"lastModified":$now,"childCount":5}}]);
			}
			_send_response_body($client, $response_body);
		} else {
			die "Unsupported method in stub firefox";
		}
	}
	close $client or die "Failed to close socket:$!";
	exit 0;
}

sub _send_response_body {
	my ($client, $response_body) = @_;



( run in 1.328 second using v1.01-cache-2.11-cpan-5511b514fd6 )