Cookies-Roundtrip

 view release on metacpan or  search on metacpan

lib/Cookies/Roundtrip.pm  view on Meta::CPAN

	# we need to find the class of the cookie jar of mech
	# this is probably unsupported but there is no other way:
	my $cookie_jar_class = $ua->{'cookie_jar_class'};

	my $ua_cookies;
	if( ! defined($ua_cookies=$ua->cookie_jar) ){
		# there is no cookiejar in $ua, make one and insert it into mech
		if( ! defined($ua_cookies=$cookie_jar_class->new()) ){ print STDERR "${whoami}, line ".__LINE__." (via $parent): error, call to ".'HTTP::Cookies->new()'." has failed.\n"; return undef }
		$ua->cookie_jar($ua_cookies);
	}

	# by now $ua has a cookie_jar (fresh or already there)
	# and this is the cookie jar we supply to the sub below
	# to load the input cookies
	if( $cookie_jar_class eq 'HTTP::Cookies' ){
		# we have a cookiejar entering a cookies in mech, need to convert
		if( ! defined httpcookiejar2httpcookies($httpcookiejar, $ua_cookies, $skip_discard, $verbosity) ){ print STDERR "--begin HTTP::Cookies:\n".as_string_httpcookies($httpcookiejar)."\n--end cookies.\n\n"."${whoami}, line ".__LINE__." (via $parent): err...
	} elsif( ($cookie_jar_class eq 'HTTP::CookieJar') || ($cookie_jar_class eq 'HTTP::CookieJar::LWP') ){
		# we have the same class of cookiejar, we need to merge
		if( ! defined merge_httpcookiejar($httpcookiejar, $ua_cookies, $skip_discard, $verbosity) ){ print STDERR "--begin HTTP::Cookies:\n".as_string_httpcookies($httpcookiejar)."\n--end cookies.\n\n"."${whoami}, line ".__LINE__." (via $parent): error, ca...
	} else {
		print STDERR "${whoami}, line ".__LINE__." (via $parent): error, input cookies type '$cookie_jar_class' is not known. Known cookies types are 'HTTP::Cookies' and 'HTTP::CookieJar'.\n";
		return undef
	}

	if( $verbosity > 0 ){ print STDOUT "${whoami}, line ".__LINE__." (via $parent): inserted ".count_cookies($httpcookiejar, $skip_discard, $verbosity)." cookies in the input HTTP::Cookies and loaded them into the LWP::UserAgent. It now has ".count_cook...

	return $ua->cookie_jar;
}

## Firefox::Marionette browser related subs
sub	firefoxmarionette_get_cookies {
	my ($ffmar, $verbosity) = @_;
	#$verbosity //= 0;
	#my $parent = ( caller(1) )[3] || "N/A";
	#my $whoami = ( caller(0) )[3];
	return [ $ffmar->cookies() ]
}

# Save cookies of LWP::UserAgent (they are HTTP::CookieJar)
# into a file. The file will be empty if no cookies.
# It returns 1 on failure, 0 on success.
sub	firefoxmarionette_save_cookies_to_file {
	my ($ffmar, $filename, $skip_discard, $verbosity) = @_;
	$verbosity //= 0;
	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];

	my $cookies = firefoxmarionette_get_cookies($ffmar);
	if( ! defined $cookies ){ print STDERR "${whoami}, line ".__LINE__." (via $parent): error, call to ".'firefoxmarionette_get_cookies()'." has failed.\n"; return 1 }
	if( firefoxmarionettecookies2file($cookies, $filename, $skip_discard, $verbosity) ){ print STDERR "${whoami}, line ".__LINE__." (via $parent): error, call to ".'httpcookies2file()'." has failed.\n"; return 1 }

	return 0 # success
}

# Convenience method to load any kind of cookies
# or a cookies file, into the LWP::UserAgent
# it returns the $ffmar's cookies on success or undef on failure
# NOTE: firefox marionette will not load cookies unless we visit the site
# of the cookie domain. However, some sites redirect you if you
# do not ask for a full-path endpoint URL (e.g. www.abc.com/a/b/c
# instead of cookie domain www.abc.com. If you visit www.abc.com
# it may take you to cy.abc.com)
# So, parameter $visit_cookie_domain_first controls this
# if it is undef, then no visit is made,
# if '' (empty string) then it goes to the domain https://www.abc.com above
# if non-empty string it visits that URL instead, this is the most safe.
sub	firefoxmarionette_load_cookies {
	my ($ffmar, $cookies_or_file_etc, $visit_cookie_domain_first, $skip_discard, $verbosity) = @_;
	$verbosity //= 0;
	$skip_discard //= 0;
	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];

	my $r = ref($cookies_or_file_etc);
	if( $r eq 'HTTP::Cookies' ){
		my $ret = firefoxmarionette_load_httpcookies($ffmar, $cookies_or_file_etc, $visit_cookie_domain_first, $skip_discard, $verbosity);
		if( ! defined $ret ){ print STDERR "${whoami}, line ".__LINE__." (via $parent): error, call to ".'firefoxmarionette_load_httpcookies()'." has failed.\n"; return undef }
		return $ret;
	} elsif( ($r eq 'HTTP::CookieJar') || ($r eq 'HTTP::CookieJar::LWP') ){
		my $ret = firefoxmarionette_load_httpcookiejar($ffmar, $cookies_or_file_etc, $visit_cookie_domain_first, $skip_discard, $verbosity);
		if( ! defined $ret ){ print STDERR "${whoami}, line ".__LINE__." (via $parent): error, call to ".'firefoxmarionette_load_httpcookiejar()'." has failed.\n"; return undef }
		return $ret;
	} elsif( $r eq 'ARRAY' ){
		# an ARRAY_REF of cookie which can be strings as come from a server as Set-Cookie headers
		# or can be an ARRAY of Firefox::Marionette::Cookie
		my $ret;
		if( (scalar(@$cookies_or_file_etc) > 0)
		 && (ref($cookies_or_file_etc->[0])eq'Firefox::Marionette::Cookie')
		){
			$ret = firefoxmarionette_load_firefoxmarionettecookies(
				$ffmar,
				$cookies_or_file_etc,
				$visit_cookie_domain_first,
				$skip_discard, $verbosity
			);
			if( ! defined $ret ){ print STDERR "${whoami}, line ".__LINE__." (via $parent): error, call to ".'firefoxmarionette_load_firefoxmarionettecookies()'." has failed.\n"; return undef }
		} else {
			$ret = firefoxmarionette_load_setcookies($ffmar, $cookies_or_file_etc, $visit_cookie_domain_first, $skip_discard, $verbosity);
			if( ! defined $ret ){ print STDERR "${whoami}, line ".__LINE__." (via $parent): error, call to ".'firefoxmarionette_load_setcookies()'." has failed.\n"; return undef }
		}
		return $ret;
	} elsif( $r eq '' ){
		# scalar means a filename
		my $ret = firefoxmarionette_load_cookies_from_file($ffmar, $cookies_or_file_etc, $visit_cookie_domain_first, $skip_discard, $verbosity);
		if( ! defined $ret ){ print STDERR "${whoami}, line ".__LINE__." (via $parent): error, call to ".'firefoxmarionette_load_cookies_from_file()'." has failed.\n"; return undef }
		return $ret;
	}
	# error!
	print STDERR "${whoami}, line ".__LINE__." (via $parent): error, input cookies type '$r' is not known. Known cookies types are 'HTTP::Cookies' and 'HTTP::CookieJar'.\n";
	return undef
}

