mark: A photo of Mark kneeling on top of the Taal Volcano in the Philippines. It was a long hike. (Default)
Mark Smith ([staff profile] mark) wrote in [site community profile] changelog2010-04-30 07:08 pm

[dw-free] Multiple domain cookies for same domain cause infinite loop.

[commit: http://hg.dwscoalition.org/dw-free/rev/cc792aafd776]

http://bugs.dwscoalition.org/show_bug.cgi?id=2574

Fix support for multiple cookies with the same name.

Patch by [personal profile] exor674.

Files modified:
  • cgi-bin/DW/Request/Base.pm
  • cgi-bin/LJ/Session.pm
--------------------------------------------------------------------------------
diff -r 7e8ff7c26de6 -r cc792aafd776 cgi-bin/DW/Request/Base.pm
--- a/cgi-bin/DW/Request/Base.pm	Fri Apr 30 09:21:49 2010 +0000
+++ b/cgi-bin/DW/Request/Base.pm	Fri Apr 30 19:08:00 2010 +0000
@@ -19,9 +19,11 @@ use strict;
 use strict;
 use Carp qw/ confess cluck /;
 use CGI::Cookie;
+use CGI::Util qw( unescape );
 
 use fields (
             'cookies_in',
+            'cookies_in_multi',
         );
 
 sub new {
@@ -30,14 +32,22 @@ sub new {
         unless ref $self;
 
     $self->{cookies_in} = undef;
+    $self->{cookies_in_multi} = undef;
 }
 
 sub cookie {
     my DW::Request::Base $self = $_[0];
 
-    $self->{cookies_in} ||= { CGI::Cookie->parse( $self->header_in( 'Cookie' ) ) };
-    return unless exists $self->{cookies_in}->{$_[1]};
-    return $self->{cookies_in}->{$_[1]}->value;
+    $self->parse( $self->header_in( 'Cookie' ) ) unless defined $self->{cookies_in};
+    my $val = $self->{cookies_in}->{$_[1]};
+    return wantarray ? @{ $val } : $val->[0];
+}
+
+sub cookie_multi {
+    my DW::Request::Base $self = $_[0];
+
+    $self->parse( $self->header_in( 'Cookie' ) ) unless defined $self->{cookies_in_multi};
+    return @{ $self->{cookies_in_multi}->{$_[1]} || [] };
 }
 
 sub add_cookie {
@@ -66,4 +76,40 @@ sub delete_cookie {
     return $self->add_cookie( %args );
 }
 
+#
+# Following sub was copied from CGI::Cookie and modified.
+#
+# Copyright 1995-1999, Lincoln D. Stein.  All rights reserved.
+# It may be used and modified freely, but I do request that this copyright
+# notice remain attached to the file.  You may modify this module as you 
+# wish, but if you redistribute a modified version, please attach a note
+# listing the modifications you have made.
+#
+sub parse {
+    my DW::Request::Base $self = $_[0];
+    my %results;
+    my %results_multi;
+
+    my @pairs = split( "[;,] ?", $_[1] );
+    foreach ( @pairs ) {
+        $_ =~ s/\s*(.*?)\s*/$1/;
+        my ( $key, $value ) = split( "=", $_, 2 );
+        
+        # Some foreign cookies are not in name=value format, so ignore
+        # them.
+        next unless defined( $value );
+        my @values = ();
+        if ( $value ne '' ) {
+          @values = map unescape( $_ ), split( /[&;]/, $value . '&dmy' );
+          pop @values;
+        }
+        $key = unescape( $key );
+        $results{$key} ||= \@values;
+        push @{ $results_multi{$key} }, \@values;
+    }
+
+    $self->{cookies_in} = \%results;
+    $self->{cookies_in_multi} = \%results_multi;
+}
+
 1;
diff -r 7e8ff7c26de6 -r cc792aafd776 cgi-bin/LJ/Session.pm
--- a/cgi-bin/LJ/Session.pm	Fri Apr 30 09:21:49 2010 +0000
+++ b/cgi-bin/LJ/Session.pm	Fri Apr 30 19:08:00 2010 +0000
@@ -491,14 +491,14 @@ sub session_from_cookies {
     my $domain_cookie = LJ::Session->domain_cookie;
     if ($domain_cookie) {
         # journal domain
-        $sessobj = LJ::Session->session_from_domain_cookie( \%getopts, $r->cookie( $domain_cookie ) );
+        $sessobj = LJ::Session->session_from_domain_cookie( \%getopts, $r->cookie_multi( $domain_cookie ) );
     } else {
         # this is the master cookie at "www.livejournal.com" or "livejournal.com";
-        my @cookies = $r->cookie( 'ljmastersession' );
+        my @cookies = $r->cookie_multi( 'ljmastersession' );
         # but support old clients who are just sending an "ljsession" cookie which they got
         # from ljprotocol's "generatesession" mode.
-        unless (@cookies) {
-            @cookies = $r->cookie( 'ljsession' );
+        unless ( @cookies ) {
+            @cookies = $r->cookie_multi( 'ljsession' );
             $getopts{old_cookie} = 1;
         }
         $sessobj = LJ::Session->session_from_master_cookie(\%getopts, @cookies);
@@ -535,7 +535,7 @@ sub session_from_domain_cookie {
     my $domcook = LJ::Session->domain_cookie;
 
     foreach my $cookie (@cookies) {
-        my $sess = valid_domain_cookie($domcook, $cookie, $li_cook);
+        my $sess = valid_domain_cookie($domcook, $cookie->[0], $li_cook);
         return $sess if $sess;
     }
 
@@ -561,7 +561,7 @@ sub session_from_master_cookie {
     my $ignore_ip  = delete $opts->{ignore_ip} ? 1 : 0;
     my $old_cookie = delete $opts->{old_cookie} ? 1 : 0;
 
-    delete $opts->{'redirect_ref'};  # we don't use this
+    delete $opts->{redirect_ref};  # we don't use this
     croak("Unknown options") if %$opts;
 
     my $now = time();
@@ -572,8 +572,8 @@ sub session_from_master_cookie {
     my $li_cook = $r->cookie( 'ljloggedin' );
 
   COOKIE:
-    foreach my $sessdata (@cookies) {
-        my ($cookie, $gen) = split(m!//!, $sessdata);
+    foreach my $sessdata ( @cookies ) {
+        my ( $cookie, $gen ) = split( m!//!, $sessdata->[0] );
 
         my ($version, $userid, $sessid, $auth, $flags);
 
--------------------------------------------------------------------------------

Post a comment in response:

This account has disabled anonymous posting.
If you don't have an account you can create one now.
HTML doesn't work in the subject.
More info about formatting

If you are unable to use this captcha for any reason, please contact us by email at support@dreamwidth.org