⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cookies.pm

📁 美国CMU大学开发的操作系统健壮性评测软件
💻 PM
📖 第 1 页 / 共 2 页
字号:
package HTTP::Cookies;# Based on draft-ietf-http-state-man-mec-08.txt and# http://www.netscape.com/newsref/std/cookie_spec.htmluse strict;use HTTP::Date qw(str2time time2str);use HTTP::Headers::Util qw(split_header_words join_header_words);use LWP::Debug ();use vars qw($VERSION);$VERSION = sprintf("%d.%02d", q$Revision: 1.1 $ =~ /(\d+)\.(\d+)/);=head1 NAMEHTTP::Cookies - Cookie storage and management=head1 SYNOPSIS use HTTP::Cookies; $cookie_jar = HTTP::Cookies->new; $cookie_jar->add_cookie_header($request); $cookie_jar->extract_cookies($response);=head1 DESCRIPTIONCookies are a general mechanism which server side connections can useto both store and retrieve information on the client side of theconnection.  For more information about cookies referrer to<URL:http://www.netscape.com/newsref/std/cookie_spec.html> and<URL:http://www.cookiecentral.com/>.  This module also implements thenew style cookies as described in I<draft-ietf-http-state-man-mec-08.txt>.The two variants of cookies is supposed to be able to coexist happily.Instances of the class I<HTTP::Cookies> are able to store a collectionof Set-Cookie2: and Set-Cookie:-headers and is able to use thisinformation to initialize Cookie-headers in I<HTTP::Request> objects.The state of the I<HTTP::Cookies> can be saved and restored fromfiles.=head1 METHODSThe following methods are provided:=over 4=cut# A HTTP::Cookies object is a hash.  The main attribute is the# COOKIES 3 level hash:  $self->{COOKIES}{$domain}{$path}{$key}.=item $cookie_jar = HTTP::Cookies->new;The constructor.  Takes hash style parameters.  The followingparameters are recognized:  file:            name of the file to restore and save cookies to  autosave:        should we save during destruction (bool)  ignore_discard:  save even cookies that are requested to be discarded (bool)Future parameters might include (not yet implemented):  max_cookies               300  max_cookies_per_domain    20  max_cookie_size           4096  no_cookies   list of domain names that we never return cookies to=cutsub new{    my $class = shift;    my $self = bless {	COOKIES => {},    }, $class;    my %cnf = @_;    for (keys %cnf) {	$self->{lc($_)} = $cnf{$_};    }    $self->load;    $self;}=item $cookie_jar->add_cookie_header($request);The add_cookie_header() method will set the appropriate Cookie:-headerfor the I<HTTP::Request> object given as argument.  The $request musthave a valid url() attribute before this method is called.=cutsub add_cookie_header{    my $self = shift;    my $request = shift || return;    my $url = $request->url;    my $domain = $url->host;    $domain = "$domain.local" unless $domain =~ /\./;    my $secure_request = ($url->scheme eq "https");    my $req_path = $url->epath;    my $req_port = $url->port;    my $now = time();    $self->_normalize_path($req_path) if $req_path =~ /%/;    my @cval;    # cookie values for the "Cookie" header    my $set_ver;    while (($domain =~ tr/././) >= 2 || # must be at least 2 dots           $domain =~ /\.local$/)    {        LWP::Debug::debug("Checking $domain for cookies");	my $cookies = $self->{COOKIES}{$domain};	next unless $cookies;	# Want to add cookies corresponding to the most specific paths	# first (i.e. longest path first)	my $path;	for $path (sort {length($b) <=> length($a) } keys %$cookies) {            LWP::Debug::debug("- checking cookie path=$path");	    if (index($req_path, $path) != 0) {	        LWP::Debug::debug("  path $path:$req_path does not fit");		next;	    }	    my($key,$array);	    while (($key,$array) = each %{$cookies->{$path}}) {		my($version,$val,$port,$path_spec,$secure,$expires) = @$array;	        LWP::Debug::debug(" - checking cookie $key=$val");		if ($secure && !$secure_request) {		    LWP::Debug::debug("   not a secure requests");		    next;		}		if ($expires && $expires < $now) {		    LWP::Debug::debug("   expired");		    next;		}		if ($port) {		    my $found;		    if ($port =~ s/^_//) {			# The correponding Set-Cookie attribute was empty			$found++ if $port eq $req_port;			$port = "";		    } else {			my $p;			for $p (split(/,/, $port)) {			    $found++, last if $p eq $req_port;			}		    }		    unless ($found) {		        LWP::Debug::debug("   port $port:$req_port does not fit");			next;		    }		}	        LWP::Debug::debug("   it's a match");		# set version number of cookie header.	        # XXX: What should it be if multiple matching                #      Set-Cookie headers have different versions themselves		if (!$set_ver++) {		    if ($version >= 1) {			push(@cval, "\$Version=$version");		    } else {			$request->header(Cookie2 => "\$Version=1");		    }		}		# do we need to quote the value		if ($val =~ /\W/ && $version) {		    $val =~ s/([\\\"])/\\$1/g;		    $val = qq("$val");		}		# and finally remember this cookie		push(@cval, "$key=$val");		if ($version >= 1) {		    push(@cval, qq(\$Path="$path"))     if $path_spec;		    push(@cval, qq(\$Domain="$domain")) if $domain =~ /^\./;		    if (defined $port) {			my $p = '$Port';			$p .= qq(="$port") if length $port;			push(@cval, $p);		    }		}	    }        }    } continue {	# Try with a more general domain:  www.sol.no ==> .sol.no	$domain =~ s/^\.?[^.]*//;    }    $request->header(Cookie => join("; ", @cval)) if @cval;    $request;}=item $cookie_jar->extract_cookies($response);The extract_cookies() method will look for Set-Cookie: andSet-Cookie2:-headers in the I<HTTP::Response> object passed asargument.  If some of these headers are found they are used to updatethe state of the $cookie_jar.=cutsub extract_cookies{    my $self = shift;    my $response = shift || return;    my @set = split_header_words($response->_header("Set-Cookie2"));    my $netscape_cookies;    unless (@set) {	@set = $response->_header("Set-Cookie");	return $response unless @set;	$netscape_cookies++;    }    my $url = $response->request->url;    my $req_host = $url->host;    $req_host = "$req_host.local" unless $req_host =~ /\./;    my $req_port = $url->port;    my $req_path = $url->epath;    $self->_normalize_path($req_path) if $req_path =~ /%/;        if ($netscape_cookies) {	# The old Netscape cookie format for Set-Cookie        # http://www.netscape.com/newsref/std/cookie_spec.html	# can for instance contain an unquoted "," in the expires	# field, so we have to use this ad-hoc parser.	my $now = time();	my @old = @set;	@set = ();	my $set;	for $set (@old) {	    my @cur;	    my $param;	    my $expires;	    for $param (split(/\s*;\s*/, $set)) {		my($k,$v) = split(/\s*=\s*/, $param, 2);		#print "$k => $v\n";		my $lc = lc($k);		if ($lc eq "expires") {		    push(@cur, "Max-Age" => str2time($v) - $now);		    $expires++;		} else {		    push(@cur, $k => $v);		}	    }	    push(@cur, "Port" => $req_port);	    push(@cur, "Discard" => undef) unless $expires;	    push(@cur, "Version" => 0);	    push(@set, \@cur);	}    }  SET_COOKIE:    for my $set (@set) {	next unless @$set >= 2;	my $key = shift @$set;	my $val = shift @$set;        LWP::Debug::debug("Set cookie $key => $val");	my %hash;	while (@$set) {	    my $k = shift @$set;	    my $v = shift @$set;	    my $lc = lc($k);	    # don't loose case distinction for unknown fields	    $k = $lc if $lc =~ /^(?:discard|domain|max-age|                                    path|port|secure|version)$/x;	    if ($k eq "discard" || $k eq "secure") {		$v = 1 unless defined $v;	    }	    next if exists $hash{$k};  # only first value is signigicant	    $hash{$k} = $v;	};	my %orig_hash = %hash;	my $version   = delete $hash{version};	$version = 1 unless defined($version);	my $discard   = delete $hash{discard};	my $secure    = delete $hash{secure};	my $maxage    = delete $hash{'max-age'};	# Check domain	my $domain  = delete $hash{domain};	if (defined($domain) && $domain ne $req_host) {	    if ($domain !~ /\./ && $domain ne "local") {	        LWP::Debug::debug("Domain $domain contains no dot");		next SET_COOKIE;	    }	    $domain = ".$domain" unless $domain =~ /^\./;	    if ($domain =~ /\.\d+$/) {	        LWP::Debug::debug("IP-address $domain illeagal as domain");		next SET_COOKIE;	    }	    my $len = length($domain);	    unless (substr($req_host, -$len) eq $domain) {	        LWP::Debug::debug("Domain $domain does not match host $req_host");		next SET_COOKIE;	    }	    my $hostpre = substr($req_host, 0, length($req_host) - $len);	    if ($hostpre =~ /\./ && !$netscape_cookies) {	        LWP::Debug::debug("Host prefix contain a dot: $hostpre => $domain");		next SET_COOKIE;	    }	} else {	    $domain = $req_host;	}	my $path = delete $hash{path};	my $path_spec;	if (defined $path) {	    $path_spec++;	    $self->_normalize_path($path) if $path =~ /%/;	    if (!$netscape_cookies &&                substr($req_path, 0, length($path)) ne $path) {	        LWP::Debug::debug("Path $path is not a prefix of $req_path");		next SET_COOKIE;	    }	} else {	    $path = $req_path;	    $path =~ s,/[^/]*$,,;	    $path = "/" unless length($path);	}	my $port;	if (exists $hash{port}) {	    $port = delete $hash{port};	    if (defined $port) {		$port =~ s/\s+//g;		my $found;		for my $p (split(/,/, $port)) {		    unless ($p =~ /^\d+$/) {		      LWP::Debug::debug("Bad port $port (not numeric)");			next SET_COOKIE;		    }		    $found++ if $p eq $req_port;		}		unless ($found) {		    LWP::Debug::debug("Request port ($req_port) not found in $port");		    next SET_COOKIE;		}	    } else {		$port = "_$req_port";	    }	}	$self->set_cookie($version,$key,$val,$path,$domain,$port,$path_spec,$secure,$maxage,$discard, \%hash)	    if $self->set_cookie_ok(\%orig_hash);    }    $response;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -