File Coverage

blib/lib/AnyEvent/HTTPD/Router/DefaultDispatcher.pm
Criterion Covered Total %
statement 53 54 98.1
branch 13 16 81.2
condition 6 12 50.0
subroutine 6 6 100.0
pod 0 3 0.0
total 78 91 85.7


line stmt bran cond sub pod time code
1             package AnyEvent::HTTPD::Router::DefaultDispatcher;
2              
3 7     7   52 use common::sense;
  7         14  
  7         48  
4 7     7   366 use Carp;
  7         16  
  7         5735  
5              
6             sub new {
7 8     8 0 350 my $this = shift;
8 8   33     92 my $class = ref($this) || $this;
9 8         48 my $self = {
10             routes => {}
11             };
12              
13 8         31 return bless $self, $class;
14             }
15              
16             sub add_route {
17 11     11 0 121 my $self = shift;
18 11         25 my $verbs = shift;
19 11         21 my $path = shift;
20 11         18 my $cb = shift;
21              
22 11 100       58 unless (exists $self->{routes}->{$path}) {
23 10         46 my @segments = split /\//, $path;
24 10         59 $self->{routes}->{$path} = {
25             segments => \@segments, # something to improve speed
26             callbacks => {}, # method/path => cb mapping
27             };
28             }
29              
30 11         30 my $dispatch_entry = $self->{routes}->{$path};
31 11         61 foreach my $verb (@$verbs) {
32 11         66 $dispatch_entry->{callbacks}->{$verb} = $cb;
33             }
34             }
35              
36             sub match {
37 11     11 0 22014 my $self = shift;
38 11         19 my $httpd = shift;
39 11         22 my $req = shift;
40 11         20 my $matched = 0;
41 11         45 my @path = $req->url->path_segments;
42 11         899 my $method = $req->method;
43              
44 11 50 33     74 if ( $method eq 'GET' or $method eq 'POST' ) {
45 11 50       51 if ( @path[-1] =~ s/:(\w+)$// ) { # TODO regex for verbs
46 0         0 $method = $1;
47             }
48             }
49              
50             # sort because we want to have reproducable
51             # behaviour for match
52 11         23 foreach my $path ( sort keys %{ $self->{routes} } ) {
  11         64  
53 18         38 my $dispatch_entry = $self->{routes}->{$path};
54              
55             # step 1: match the method/verb
56 18 50       55 if ( my $cb = $dispatch_entry->{callbacks}->{$method} ) {
57             # step 2: match the path
58 18 100       50 if ( my $variables = _match_paths( \@path, $dispatch_entry->{segments} ) ) {
59 9         23 $matched = 1;
60 9         31 $cb->( $httpd, $req, $variables );
61 9         9919 last;
62             }
63             }
64             }
65 11         58 return $matched;
66             }
67              
68             sub _match_paths {
69             # copies
70 18     18   31 my @request_path_seq = @{ +shift };
  18         48  
71 18         28 my @routing_path_seq = @{ +shift };
  18         40  
72              
73 18         52 my $request_seq;
74             my $routing_seq;
75 18         0 my %variables;
76              
77 18   66     56 while (@request_path_seq or @routing_path_seq) {
78 43         77 $request_seq = shift @request_path_seq; # maybe undef
79 43         70 $routing_seq = shift @routing_path_seq; # maybe undef
80              
81 43 100 66     194 if ($routing_seq eq '*') {
    100          
    100          
82             # done with all matching,
83             # * slurps all the $request_seq that still might come
84 2         10 $variables{'*'} = join('/', $request_seq, @request_path_seq);
85 2         4 last;
86             } elsif ($routing_seq eq $request_seq) {
87             # go on with matching
88             } elsif ($routing_seq =~ m/^\:(.+)$/ and defined $request_seq) {
89             # remember the variable
90 4         10 my $var_name = $1;
91 4         16 $variables{$var_name} = $request_seq;
92             } else {
93             ## mismatch
94             # if they are not equal
95             # this includes if one of them is undef
96 9         45 return;
97             }
98             }
99              
100 9         31 return \%variables;
101             }
102              
103             1;