# It loads cookies from specified file which needs
# to have this header:
#   #LWP-Cookies-ZZZ.ZZZ
# and then followed by 'Set-Cookie: blahblah' lines,
# into the specified LWP::UserAgent object, appending
# cookies to it if already some there.
# It takes in the $ffmar, $filename and, optionally $verbosity (integer),
# and returns back the $ffmar's cookie jar (as HTTP::CookieJar object)
# It returns undef on failure.
# NOTE: firefox marionette will not load cookies unless we visit the site
# of the cookie domain. However, some sites redirect you if you
# do not ask for a full-path endpoint URL (e.g. www.abc.com/a/b/c
# instead of cookie domain www.abc.com. If you visit www.abc.com
# it may take you to cy.abc.com)
# So, parameter $visit_cookie_domain_first controls this
# if it is undef, then no visit is made,
# if '' (empty string) then it goes to the domain https://www.abc.com above
# if non-empty string it visits that URL instead, this is the most safe.
sub	firefoxmarionette_load_cookies_from_file {
	my ($ffmar, $filename, $visit_cookie_domain_first, $skip_discard, $verbosity) = @_;
	$skip_discard //= 0;
	$verbosity //= 0;
	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];

	my $httpcookies = file2httpcookies($filename, undef, $verbosity);
	if( ! defined $httpcookies ){ print STDERR "${whoami}, line ".__LINE__." (via $parent): error, call to ".'file2httpcookies()'." has failed for cookies file '$filename'.\n"; return undef }
	my $read_num_cookies = count_cookies($httpcookies, $skip_discard, $verbosity);
	my $new_ffmar_cookies = httpcookies2firefoxmarionettecookies($httpcookies, undef, $skip_discard, $verbosity);
	if( ! defined $new_ffmar_cookies ){ print STDERR "${whoami}, line ".__LINE__." (via $parent): error, call to ".'httpcookies2firefoxmarionettecookies()'." has failed for cookies file '$filename'.\n"; return undef }

	if( ! defined firefoxmarionette_load_firefoxmarionettecookies(
		$ffmar,
		$new_ffmar_cookies,
		$visit_cookie_domain_first,
		$skip_discard,
		$verbosity
	) ){ print STDERR "${whoami}, line ".__LINE__." (via $parent): error, call to ".'firefoxmarionette_load_firefoxmarionettecookies()'." has failed.\n"; return undef }

	my $now_ffmar_cookies = firefoxmarionette_get_cookies($ffmar, $verbosity);
	if( ! defined $now_ffmar_cookies ){ print STDERR "${whoami}, line ".__LINE__." (via $parent): error, call to ".'firefoxmarionette_get_cookies()'." has failed.\n"; return undef }
	if( $verbosity > 0 ){ print STDOUT "${whoami}, line ".__LINE__." (via $parent): loaded ${read_num_cookies} cookies into the specified Firefox::Marionette object. It now has ".count_cookies($now_ffmar_cookies, $skip_discard, $verbosity)." cookies.\n"...

	return $now_ffmar_cookies;
}

