File Coverage

blib/lib/XRI.pm
Criterion Covered Total %
statement 79 107 73.8
branch 17 40 42.5
condition 2 9 22.2
subroutine 13 15 86.6
pod 0 8 0.0
total 111 179 62.0


line stmt bran cond sub pod time code
1             # Copyright (C) 2004 Identity Commons. All Rights Reserved.
2             # See LICENSE for licensing details
3              
4             # Author: Fen Labalme
5              
6             # TODO: Insert logic about choosing an authority from the current descriptor
7             # TODO: Logic about whether to look at the mapping, etc.
8              
9             require 5.6.0;
10              
11             package XRI;
12             our $VERSION = '0.2.4';
13              
14 3     3   82101 use strict;
  3         7  
  3         284  
15              
16 3     3   1646 use XRI::Parse qw( GCS_CHARS );
  3         8  
  3         104  
17 3     3   1860 use XRI::Descriptor;
  3         73  
  3         95  
18              
19 3     3   34 use XML::Smart;
  3         6  
  3         54  
20 3     3   14 use URI::Escape;
  3         5  
  3         248  
21 3     3   3786 use LWP::Simple;
  3         306445  
  3         32  
22              
23 3     3   1394 use Log::Agent;
  3         18  
  3         4385  
24             logconfig(-prefix => $0);
25              
26             # this gets changed during make install
27             my $ROOTS = '/usr/local/lib/perl5/site_perl/5.20.0/XRI/xriroots.xml';
28              
29             my $xrins = 'xri:$r.s/XRIDescriptor';
30              
31             our %globals = ();
32             our %private = ();
33              
34             sub new {
35 3     3 0 1580 my $self = shift;
36 3         5 my $xri = shift;
37 3         14 my $this = { descriptor=>undef,
38             descriptorXML=>undef,
39             localAccessURL=>undef,
40             xri=>$xri };
41 3         10 bless $this, $self;
42             }
43              
44             # Converts XRIs with DNS-based Authorities to HTTP URIs and stores the localaccessurl
45             #
46             # FIXME: more escaping needed - also need to check for absoluteness
47             #
48             sub convertToHTTP {
49 1     1 0 2 my $self = shift;
50              
51 1 50       7 $self->{localAccessURL} = "http:" .
52             (( $self->{xri} =~ /^xri:(.*)$/ ) ? $1 : $self->{xri} );
53             }
54              
55             sub resolveToAuthorityXML {
56 3     3 0 4 my $self = shift;
57 3         4 my ($service, $type) = @_;
58 3         19 my $XRI = new XRI::Parse $self->{xri}; # FIXME: created two XRI objects...
59 3         5 my ($authRef, $descriptor, @authURIs);
60 3         5 my $descXML = undef;
61              
62             # get the authority and local access parts
63             #
64 3         10 my $authLocal = $XRI->splitAuthLocal;
65              
66             # no authority part -> relative-path
67             #
68 3 100       9 if ( ! defined $XRI->{authority} ) {
69 1 50 33     10 die "RelativePathNotXRIAuthority for passed service or type\n"
70             if ($service || $type);
71 1         3 $self->{localAccessURL} = $authLocal;
72 1         28 logtrc 'notice', "No XRI Authority - relative-path resolved";
73 1         297 return;
74             }
75             # if the first segment is '//' convert to HTTP and return
76             #
77 2 100       7 if ( $XRI->{authority} eq '//') {
78 1 50 33     7 die "URIAuthorityNotXRIAuthority for passed service or type\n"
79             if ($service || $type);
80 1         4 $self->convertToHTTP;
81 1         27 logtrc 'notice', "XRI Authority is DNS Based - XRI converted to HTTP";
82 1         267 return;
83             }
84 1         36 logtrc 'notice', "Extracted root identifier of %s", $XRI->{authority};
85              
86             # load the roots (global roots could be "precomputed")
87             # FIXME: need mechanism to incrementally add to private roots
88             #
89 1 50       333 readRoots() if ! scalar %globals;
90              
91 1         6 ($authRef, $self->{localAccessURL}) = @$authLocal;
92 1         3 my $subseg = shift @$authRef;
93              
94             # get the root authority
95             # HACK: we assume there's only one root AuthorityURI
96             # HACK: we randomly choose the first XRIAuthority URI
97             #
98 1 50       3 my $url = isGCS( $subseg ) ? $globals{ $subseg } : $private{ $subseg };
99 1 50       5 if (! defined $url) {
100 0         0 die "UnknownAuthority: $subseg\n";
101             }
102 1         5 while ( $subseg = shift @$authRef ) { # divider
103 1         3 $subseg .= shift @$authRef; # segment
104 1         33 logtrc 'notice', "Resolving authority subsegment %s", $subseg;
105              
106 1 50       317 $url .= '/' unless $url =~ m|/$|;
107 1         100 $url .= uri_escape($subseg); # FIXME turn spaces into '+', etc...
108              
109 1         105 logtrc 'notice', "Contacting Naming Authority URL %s", $url;
110 1         322 $descXML = get $url; # Quick and dirty - should catch exceptions and 404s
111 1 50       128239518 if ( ! defined $descXML ) {
112 1         322 die "NoDescriptorXML for $url\n"; # FIXME
113             }
114 0         0 logtrc 'notice', "Descriptor for %s is\n%s", $subseg, $descXML;
115              
116 0         0 $descriptor = XRI::Descriptor->new($descXML);
117              
118 0 0       0 if (! defined $descriptor) {
119 0         0 die "MalformedXRIDescriptor for $url\n";
120             }
121 0         0 @authURIs = @{$descriptor->getXRIAuthorityURIs};
  0         0  
122              
123             # is it a bug if there is no XRIAuthority URI in a delegated segment?
124             # we'll accept it for now, and expect to use LocalAccess from here...
125             #
126 0 0       0 last unless scalar @authURIs; # done if no XRI Authority URU
127              
128 0         0 $url = $authURIs[0]; # HACK: randomly choose the first URI
129             }
130 0         0 $self->{descriptor} = $descriptor;
131 0         0 $self->{descriptorXML} = $descXML;
132             }
133              
134             # Performs basic Authority Resolution
135             # Assumes we are not using a DNS-based authority
136             # Sets the descriptor to the XRI
137             #
138             sub resolveToLocalAccessURI {
139 3     3 0 13 my $self = shift;
140 3         5 my ($service, $type) = @_;
141 3         10 $self->resolveToAuthorityXML($service, $type);
142              
143 2 50       12 return unless $self->{descriptor};
144              
145 0         0 my $local = $self->{localAccessURL};
146 0         0 my @localAccessElem = $self->{descriptor}->getLocalAccess($service, $type);
147              
148 0 0       0 if ( scalar @localAccessElem ) {
149            
150             # HACK: randomly choose the first LocalAccess element and the first URI within it
151             #
152 0         0 my $desLocalAccess = ${$localAccessElem[0]->uris}[0];
  0         0  
153 0         0 logtrc( 'notice',
154             "Constructed local access URL from base local access url %s and local XRI part %s",
155             $desLocalAccess, $local );
156 0 0 0     0 $desLocalAccess .= '/' if $local && $desLocalAccess !~ m|\/$|;
157 0         0 logtrc 'notice', "Local access descriptor is %s", $desLocalAccess;
158 0         0 $self->{localAccessURL} = $desLocalAccess . XRI::Parse->new($local)->escapeURI;
159             }
160             else {
161             #No local access URL! Probably should raise an excepetion
162 0         0 $self->{localAccessURL} = undef;
163 0         0 die "NoLocalAccessFound for XRI $self->{xri}\n";
164             }
165             }
166              
167             sub doGet {
168 0     0 0 0 my $self = shift;
169              
170 0 0       0 $self->resolveToLocalAccessURI
171             unless defined $self->{localAccessURL};
172 0         0 return get( $self->{localAccessURL} ); # returns the document
173             }
174              
175             sub getGetURL {
176 0     0 0 0 my $self = shift;
177              
178 0 0       0 $self->resolveToLocalAccessURI
179             unless defined $self->{localAccessURL};
180 0         0 return $self->{localAccessURL};
181             }
182              
183             sub isGCS {
184 9     9 0 427 my $char = shift;
185              
186 9         20 return grep { $_ eq $char } @XRI::Parse::GCS_CHARS;
  45         1257  
187             }
188              
189             # Read XRI roots file
190             # TODO: implement mechanism to add private roots
191             #
192             sub readRoots {
193 2     2 0 695 my $roots = shift;
194              
195 2 50       9 $roots = $ROOTS unless defined $roots;
196              
197 2 50       63 die "XRIRootsNotFound: Can't find $roots\n" unless -r $roots;
198              
199 2         25 my $XML = XML::Smart->new($roots);
200              
201 2         40276 $XML = $XML->cut_root();
202              
203 2         1348 foreach my $descriptor ( @{$XML->{XRIDescriptor}} ) { # missing: ('xmlns','eq',$xrins)
  2         118  
204 8         1713 my $resolved = $descriptor->{Resolved};
205 8         2494 my $authority = $descriptor->{XRIAuthority}{URI};
206 8 100       2240 if ( isGCS( $resolved )) {
207 6         353 logtrc 'notice', "Resolved Global %s to %s", $resolved, $authority;
208 6         5830 $XRI::globals{$resolved} = $authority;
209             }
210             else {
211 2         125 logtrc 'notice', "Resolved Private %s to %s", $resolved, $authority;
212 2         1251 $XRI::private{$resolved} = $authority;
213             }
214             }
215             }
216              
217             1;
218             __END__