File Coverage

lib/Perlbal/Plugin/UrlGroup.pm
Criterion Covered Total %
statement 66 82 80.4
branch 16 24 66.6
condition 6 15 40.0
subroutine 9 11 81.8
pod 0 5 0.0
total 97 137 70.8


line stmt bran cond sub pod time code
1             package Perlbal::Plugin::UrlGroup;
2 3     3   785144 use strict;
  3         12  
  3         101  
3 3     3   15 use warnings;
  3         5  
  3         159  
4 3     3   23 no warnings qw(deprecated);
  3         11  
  3         103  
5              
6 3     3   14 use URI::Escape;
  3         5  
  3         5884  
7              
8             our $VERSION = '0.03';
9              
10             our %Services; # service_name => $svc
11             my $manage_command = 'manage_command.group';
12             my $manage_command_regex = 'manage_command.group_regex';
13              
14             my $group_regex = '';
15             my $group_postfix = '';
16             my %url_group;
17              
18             # when "LOAD" directive loads us up
19             sub load {
20 3     3 0 285 my $class = shift;
21              
22             Perlbal::register_global_hook($manage_command_regex, sub {
23 4     4   659 my $mc = shift->parse(qr/^group_regex\s+(\S+)\s*=\s*(\w+)$/,
24             "usage: GROUP_REGEX = ");
25 4         103 ($group_regex,$group_postfix) = $mc->args;
26 4         31 $url_group{$group_regex} = $group_postfix;
27 4         14 return $mc->ok;
28 3         23 });
29              
30             Perlbal::register_global_hook($manage_command, sub {
31 8     8   1274 my $mc = shift->parse(qr/^group\s+(?:(\w+)\s+)?(\S+)\s*=\s*(\w+)$/,
32             "usage: GROUP [] = ");
33 8         190 my ($selname, $host, $target) = $mc->args;
34 8 50 33     94 unless ($selname ||= $mc->{ctx}{last_created}) {
35 0         0 return $mc->err("omitted service name not implied from context");
36             }
37              
38 8         31 my $ss = Perlbal->service($selname);
39 8 50 33     78 return $mc->err("Service '$selname' is not a selector service")
40             unless $ss && $ss->{role} eq "selector";
41              
42 8         17 $host = lc $host;
43 8 50       37 return $mc->err("invalid host pattern: '$host'")
44             unless $host =~ /^[\w\-\_\.\*\;\:\\]+$/;
45              
46 8 100       31 $ss->{extra_config}->{_use_wild_card} = 1 if $host =~ /\*/;
47              
48 8   50     25 $ss->{extra_config}->{_groups} ||= {};
49 8         36 $ss->{extra_config}->{_groups}{$host} = $target;
50              
51 8         23 return $mc->ok;
52 3         30 });
53 3         67 return 1;
54             }
55              
56             # unload our global commands, clear our service object
57             sub unload {
58 0     0 0 0 my $class = shift;
59              
60 0         0 Perlbal::unregister_global_hook($manage_command);
61 0         0 Perlbal::unregister_global_hook($manage_command_regex);
62 0         0 unregister($class, $_) foreach (values %Services);
63 0         0 return 1;
64             }
65              
66             # called when we're being added to a service
67             sub register {
68 3     3 0 105726 my ($class, $svc) = @_;
69 3 50 33     89 unless ($svc && $svc->{role} eq "selector") {
70 0         0 die "You can't load the url_group plugin on a service not of role selector.\n";
71             }
72              
73 3         22 $svc->selector(\&url_group_selector);
74 3         42 $svc->{extra_config}->{_groups} = {};
75              
76 3         15 $Services{"$svc"} = $svc;
77 3         59 return 1;
78             }
79              
80             # called when we're no longer active on a service
81             sub unregister {
82 0     0 0 0 my ($class, $svc) = @_;
83 0         0 $svc->selector(undef);
84 0         0 delete $Services{"$svc"};
85 0         0 return 1;
86             }
87              
88             # call back from Service via ClientHTTPBase's event_read calling service->select_new_service(Perlbal::ClientHTTPBase)
89             sub url_group_selector {
90 36     36 0 843532 my Perlbal::ClientHTTPBase $cb = shift;
91              
92 36         93 my $req = $cb->{req_headers};
93              
94 36 50       147 return $cb->_simple_response(404, "Not Found (no reqheaders)") unless $req;
95              
96 36         174 my $vhost = $req->header("Host");
97 36         389 my $uri = $req->request_uri;
98 36   50     317 my $maps = $cb->{service}{extra_config}{_groups} ||= {};
99              
100 36         111 $vhost =~ s/:\d+$//;
101              
102 36         66 my $target;
103 36 50       170 if ( $cb->{service}{extra_config}{_use_wild_card} ) {
104 36         136 for my $host_org (keys %$maps) {
105 92         362 (my $host_name = $host_org) =~ s/\*/.+/g;
106              
107 92 100       239 if ( $vhost eq $host_name ) {
108 14         31 $target = $maps->{$host_org};
109 14         36 last;
110             }
111              
112 78 100       2155 if ($vhost =~ /^$host_name$/) {
113 22         89 $target = $maps->{$host_org};
114             # do more loop.
115             }
116             }
117             } else {
118 0         0 $target = $maps->{$vhost};
119             }
120              
121 36         210 my $chk_uri = URI::Escape::uri_unescape($uri);
122             # query¤Ï̵»ë
123 36         347 $chk_uri =~ s/\?.+$//g;
124              
125 36 50       87 if ( $target ) {
126 36         60 my $dest_service;
127 36         118 for my $regex ( keys %url_group ) {
128 44 100       720 if ( $chk_uri =~ /$regex/ ) {
129 20         49 $dest_service = $target.$url_group{$regex};
130 20         40 last;
131             }
132 24         63 $dest_service = $target;
133             }
134              
135 36   50     267 my $svc = Perlbal->service($dest_service) || undef;
136 36 50       460 unless ($svc) {
137 0         0 $cb->_simple_response(404, "Not Found (no configured url_group's dest_service)");
138 0         0 return 1;
139             } else {
140 36         183 $svc->adopt_base_client($cb);
141 36         89074 return 0;
142             }
143             } else {
144 0           $cb->_simple_response(404, "Not Found (no configured url_group's vhost name)");
145 0           return 1;
146             }
147             }
148              
149             1;
150              
151             __END__