# It loads the specified HTTP::Cookies object
# into the specified LWP::UserAgent object, appending
# cookies to it if already some there.
# It takes in the $ffmar, $httpcookies and, optionally $verbosity (integer),
# and returns back the $ffmar's cookie jar (as HTTP::CookieJar object)
# It returns undef on failure.
# NOTE: firefox marionette will not load cookies unless we visit the site
# of the cookie domain. However, some sites redirect you if you
# do not ask for a full-path endpoint URL (e.g. www.abc.com/a/b/c
# instead of cookie domain www.abc.com. If you visit www.abc.com
# it may take you to cy.abc.com)
# So, parameter $visit_cookie_domain_first controls this
# if it is undef, then no visit is made,
# if '' (empty string) then it goes to the domain https://www.abc.com above
# if non-empty string it visits that URL instead, this is the most safe.
sub	firefoxmarionette_load_setcookies {
	my ($ffmar, $setcookies, $visit_cookie_domain_first, $skip_discard, $verbosity) = @_;
	$verbosity //= 0;
	$skip_discard //= 0;
	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];

	my $firefoxmarionettecookies = setcookies2firefoxmarionettecookies($setcookies, undef, $verbosity);
	if( ! defined $firefoxmarionettecookies ){ print STDERR "--begin cookies:\n".as_string_cookies($setcookies)."\n--end cookies.\n"."${whoami}, line ".__LINE__." (via $parent): error, call to ".'setcookies2firefoxmarionettecookies()'." has failed for a...
	if( ! defined firefoxmarionette_load_firefoxmarionettecookies(
		$ffmar,
		$firefoxmarionettecookies,
		$visit_cookie_domain_first,
		$skip_discard,
		$verbosity
	) ){ print STDERR "--begin cookies:\n".as_string_cookies($setcookies)."\n--end cookies.\n"."${whoami}, line ".__LINE__." (via $parent): error, call to ".'firefoxmarionette_load_firefoxmarionettecookies()'." has failed for above array of Firefox::Mar...

	my $now_ffmar_cookies = firefoxmarionette_get_cookies($ffmar, $verbosity);
	if( ! defined $now_ffmar_cookies ){ print STDERR "${whoami}, line ".__LINE__." (via $parent): error, call to ".'firefoxmarionette_get_cookies()'." has failed.\n"; return undef }
	if( $verbosity > 0 ){ print STDOUT "${whoami}, line ".__LINE__." (via $parent): loaded ".count_cookies($setcookies, $skip_discard, $verbosity)." cookies into the specified Firefox::Marionette object. It now has ".count_cookies($now_ffmar_cookies, $s...

	return $now_ffmar_cookies;
}

# It loads the specified ARRAY of Firefox::Marionette::Cookie
# OR JUST A SINGLE Firefox::Marionette::Cookie object
# into the specified Firefox::Marionette browser object, appending
# cookies to it if already some there.
# It takes in the $ffmar, $firefoxmarionettecookies and, optionally $verbosity (integer),
# and returns back the $ffmar's cookie jar (as array of Firefox::Marionette::Cookie objects)
# It returns undef on failure.
# NOTE: if you have not visited a url then you can not add cookies!!!! (for firefox-marionette/firefox)
# if you have visited a url then you can add only cookies whose domain is the same as the
# current url!!! Otherwise you get error about cookie-averse document etc.
# see
#   https://stackoverflow.com/questions/48352380/org-openqa-selenium-invalidcookiedomainexception-document-is-cookie-averse-usin
# So, we have an extra flag to visit the page of each cookie domain before loading it
# set $visit_cookie_domain_first to false in order not to visit (that means you are sure
# you are there already, otherwise this call will fail).
# Default is to visit first.
# NOTE: firefox marionette will not load cookies unless we visit the site
# of the cookie domain. However, some sites redirect you if you
# do not ask for a full-path endpoint URL (e.g. www.abc.com/a/b/c
# instead of cookie domain www.abc.com. If you visit www.abc.com
# it may take you to cy.abc.com)
# So, parameter $visit_cookie_domain_first controls this
# if it is undef, then no visit is made,
# if '' (empty string) then it goes to the domain https://www.abc.com above
# if non-empty string (and starts with https?://) it visits that URL instead, this is the most safe.
# BUT if you have a lot of cookies you need to load each with its own calculated url
# This is so stupid and will probably fail.
# Perhaps we can skip cookies which are failing to load and not dump core...
sub	firefoxmarionette_load_firefoxmarionettecookies {
	my ($ffmar, $firefoxmarionettecookies, $visit_cookie_domain_first, $skip_discard, $verbosity) = @_;
	$verbosity //= 0;
	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];

	for my $acookie (
		(ref($firefoxmarionettecookies) eq 'Firefox::Marionette::Cookie')
		? [ $firefoxmarionettecookies ]
		: @$firefoxmarionettecookies
	){
		my $domain = $acookie->domain;
		if( ! defined($domain) || ($domain=~/^\s*$/) ){ print STDERR "--begin cookie:\n".as_string_cookies($acookie)."\n--end cookie.\n"."${whoami}, line ".__LINE__." (via $parent): error, above cookie has no domain!\n"; return undef }
		my $rr;
		if( defined $visit_cookie_domain_first ){
			my $url;
			if( $visit_cookie_domain_first eq '' ){
			  # visit the domain site as it is
			  $url = eval {
				my $uri = URI->new();
				$uri->scheme('https'); # i guess ... this can be a huge bug
				# there may be a path else use some imaginary path
				# hoping it will not redirect us OUTSIDE the domain, inside the domain is ok, cookie will be set.
				$uri->path(defined($acookie->path)?$acookie->path:'a/b/c');
				$uri->host($domain);
				$uri->as_string;
			  };
			  if( $@ || ! $url ){ print STDERR "--begin cookie:\n".as_string_cookies($acookie)."\n--end cookie.\n"."${whoami}, line ".__LINE__." (via $parent): error, failed to create a URL from above cookie's domain".($@?": $@":".")."\n"; return undef }
			  if( $verbosity > 0 ){ print STDOUT "${whoami}, line ".__LINE__." (via $parent): visiting cookie's domain ($domain) to url ($url) before loading above cookie...\n" }
			} elsif( $visit_cookie_domain_first =~ m!^https?\://!i ){
			  # we have a user-specified full url, hopefully, check it is valid
			  # and go there instead of the domain, this is much preferred
			  $url = eval {
				my $uri = URI->new($visit_cookie_domain_first);
				$uri->as_string;
			  };
			  if( $@ || ! $url ){ print STDERR "${whoami}, line ".__LINE__." (via $parent): error, failed to create a URL from specified url parameter '${visit_cookie_domain_first}'".($@?": $@":".")."\n"; return undef }
			  if( $verbosity > 0 ){ print STDOUT "${whoami}, line ".__LINE__." (via $parent): visiting cookie's domain ($domain) to url ($url) before loading above cookie...\n" }
			} else { print STDERR "${whoami}, line ".__LINE__." (via $parent): error, parameter 'visit_cookie_domain_first' was not understood ($visit_cookie_domain_first).\n"; return undef }
			$rr = eval { $ffmar->go($url) };
			if( $@ || ! $rr ){ print STDERR "--begin cookie:\n".as_string_cookies($acookie)."\n--end cookie.\n"."${whoami}, line ".__LINE__." (via $parent): error, call to ".'Firefox::Marionette::go()'." has failed for above cookie and url ($url). Warning: th...
		}
		$rr = eval { $ffmar->add_cookie($acookie) };
		if( $@ || ! $rr ){
			print STDERR "--begin cookie:\n".as_string_cookies($acookie)."\n--end cookie.\n"."${whoami}, line ".__LINE__." (via $parent): error, call to ".'Firefox::Marionette::add_cookie()'." has failed for above cookie but will continue with the others".($@...
			# ignoring errors!
			#return undef
		}
	}
	my $now_ffmar_cookies = firefoxmarionette_get_cookies($ffmar, $verbosity);
	if( ! defined $now_ffmar_cookies ){ print STDERR "${whoami}, line ".__LINE__." (via $parent): error, call to ".'firefoxmarionette_get_cookies()'." has failed.\n"; return undef }
	if( $verbosity > 0 ){ print STDOUT "${whoami}, line ".__LINE__." (via $parent): loaded ".count_cookies($firefoxmarionettecookies, $skip_discard, $verbosity)." cookies into the specified Firefox::Marionette object. It now has ".count_cookies($now_ffm...

	return $now_ffmar_cookies;
}

# It loads the specified HTTP::Cookies object
# into the specified LWP::UserAgent object, appending
# cookies to it if already some there.
# It takes in the $ffmar, $httpcookies and, optionally $verbosity (integer),
# and returns back the $ffmar's cookie jar (as array of Firefox::Marionette::Cookie object)
# It returns undef on failure.
# NOTE: firefox marionette will not load cookies unless we visit the site
# of the cookie domain. However, some sites redirect you if you
# do not ask for a full-path endpoint URL (e.g. www.abc.com/a/b/c
# instead of cookie domain www.abc.com. If you visit www.abc.com
# it may take you to cy.abc.com)
# So, parameter $visit_cookie_domain_first controls this
# if it is undef, then no visit is made,
# if '' (empty string) then it goes to the domain https://www.abc.com above
# if non-empty string it visits that URL instead, this is the most safe.
sub	firefoxmarionette_load_httpcookies {
	my ($ffmar, $httpcookies, $visit_cookie_domain_first, $skip_discard, $verbosity) = @_;
	$skip_discard //= 0;
	$verbosity //= 0;
	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];

	my $firefoxmarionettecookies = httpcookies2firefoxmarionettecookies($httpcookies, undef, $verbosity);
	if( ! defined $firefoxmarionettecookies ){ print STDERR "--begin cookies:\n".as_string_cookies($httpcookies)."\n--end cookies.\n"."${whoami}, line ".__LINE__." (via $parent): error, call to ".'httpcookies2firefoxmarionettecookies()'." has failed for...
	if( ! defined firefoxmarionette_load_firefoxmarionettecookies(
		$ffmar,
		$firefoxmarionettecookies,
		$visit_cookie_domain_first,
		$skip_discard,
		$verbosity
	) ){ print STDERR "--begin cookies:\n".as_string_cookies($httpcookies)."\n--end cookies.\n"."${whoami}, line ".__LINE__." (via $parent): error, call to ".'firefoxmarionette_load_firefoxmarionettecookies()'." has failed for above array of Firefox::Ma...

	my $now_ffmar_cookies = firefoxmarionette_get_cookies($ffmar, $verbosity);
	if( ! defined $now_ffmar_cookies ){ print STDERR "${whoami}, line ".__LINE__." (via $parent): error, call to ".'firefoxmarionette_get_cookies()'." has failed.\n"; return undef }
	if( $verbosity > 0 ){ print STDOUT "${whoami}, line ".__LINE__." (via $parent): loaded ".count_cookies($httpcookies, $skip_discard, $verbosity)." cookies into the specified Firefox::Marionette object. It now has ".count_cookies($now_ffmar_cookies, $...

	return $now_ffmar_cookies;
}

# It loads the specified HTTP::CookieJar object
# into the specified LWP::UserAgent object, appending
# cookies to it if already some there.
# It takes in the $ffmar, $httpcookiejar and, optionally $verbosity (integer),
# and returns back the $ffmar's cookie jar (as HTTP::CookieJar object)
# If the $ffmar has no cookie jar then the supplied cookie jar will be
# first cloned and then into $ffmar.
# So the input $httpcookiejar will be independent of the one in $ffmar.
# It returns undef on failure.
# NOTE: firefox marionette will not load cookies unless we visit the site
# of the cookie domain. However, some sites redirect you if you
# do not ask for a full-path endpoint URL (e.g. www.abc.com/a/b/c
# instead of cookie domain www.abc.com. If you visit www.abc.com
# it may take you to cy.abc.com)
# So, parameter $visit_cookie_domain_first controls this
# if it is undef, then no visit is made,
# if '' (empty string) then it goes to the domain https://www.abc.com above
# if non-empty string it visits that URL instead, this is the most safe.
sub	firefoxmarionette_load_httpcookiejar {
	my ($ffmar, $httpcookiejar, $visit_cookie_domain_first, $skip_discard, $verbosity) = @_;
	$skip_discard //= 0;
	$verbosity //= 0;
	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];

	my $firefoxmarionettecookies = httpcookiejar2firefoxmarionettecookies($httpcookiejar, undef, $verbosity);
	if( ! defined $firefoxmarionettecookies ){ print STDERR "--begin cookies:\n".as_string_cookies($httpcookiejar)."\n--end cookies.\n"."${whoami}, line ".__LINE__." (via $parent): error, call to ".'httpcookiejar2firefoxmarionettecookies()'." has failed...
	if( ! defined firefoxmarionette_load_firefoxmarionettecookies(
		$ffmar,
		$firefoxmarionettecookies,
		$visit_cookie_domain_first,
		$skip_discard,
		$verbosity
	) ){ print STDERR "--begin cookies:\n".as_string_cookies($httpcookiejar)."\n--end cookies.\n"."${whoami}, line ".__LINE__." (via $parent): error, call to ".'firefoxmarionette_load_firefoxmarionettecookies()'." has failed for above array of Firefox::...

	my $now_ffmar_cookies = firefoxmarionette_get_cookies($ffmar, $verbosity);
	if( ! defined $now_ffmar_cookies ){ print STDERR "${whoami}, line ".__LINE__." (via $parent): error, call to ".'firefoxmarionette_get_cookies()'." has failed.\n"; return undef }
	if( $verbosity > 0 ){ print STDOUT "${whoami}, line ".__LINE__." (via $parent): loaded ".count_cookies($httpcookiejar)." cookies into the specified Firefox::Marionette object. It now has ".count_cookies($now_ffmar_cookies)." cookies.\n" }

	return $now_ffmar_cookies;
}

## WWW::Mechanize browser related subs

sub	wwwmechanize_get_cookies {
	my ($mech, $verbosity) = @_;
	#$verbosity //= 0;
	#my $parent = ( caller(1) )[3] || "N/A";
	#my $whoami = ( caller(0) )[3];
	return $mech->cookie_jar
}

# Save cookies of WWW::Mechanize::ANY (they are HTTP::Cookies)
# into a file. The file will be empty if no cookies.
# It returns 1 on failure, 0 on success.
sub	wwwmechanize_save_cookies_to_file {
	my ($mech, $filename, $skip_discard, $verbosity) = @_;
	$verbosity //= 0;
	my $parent = ( caller(1) )[3] || "N/A";
	my $whoami = ( caller(0) )[3];

	# WWW::Mechanize::* supports both HTTP::Cookies and HTTP::CookieJar
	# cookie jars (depending on the 'cookie_jar_class' param to their constructor)
	# we need to find the class of the cookie jar of mech
	# this is probably unsupported but there is no other way:
	my $cookie_jar_class = $mech->{'cookie_jar_class'};

	if( $cookie_jar_class eq 'HTTP::Cookies' ){
		if( httpcookies2file(
			defined($mech->cookie_jar) ? $mech->cookie_jar : $cookie_jar_class->new(),
			$filename, $skip_discard, $verbosity
		) ){ print STDERR "${whoami}, line ".__LINE__." (via $parent): error, call to ".'httpcookies2file()'." has failed.\n"; return 1 }



( run in 0.640 second using v1.01-cache-2.11-cpan-c966e8aa7e8 )