1 package HTTP::Cookies::Microsoft;
5 use vars qw(@ISA $VERSION);
10 @ISA=qw(HTTP::Cookies);
12 sub load_cookies_from_file
16 my ($key, $value, $domain_path, $flags, $lo_expire, $hi_expire);
17 my ($lo_create, $hi_create, $sep);
19 open(COOKIES, $file) || return;
21 while ($key = <COOKIES>)
24 chomp($value = <COOKIES>);
25 chomp($domain_path= <COOKIES>);
26 chomp($flags = <COOKIES>); # 0x0001 bit is for secure
27 chomp($lo_expire = <COOKIES>);
28 chomp($hi_expire = <COOKIES>);
29 chomp($lo_create = <COOKIES>);
30 chomp($hi_create = <COOKIES>);
31 chomp($sep = <COOKIES>);
33 if (!defined($key) || !defined($value) || !defined($domain_path) ||
34 !defined($flags) || !defined($hi_expire) || !defined($lo_expire) ||
35 !defined($hi_create) || !defined($lo_create) || !defined($sep) ||
41 if ($domain_path =~ /^([^\/]+)(\/.*)$/)
46 push(@cookies, {KEY => $key, VALUE => $value, DOMAIN => $domain,
47 PATH => $path, FLAGS =>$flags, HIXP =>$hi_expire,
48 LOXP => $lo_expire, HICREATE => $hi_create,
49 LOCREATE => $lo_create});
60 my $user = lc(Win32::LoginName());
65 # MSIE stores create and expire times as Win32 FILETIME,
66 # which is 64 bits of 100 nanosecond intervals since Jan 01 1601
68 # But Cookies code expects time in 32-bit value expressed
69 # in seconds since Jan 01 1970
71 sub epoch_time_offset_from_win32_filetime
73 my ($high, $low) = @_;
75 #--------------------------------------------------------
77 #--------------------------------------------------------
78 # 0x019db1de 0xd53e8000 is 1970 Jan 01 00:00:00 in Win32 FILETIME
80 # 100 nanosecond intervals == 0.1 microsecond intervals
82 my $filetime_low32_1970 = 0xd53e8000;
83 my $filetime_high32_1970 = 0x019db1de;
85 #------------------------------------
87 #------------------------------------
88 # To go from 100 nanosecond intervals to seconds since 00:00 Jan 01 1970:
90 # 1. Adjust 100 nanosecond intervals to Jan 01 1970 base
91 # 2. Divide by 10 to get to microseconds (1/millionth second)
92 # 3. Divide by 1000000 (10 ^ 6) to get to seconds
94 # We can combine Step 2 & 3 into one divide.
96 # After much trial and error, I came up with the following code which
97 # avoids using Math::BigInt or floating pt, but still gives correct answers
99 # If the filetime is before the epoch, return 0
100 if (($high < $filetime_high32_1970) ||
101 (($high == $filetime_high32_1970) && ($low < $filetime_low32_1970)))
106 # Can't multiply by 0x100000000, (1 << 32),
107 # without Perl issuing an integer overflow warning
109 # So use two multiplies by 0x10000 instead of one multiply by 0x100000000
111 # The result is the same.
113 my $date1970 = (($filetime_high32_1970 * 0x10000) * 0x10000) + $filetime_low32_1970;
114 my $time = (($high * 0x10000) * 0x10000) + $low;
124 my($self, $file) = @_;
125 my $now = time() - $HTTP::Cookies::EPOCH_OFFSET;
130 # open the cookie file and get the data
131 $cookie_data = load_cookies_from_file($file);
133 foreach my $cookie (@{$cookie_data})
135 my $secure = ($cookie->{FLAGS} & 1) != 0;
136 my $expires = epoch_time_offset_from_win32_filetime($cookie->{HIXP}, $cookie->{LOXP});
138 $self->set_cookie(undef, $cookie->{KEY}, $cookie->{VALUE},
139 $cookie->{PATH}, $cookie->{DOMAIN}, undef,
140 0, $secure, $expires-$now, 0);
147 my($self, $cookie_index) = @_;
148 my $now = time() - $HTTP::Cookies::EPOCH_OFFSET;
150 my $delay_load = (defined($self->{'delayload'}) && $self->{'delayload'});
151 my $user_name = get_user_name();
154 $cookie_index ||= $self->{'file'} || return;
155 if ($cookie_index =~ /[\\\/][^\\\/]+$/)
157 $cookie_dir = $` . "\\";
162 open(INDEX, $cookie_index) || return;
164 if (256 != read(INDEX, $data, 256))
166 warn "$cookie_index file is not large enough";
171 # Cookies' index.dat file starts with 32 bytes of signature
172 # followed by an offset to the first record, stored as a little-endian DWORD
173 my ($sig, $size) = unpack('a32 V', $data);
175 if (($sig !~ /^Client UrlCache MMF Ver 5\.2/) || # check that sig is valid (only tested in IE6.0)
178 warn "$cookie_index ['$sig' $size] does not seem to contain cookies";
183 if (0 == seek(INDEX, $size, 0)) # move the file ptr to start of the first record
189 # Cookies are usually stored in 'URL ' records in two contiguous 0x80 byte sectors (256 bytes)
190 # so read in two 0x80 byte sectors and adjust if not a Cookie.
191 while (256 == read(INDEX, $data, 256))
193 # each record starts with a 4-byte signature
194 # and a count (little-endian DWORD) of 0x80 byte sectors for the record
195 ($sig, $size) = unpack('a4 V', $data);
197 # Cookies are found in 'URL ' records
200 # skip over uninteresting record: I've seen 'HASH' and 'LEAK' records
201 if (($sig eq 'HASH') || ($sig eq 'LEAK'))
203 # '-2' takes into account the two 0x80 byte sectors we've just read in
204 if (($size > 0) && ($size != 2))
206 if (0 == seek(INDEX, ($size-2)*0x80, 1))
208 # Seek failed. Something's wrong. Gonna stop.
216 #$REMOVE Need to check if URL records in Cookies' index.dat will
217 # ever use more than two 0x80 byte sectors
220 my $more_data = ($size-2)*0x80;
222 if ($more_data != read(INDEX, $data, $more_data, 256))
228 if ($data =~ /Cookie\:$user_name\@([\x21-\xFF]+).*?($user_name\@[\x21-\xFF]+\.txt)/)
230 my $cookie_file = $cookie_dir . $2; # form full pathname
234 $self->load_cookie($cookie_file);
240 # grab only the domain name, drop everything from the first dir sep on
241 if ($domain =~ m{[\\/]})
246 # set the delayload cookie for this domain with
247 # the cookie_file as cookie for later-loading info
248 $self->set_cookie(undef, 'cookie', $cookie_file,
249 '//+delayload', $domain, undef,
250 0, 0, $now+86400, 0);
266 HTTP::Cookies::Microsoft - access to Microsoft cookies files
271 use HTTP::Cookies::Microsoft;
272 use Win32::TieRegistry(Delimiter => "/");
273 my $cookies_dir = $Registry->
274 {"CUser/Software/Microsoft/Windows/CurrentVersion/Explorer/Shell Folders/Cookies"};
276 $cookie_jar = HTTP::Cookies::Microsoft->new(
277 file => "$cookies_dir\\index.dat",
280 my $browser = LWP::UserAgent->new;
281 $browser->cookie_jar( $cookie_jar );
285 This is a subclass of C<HTTP::Cookies> which
286 loads Microsoft Internet Explorer 5.x and 6.x for Windows (MSIE)
289 See the documentation for L<HTTP::Cookies>.
293 The following methods are provided:
297 =item $cookie_jar = HTTP::Cookies::Microsoft->new;
299 The constructor takes hash style parameters. In addition
300 to the regular HTTP::Cookies parameters, HTTP::Cookies::Microsoft
301 recognizes the following:
303 delayload: delay loading of cookie data until a request
304 is actually made. This results in faster
305 runtime unless you use most of the cookies
306 since only the domain's cookie data
313 Please note that the code DOESN'T support saving to the MSIE
318 Johnny Lee <typo_pl@hotmail.com>
322 Copyright 2002 Johnny Lee
324 This library is free software; you can redistribute it and/or
325 modify it under the same terms as Perl itself.