|  line  | 
 stmt  | 
 bran  | 
 cond  | 
 sub  | 
 pod  | 
 time  | 
 code  | 
| 
1
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
26901
 | 
 use strict;  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
31
 | 
    | 
| 
2
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
5
 | 
 use warnings;  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
46
 | 
    | 
| 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package Perlbal::Plugin::SessionAffinity;  | 
| 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # ABSTRACT: Sane session affinity (sticky sessions) for Perlbal  | 
| 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 $Perlbal::Plugin::SessionAffinity::VERSION = '0.100';  | 
| 
6
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
1002
 | 
 use Perlbal;  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
288555
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
33
 | 
    | 
| 
7
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
10
 | 
 use Hash::Util;  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
    | 
| 
8
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
1028
 | 
 use CGI::Cookie;  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8845
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
32
 | 
    | 
| 
9
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
887
 | 
 use MIME::Base64;  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
848
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
64
 | 
    | 
| 
10
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
7
 | 
 use Digest::MD5 'md5';  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
52
 | 
    | 
| 
11
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
937
 | 
 use Digest::SHA 'sha1_hex';  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3515
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2681
 | 
    | 
| 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my $default_cookie_hdr = 'X-SERVERID';  | 
| 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my $cookie_hdr_sub     = sub { encode_base64( md5( $_[0] ) ) };  | 
| 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my $salt               = join q{}, map { $_ = rand 999; s/\.//; $_ } 1 .. 10;  | 
| 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my $use_salt           = 0;  | 
| 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my $use_domain         = 0;  | 
| 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my $use_dynamic_cookie = 0;  | 
| 
19
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
20
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub get_domain_from_req {  | 
| 
21
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
     my $req    = shift;  | 
| 
22
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my $domain = ref $req eq 'Perlbal::XS::HTTPHeaders' ?  | 
| 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                  $req->getHeader('host')                : # XS version  | 
| 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                  $req->{'headers'}{'host'};               # PP version  | 
| 
25
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
26
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     return $domain;  | 
| 
27
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
28
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
29
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # get the ip and port of the requested backend from the cookie  | 
| 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub get_ip_port {  | 
| 
31
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
  
1
  
 | 
0
 | 
     my ( $svc, $req ) = @_;  | 
| 
32
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
33
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my $domain     = get_domain_from_req($req);  | 
| 
34
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my $cookie_hdr = $use_dynamic_cookie        ?  | 
| 
35
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                      $cookie_hdr_sub->($domain) :  | 
| 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                      $default_cookie_hdr;  | 
| 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
38
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my $cookie     = $req->header('Cookie');  | 
| 
39
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my %cookies    = ();  | 
| 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
41
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     if ( defined $cookie ) {  | 
| 
42
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         %cookies = CGI::Cookie->parse($cookie);  | 
| 
43
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
44
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         if ( defined $cookies{$cookie_hdr} ) {  | 
| 
45
 | 
0
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
             my $id      = $cookies{$cookie_hdr}->value || '';  | 
| 
46
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             my $backend = find_backend_by_id( $svc, $id );  | 
| 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
48
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             ref $backend and return join ':', @{$backend};  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
49
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
51
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
52
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     return;  | 
| 
53
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
54
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
55
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # create a domain ID  | 
| 
56
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub create_domain_id {  | 
| 
57
 | 
0
 | 
 
 | 
  
  0
  
 | 
  
0
  
 | 
  
1
  
 | 
0
 | 
     my $domain = shift || '';  | 
| 
58
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my @nodes  = @_;  | 
| 
59
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
60
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # the ID is determined by the specific server  | 
| 
61
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # that has the matching index for the domain  | 
| 
62
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my $index = domain_index( $domain, scalar @nodes );  | 
| 
63
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my $node  = join ':', @{ $nodes[$index] };  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
64
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     return sha1_hex( $use_salt ? $salt . $node : $node );  | 
| 
65
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
67
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # create an id from ip and optional port  | 
| 
68
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub create_id {  | 
| 
69
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
  
1
  
 | 
0
 | 
     my $ip   = shift;  | 
| 
70
 | 
0
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
     my $port = shift || '';  | 
| 
71
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my $str  = $use_salt ? $salt . "$ip:$port" : "$ip:$port";  | 
| 
72
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     return sha1_hex($str);  | 
| 
73
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
74
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
75
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # a nifty little trick:  | 
| 
76
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # we create a numeric value of the domain name  | 
| 
77
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # then we use that as a seed for the random function  | 
| 
78
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # then create a random number which is predictable  | 
| 
79
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # that is the index of the domain  | 
| 
80
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub domain_index {  | 
| 
81
 | 
200
 | 
 
 | 
 
 | 
  
200
  
 | 
  
1
  
 | 
206179
 | 
     my $domain = shift;  | 
| 
82
 | 
200
 | 
 
 | 
 
 | 
 
 | 
 
 | 
263
 | 
     my $max    = shift;  | 
| 
83
 | 
200
 | 
 
 | 
 
 | 
 
 | 
 
 | 
224
 | 
     my $seed   = 0;  | 
| 
84
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
85
 | 
200
 | 
 
 | 
 
 | 
 
 | 
 
 | 
735
 | 
     foreach my $char ( split //, $domain ) {  | 
| 
86
 | 
1500
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1677
 | 
         $seed += ord $char;  | 
| 
87
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
88
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
89
 | 
200
 | 
 
 | 
 
 | 
 
 | 
 
 | 
658
 | 
     return ( $seed % $max);  | 
| 
90
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
92
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # using an sha1 checksum id, find the matching backend  | 
| 
93
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub find_backend_by_id {  | 
| 
94
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
  
1
  
 | 
 
 | 
     my ( $svc, $id ) = @_;  | 
| 
95
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
96
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     foreach my $backend ( @{ $svc->{'pool'}{'nodes'} } ) {  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
97
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $backendid = create_id( @{$backend} );  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
98
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
99
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         if ( $backendid eq $id ) {  | 
| 
100
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             return $backend;  | 
| 
101
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
102
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
103
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
104
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     return;  | 
| 
105
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
106
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
107
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # TODO: refactor this function  | 
| 
108
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub find_backend_by_domain_id {  | 
| 
109
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
  
1
  
 | 
 
 | 
     my ( $svc, $id ) = @_;  | 
| 
110
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
111
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     foreach my $backend ( @{ $svc->{'pool'}{'nodes'} } ) {  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
112
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $backendid = create_id( @{$backend} );  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
113
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
114
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         if ( $backendid eq $id ) {  | 
| 
115
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             return $backend;  | 
| 
116
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
117
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
118
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
119
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     return;  | 
| 
120
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
121
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
122
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub load {  | 
| 
123
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # the name of header in the cookie that stores the backend ID  | 
| 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     Perlbal::register_global_hook(  | 
| 
125
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         'manage_command.affinity_cookie_header', sub {  | 
| 
126
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
             my $mc = shift->parse(qr/^\s*affinity_cookie_header\s+=\s+(.+)\s*$/,  | 
| 
127
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                       "usage: AFFINITY_COOKIE_HEADER = ");  | 
| 
128
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
129
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             ($default_cookie_hdr) = $mc->args;  | 
| 
130
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
131
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             return $mc->ok;  | 
| 
132
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         },  | 
| 
133
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
 
 | 
     );  | 
| 
134
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
135
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     Perlbal::register_global_hook(  | 
| 
136
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         'manage_command.affinity_salt', sub {  | 
| 
137
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
             my $mc = shift->parse(qr/^\s*affinity_salt\s+=\s+(.+)\s*$/,  | 
| 
138
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                       "usage: AFFINITY_SALT = ");  | 
| 
139
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
140
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             ($salt) = $mc->args;  | 
| 
141
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
142
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             return $mc->ok;  | 
| 
143
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         },  | 
| 
144
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     );  | 
| 
145
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     Perlbal::register_global_hook(  | 
| 
147
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         'manage_command.affinity_use_salt', sub {  | 
| 
148
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
             my $mc = shift->parse(qr/^\s*affinity_use_salt\s+=\s+(.+)\s*$/,  | 
| 
149
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                       "usage: AFFINITY_USE_SALT = ");  | 
| 
150
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
151
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             my ($res) = $mc->args;  | 
| 
152
 | 
0
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
             if ( $res eq 'yes' || $res == 1 ) {  | 
| 
 
 | 
 
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
153
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $use_salt = 1;  | 
| 
154
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             } elsif ( $res eq 'no' || $res == 0 ) {  | 
| 
155
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $use_salt = 0;  | 
| 
156
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             } else {  | 
| 
157
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 die qq"affinity_use_salt must be boolean (yes/no/1/0)";  | 
| 
158
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
159
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
160
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             return $mc->ok;  | 
| 
161
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         },  | 
| 
162
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     );  | 
| 
163
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
164
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     Perlbal::register_global_hook(  | 
| 
165
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         'manage_command.affinity_use_domain', sub {  | 
| 
166
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
             my $mc = shift->parse(qr/^\s*affinity_use_domain\s+=\s+(.+)\s*$/,  | 
| 
167
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                       "usage: AFFINITY_USE_DOMAIN = ");  | 
| 
168
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
169
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             my ($res) = $mc->args;  | 
| 
170
 | 
0
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
             if ( $res eq 'yes' || $res == 1 ) {  | 
| 
 
 | 
 
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
171
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $use_domain = 1;  | 
| 
172
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             } elsif ( $res eq 'no' || $res == 0 ) {  | 
| 
173
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $use_domain = 0;  | 
| 
174
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             } else {  | 
| 
175
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 die qq"affinity_use_domain must be boolean (yes/no/1/0)";  | 
| 
176
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
177
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
178
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             return $mc->ok;  | 
| 
179
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         },  | 
| 
180
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     );  | 
| 
181
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
182
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     Perlbal::register_global_hook(  | 
| 
183
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         'manage_command.affinity_use_dynamic_cookie', sub {  | 
| 
184
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
             my $mc = shift->parse(qr/^\s*affinity_use_dynamic_cookie\s+=\s+(.+)\s*$/,  | 
| 
185
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                       "usage: AFFINITY_USE_DYNAMIC_COOKIE = ");  | 
| 
186
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
187
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             my ($res) = $mc->args;  | 
| 
188
 | 
0
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
             if ( $res eq 'yes' || $res == 1 ) {  | 
| 
 
 | 
 
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
189
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $use_dynamic_cookie = 1;  | 
| 
190
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             } elsif ( $res eq 'no' || $res == 0 ) {  | 
| 
191
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $use_dynamic_cookie = 0;  | 
| 
192
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             } else {  | 
| 
193
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 die qq"affinity_use_dynamic_cookie must be boolean (yes/no/1/0)";  | 
| 
194
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
195
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
196
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             return $mc->ok;  | 
| 
197
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         },  | 
| 
198
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     );  | 
| 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
200
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     return 1;  | 
| 
201
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
202
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
203
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub register {  | 
| 
204
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
  
1
  
 | 
 
 | 
     my ( $class, $gsvc ) = @_;  | 
| 
205
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
206
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $check_cookie = sub {  | 
| 
207
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
         my $client = shift;  | 
| 
208
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $req    = $client->{'req_headers'} or return 0;  | 
| 
209
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $svc    = $client->{'service'};  | 
| 
210
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $pool   = $svc->{'pool'};  | 
| 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
212
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # make sure all nodes in this service have their own pool  | 
| 
213
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         foreach my $node ( @{ $pool->{'nodes'} } ) {  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
214
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             my ( $ip, $port ) = @{$node};  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
215
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
216
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # pool  | 
| 
217
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             my $poolid = create_id( $ip, $port );  | 
| 
218
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             exists $Perlbal::pool{$poolid} and next;  | 
| 
219
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
220
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             my $nodepool = Perlbal::Pool->new($poolid);  | 
| 
221
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $nodepool->add( $ip, $port );  | 
| 
222
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $Perlbal::pool{$poolid} = $nodepool;  | 
| 
223
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
224
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # service  | 
| 
225
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             my $serviceid = "${poolid}_service";  | 
| 
226
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             exists $Perlbal::service{$serviceid} and next;  | 
| 
227
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
228
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             my $nodeservice = Perlbal->create_service($serviceid);  | 
| 
229
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             my $svc_role    = $svc->{'role'};  | 
| 
230
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
231
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # role sets up constraints for the rest  | 
| 
232
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # so it goes first  | 
| 
233
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $nodeservice->set( role => $svc_role );  | 
| 
234
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
235
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             foreach my $tunable_name ( keys %{$Perlbal::Service::tunables} ) {  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
236
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # skip role because we had already set it  | 
| 
237
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $tunable_name eq 'role' and next;  | 
| 
238
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
239
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # persist_client_timeout is DEPRECATED  | 
| 
240
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # but not marked anywhere as deprecated. :(  | 
| 
241
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # (well, nowhere we can actually predictably inspect)  | 
| 
242
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $tunable_name eq 'persist_client_timeout' and next;   | 
| 
243
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
244
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # we skip the pool because we're gonna set it to a specific one  | 
| 
245
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $tunable_name eq 'pool' and next;  | 
| 
246
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
247
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # make sure svc has value for this tunable  | 
| 
248
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 defined $svc->{$tunable_name} or next;  | 
| 
249
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
250
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 my $tunable = $Perlbal::Service::tunables->{$tunable_name};  | 
| 
251
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 my $role    = $tunable->{'check_role'};  | 
| 
252
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
253
 | 
0
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
                 if ( $role eq '*' || $role eq $svc_role ) {  | 
| 
254
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     $nodeservice->set( $tunable_name, $svc->{$tunable_name} );  | 
| 
255
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
256
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
257
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
258
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # restricted hashes are stupid  | 
| 
259
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # so we have to use the API to add them  | 
| 
260
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             foreach my $hook_name ( keys %{ $svc->{'hooks'} } ) {  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
261
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 foreach my $set ( @{ $svc->{'hooks'}{$hook_name} } ) {  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
262
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     my ( $plugin, $sub ) = @{$set};  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
263
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     $nodeservice->register_hook( $plugin, $hook_name, $sub );  | 
| 
264
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
265
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
266
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
267
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # add all the extra config and extra headers  | 
| 
268
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $nodeservice->{'extra_config'}  = $svc->{'extra_config'};  | 
| 
269
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $nodeservice->{'extra_headers'} = $svc->{'extra_headers'};  | 
| 
270
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
271
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $nodeservice->set( pool => $poolid );  | 
| 
272
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
273
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $Perlbal::service{$serviceid} = $nodeservice;  | 
| 
274
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
275
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
276
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $ip_port = get_ip_port( $svc, $req );  | 
| 
277
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
278
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         if ( ! $ip_port ) {  | 
| 
279
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $use_domain or return 0;  | 
| 
280
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
281
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # we're going to override whatever Perlbal found  | 
| 
282
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # because we only care about the domain  | 
| 
283
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             my $domain = get_domain_from_req($req);  | 
| 
284
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
285
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             my @ordered_nodes = sort {  | 
| 
286
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 ( join ':', @{$a} ) cmp ( join ':', @{$b} )  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
287
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             } @{ $svc->{'pool'}{'nodes'} };  | 
| 
288
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
289
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             my $id      = create_domain_id( $domain, @ordered_nodes );  | 
| 
290
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             my $backend = find_backend_by_domain_id( $svc, $id );  | 
| 
291
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $ip_port = join ':', @{$backend};  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
292
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
293
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
294
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my ( $ip, $port )    = split /:/, $ip_port;  | 
| 
295
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $req_pool_id      = create_id( $ip, $port );  | 
| 
296
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $req_svc          = $Perlbal::service{"${req_pool_id}_service"};  | 
| 
297
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $client->{'service'} = $req_svc;  | 
| 
298
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
299
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         return 0;  | 
| 
300
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     };  | 
| 
301
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
302
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $set_cookie = sub {  | 
| 
303
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
         my $backend = shift; # Perlbal::BackendHTTP  | 
| 
304
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
305
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         defined $backend or return 0;  | 
| 
306
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
307
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $res        = $backend->{'res_headers'};  | 
| 
308
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $req        = $backend->{'req_headers'};  | 
| 
309
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $svc        = $backend->{'service'};  | 
| 
310
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $backend_id = create_id( split /:/, $backend->{'ipport'} );  | 
| 
311
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $domain     = get_domain_from_req($req);  | 
| 
312
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $cookie_hdr = $use_dynamic_cookie        ?  | 
| 
313
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                          $cookie_hdr_sub->($domain) :  | 
| 
314
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                          $default_cookie_hdr;  | 
| 
315
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
316
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my %cookies = ();  | 
| 
317
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         if ( my $cookie = $req->header('Cookie') ) {  | 
| 
318
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             %cookies = CGI::Cookie->parse($cookie);  | 
| 
319
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
320
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
321
 | 
0
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
         if ( ! defined $cookies{$cookie_hdr} ||  | 
| 
322
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
              $cookies{$cookie_hdr}->value ne $backend_id ) {  | 
| 
323
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
324
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             my $backend_cookie = CGI::Cookie->new(  | 
| 
325
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 -name  => $cookie_hdr,  | 
| 
326
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 -value => $backend_id,  | 
| 
327
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             );  | 
| 
328
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
329
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             if ( defined $res->header('set-cookie') ) {  | 
| 
330
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 my $value = $res->header('set-cookie') .  | 
| 
331
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                             "\r\nSet-Cookie: "         .  | 
| 
332
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                             $backend_cookie->as_string;  | 
| 
333
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
334
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $res->header( 'Set-Cookie' => $value );  | 
| 
335
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             } else {  | 
| 
336
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $res->header( 'Set-Cookie' => $backend_cookie->as_string );  | 
| 
337
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
338
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
339
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
340
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         return 0;  | 
| 
341
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     };  | 
| 
342
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
343
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $gsvc->register_hook(  | 
| 
344
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         'SessionAffinity', 'start_proxy_request', $check_cookie,  | 
| 
345
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     );  | 
| 
346
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
347
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $gsvc->register_hook(  | 
| 
348
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         'SessionAffinity', 'backend_response_received', $set_cookie,  | 
| 
349
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     );  | 
| 
350
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
351
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     return 1;  | 
| 
352
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
353
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
354
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub unregister {  | 
| 
355
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
  
1
  
 | 
 
 | 
     my ( $class, $svc ) = @_;  | 
| 
356
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
357
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # TODO: are we using setters?  | 
| 
358
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $svc->unregister_hooks('SessionAffinity');  | 
| 
359
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $svc->unregister_setters('SessionAffinity');  | 
| 
360
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
361
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     return 1;  | 
| 
362
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
363
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
364
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 1;  | 
| 
365
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
366
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 __END__  |