line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package URI::Builder; |
2
|
|
|
|
|
|
|
|
3
|
4
|
|
|
4
|
|
140202
|
use strict; |
|
4
|
|
|
|
|
11
|
|
|
4
|
|
|
|
|
161
|
|
4
|
4
|
|
|
4
|
|
22
|
use warnings; |
|
4
|
|
|
|
|
19
|
|
|
4
|
|
|
|
|
193
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
=head1 NAME |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
URI::Builder - URI objects optimised for manipulation |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
=head1 SYNOPSIS |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
my $uri = URI::Builder->new( |
13
|
|
|
|
|
|
|
scheme => 'http', |
14
|
|
|
|
|
|
|
host => 'www.cpan.org', |
15
|
|
|
|
|
|
|
); |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
$uri->path_segments(qw( misc cpan-faq.html )); |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
say $uri->as_string; # http://www.cpan.org/misc/cpan-faq.html |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
=head1 VERSION |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
0.04 |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
=cut |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
our $VERSION = '0.04'; |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
=head1 DESCRIPTION |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
This class is a close relative of L, but while that class is optimised |
32
|
|
|
|
|
|
|
for parsing, this is optimised for building up or modifying URIs. To that end |
33
|
|
|
|
|
|
|
objects of this class represent their URIs in sections, each of which are |
34
|
|
|
|
|
|
|
independently mutable, that then need to be serialised to form a string. In |
35
|
|
|
|
|
|
|
contrast, C uses a fully-formed string internally which must be parsed |
36
|
|
|
|
|
|
|
afresh each time a mutation is performed on it. |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
At the moment only http and https URIs are known to work correctly, support |
39
|
|
|
|
|
|
|
for other schemes may follow later. |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
=cut |
42
|
|
|
|
|
|
|
|
43
|
4
|
|
|
4
|
|
3742
|
use URI; |
|
4
|
|
|
|
|
32130
|
|
|
4
|
|
|
|
|
147
|
|
44
|
4
|
|
|
4
|
|
39
|
use Scalar::Util qw( blessed ); |
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
602
|
|
45
|
4
|
|
|
4
|
|
30
|
use Carp qw( confess ); |
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
1208
|
|
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
# Utility functions |
48
|
|
|
|
|
|
|
sub _flatten { |
49
|
141
|
100
|
|
|
|
680
|
return map { |
|
|
100
|
|
|
|
|
|
50
|
52
|
|
|
52
|
|
150
|
ref $_ eq 'ARRAY' ? _flatten(@$_) |
51
|
|
|
|
|
|
|
: ref $_ eq 'HASH' ? _flatten_hash($_) |
52
|
|
|
|
|
|
|
: $_ |
53
|
|
|
|
|
|
|
} @_ = @_; |
54
|
|
|
|
|
|
|
} |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
sub _flatten_hash { |
57
|
5
|
|
|
5
|
|
5
|
my $hash = shift; |
58
|
|
|
|
|
|
|
|
59
|
7
|
|
|
|
|
14
|
return map { |
60
|
5
|
|
|
|
|
14
|
my ($k, $v) = ($_, $hash->{$_}); |
61
|
7
|
100
|
|
|
|
19
|
$v = '' unless defined $v; |
62
|
7
|
|
|
|
|
13
|
map { $k => $_ } _flatten $v |
|
16
|
|
|
|
|
44
|
|
63
|
|
|
|
|
|
|
} keys %$hash; |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
|
66
|
4
|
|
|
4
|
|
34
|
use overload ('""' => \&as_string, fallback => 1); |
|
4
|
|
|
|
|
10
|
|
|
4
|
|
|
|
|
28
|
|
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
The following attributes relate closely with the URI methods of the same |
71
|
|
|
|
|
|
|
names. |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
=over |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
=item * scheme |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
=item * userinfo |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
=item * host |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
=item * port |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
=item * path_segments |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
=item * query_form |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
=item * query_keywords |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
=item * fragment |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
=back |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
In addition the C attribute defines how C fields |
94
|
|
|
|
|
|
|
are joined. It defaults to C<';'> but can be usefully set to '&'. |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
The accessors for these attributes have a similar interface to the L |
97
|
|
|
|
|
|
|
methods, that is to say that they return old values when new ones are set. |
98
|
|
|
|
|
|
|
Those attributes that take a list of values: C, C |
99
|
|
|
|
|
|
|
and C all return plain lists but can be passed nested array |
100
|
|
|
|
|
|
|
references. |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
=cut |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
my (@uri_fields, %listish, @fields); |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
BEGIN { |
107
|
|
|
|
|
|
|
# Fields that correspond to methods in URI |
108
|
4
|
|
|
4
|
|
16
|
@uri_fields = qw( |
109
|
|
|
|
|
|
|
scheme |
110
|
|
|
|
|
|
|
userinfo |
111
|
|
|
|
|
|
|
host |
112
|
|
|
|
|
|
|
port |
113
|
|
|
|
|
|
|
path_segments |
114
|
|
|
|
|
|
|
query_form |
115
|
|
|
|
|
|
|
query_keywords |
116
|
|
|
|
|
|
|
fragment |
117
|
|
|
|
|
|
|
); |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
# Fields that contain lists of values |
120
|
4
|
|
|
|
|
10
|
%listish = map { $_ => 1 } qw( |
|
12
|
|
|
|
|
50
|
|
121
|
|
|
|
|
|
|
path_segments |
122
|
|
|
|
|
|
|
query_form |
123
|
|
|
|
|
|
|
query_keywords |
124
|
|
|
|
|
|
|
); |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
# All fields |
127
|
4
|
|
|
|
|
21
|
@fields = ( @uri_fields, qw( query_separator )); |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
# Generate accessors for all fields: |
130
|
4
|
|
|
|
|
19
|
for my $field (@fields) { |
131
|
4
|
|
|
4
|
|
765
|
my $glob = do { no strict 'refs'; \*$field }; |
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
620
|
|
|
36
|
|
|
|
|
47
|
|
|
36
|
|
|
|
|
183
|
|
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
*$glob = $listish{$field} ? sub { |
134
|
221
|
|
|
221
|
|
320
|
my $self = shift; |
135
|
221
|
100
|
|
|
|
235
|
my @old = @{ $self->{$field} || []}; |
|
221
|
|
|
|
|
1052
|
|
136
|
221
|
100
|
|
|
|
481
|
$self->{$field} = [ _flatten @_ ] if @_; |
137
|
221
|
|
|
|
|
627
|
return @old; |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
: sub { |
140
|
248
|
|
|
248
|
|
646
|
my $self = shift; |
141
|
248
|
|
|
|
|
502
|
my $old = $self->{$field}; |
142
|
248
|
50
|
|
|
|
488
|
$self->{$field} = shift if @_; |
143
|
248
|
|
|
|
|
721
|
return $old; |
144
|
36
|
100
|
|
|
|
8803
|
}; |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
=head1 METHODS |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
=head2 new |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
The constructor. |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
In addition to the attributes listed above, a C argument can be passed as |
155
|
|
|
|
|
|
|
a string or a L object, which will be parsed to popoulate any missing |
156
|
|
|
|
|
|
|
fields. |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
# a cpan URL without its path |
159
|
|
|
|
|
|
|
my $uri = URI::Builder->new( |
160
|
|
|
|
|
|
|
uri => 'http://www.cpan.org/SITES.html', |
161
|
|
|
|
|
|
|
path_segments => [], |
162
|
|
|
|
|
|
|
); |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
Non-attribute arguments that match other methods in the class will cause those |
165
|
|
|
|
|
|
|
methods to be called on the object. This means that what we internally regard |
166
|
|
|
|
|
|
|
as composite attributes can be specified directly in the constructor. |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
# Implicitly populate path_segments: |
169
|
|
|
|
|
|
|
my $uri = URI::Builder->new( path => 'relative/path' ); |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
Unrecognised arguments cause an exception. |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
=cut |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
sub new { |
176
|
34
|
|
|
34
|
1
|
15730
|
my $class = shift; |
177
|
34
|
50
|
33
|
|
|
215
|
my %opts = @_ == 1 && ref $_[0] eq 'HASH' ? %{ $_[0] } : @_; |
|
0
|
|
|
|
|
0
|
|
178
|
|
|
|
|
|
|
|
179
|
34
|
|
100
|
|
|
179
|
$opts{query_separator} ||= ';'; |
180
|
|
|
|
|
|
|
|
181
|
34
|
100
|
|
|
|
110
|
if (my $uri = $opts{uri}) { |
182
|
9
|
|
|
|
|
63
|
$uri = $class->_inflate_uri($uri); |
183
|
|
|
|
|
|
|
|
184
|
9
|
|
|
|
|
31770
|
for my $field (@uri_fields) { |
185
|
72
|
100
|
66
|
|
|
3137
|
if (!defined $opts{$field} && (my $code = $uri->can($field))) { |
186
|
69
|
100
|
|
|
|
307
|
$opts{$field} = |
187
|
|
|
|
|
|
|
$listish{$field} ? [ $code->($uri) ] : $code->($uri); |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
$_ = [ _flatten $_ ] |
193
|
34
|
|
100
|
|
|
454
|
for grep defined && ref ne 'ARRAY', @opts{ keys %listish }; |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
# Still no scheme? Default to http |
196
|
|
|
|
|
|
|
# $opts{scheme} ||= 'http'; |
197
|
|
|
|
|
|
|
|
198
|
34
|
|
|
|
|
125
|
my $self = bless { map { $_ => $opts{$_} } @fields }, $class; |
|
306
|
|
|
|
|
770
|
|
199
|
|
|
|
|
|
|
|
200
|
34
|
|
|
|
|
163
|
delete @opts{@fields}; |
201
|
|
|
|
|
|
|
|
202
|
34
|
|
|
|
|
117
|
for my $field (sort keys %opts) { |
203
|
14
|
50
|
|
|
|
86
|
if (my $method = $self->can($field)) { |
204
|
14
|
|
|
|
|
49
|
$method->($self, _flatten delete $opts{$field}); |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
|
208
|
34
|
50
|
|
|
|
787
|
if (my @invalid = sort keys %opts) { |
209
|
0
|
|
|
|
|
0
|
confess "Unrecognised fields in constructor: ", join ', ', @invalid; |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
|
212
|
34
|
|
|
|
|
140
|
return $self; |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
# Turn various things into URI objects |
216
|
|
|
|
|
|
|
sub _inflate_uri { |
217
|
11
|
|
|
11
|
|
126
|
my ($self, $thing) = @_; |
218
|
|
|
|
|
|
|
|
219
|
11
|
100
|
|
|
|
53
|
if (blessed $thing) { |
220
|
4
|
50
|
|
|
|
35
|
if ($thing->isa('URI')) { |
|
|
0
|
|
|
|
|
|
221
|
4
|
|
|
|
|
11
|
return $thing; |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
elsif ($thing->isa(__PACKAGE__)) { |
224
|
0
|
|
|
|
|
0
|
return $thing->uri; |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
else { |
227
|
0
|
|
|
|
|
0
|
return URI->new("$thing"); |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
else { |
231
|
7
|
|
|
|
|
55
|
return URI->new($thing); |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
} |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
=head2 abs |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
$absolute_uri = $relative_uri->abs($base_uri) |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
Returns a new L object as an absolute URL based on the given |
240
|
|
|
|
|
|
|
base URI. |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
Implemented as a wrapper of L. |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
=cut |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
sub abs { |
247
|
1
|
|
|
1
|
1
|
398
|
my ($self, $base, @args) = @_; |
248
|
1
|
|
|
|
|
3
|
my $class = ref $self; |
249
|
|
|
|
|
|
|
|
250
|
1
|
|
|
|
|
4
|
return $class->new(uri => $self->uri->abs($self->_inflate_uri($base), @args)); |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
=head2 rel |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
$relative_uri = $absolute_uri->rel($base_uri) |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
Returns a new L object denoting the relative URI compared with |
259
|
|
|
|
|
|
|
the base URI. |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
Implemented as a wrapper of L. |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
=cut |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
sub rel { |
266
|
1
|
|
|
1
|
1
|
7
|
my ($self, $base) = @_; |
267
|
1
|
|
|
|
|
3
|
my $class = ref $self; |
268
|
|
|
|
|
|
|
|
269
|
1
|
|
|
|
|
4
|
return $class->new(uri => $self->uri->rel($self->_inflate_uri($base))); |
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
=head2 clone |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
Returns a new object with all attributes copied. |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
=cut |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
sub clone { |
279
|
2
|
|
|
2
|
1
|
20
|
my $self = shift; |
280
|
|
|
|
|
|
|
|
281
|
2
|
|
|
|
|
24
|
my %clone = %$self; |
282
|
2
|
|
|
|
|
7
|
for my $list ( keys %listish ) { |
283
|
6
|
50
|
100
|
|
|
18
|
$clone{$list} &&= [ @{ $clone{$list} || [] } ]; |
|
3
|
|
|
|
|
20
|
|
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
|
286
|
2
|
|
|
|
|
13
|
return ref($self)->new(%clone); |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
=head2 as_string |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
Returns the URI described by the object as a string. This is built up from the |
292
|
|
|
|
|
|
|
individual components each time it's called. |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
This is also used as the stringification overload. |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
=cut |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
sub as_string { |
299
|
44
|
|
|
44
|
1
|
397
|
my $self = shift; |
300
|
|
|
|
|
|
|
|
301
|
44
|
|
|
|
|
53
|
my @parts; |
302
|
|
|
|
|
|
|
|
303
|
44
|
100
|
|
|
|
98
|
if (my $authority = $self->authority) { |
304
|
28
|
100
|
|
|
|
63
|
if (my $scheme = $self->scheme) { |
305
|
22
|
|
|
|
|
45
|
push @parts, "$scheme:"; |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
|
308
|
28
|
|
|
|
|
40
|
$authority =~ s/:@{[ $self->default_port ]}\z//; |
|
28
|
|
|
|
|
83
|
|
309
|
|
|
|
|
|
|
|
310
|
28
|
|
|
|
|
3188
|
push @parts, "//$authority"; |
311
|
|
|
|
|
|
|
} |
312
|
|
|
|
|
|
|
|
313
|
44
|
100
|
|
|
|
107
|
if (my $path = $self->path) { |
314
|
20
|
100
|
|
|
|
64
|
$path =~ s{^(?!/)}{/} if @parts; |
315
|
20
|
|
|
|
|
35
|
push @parts, $path; |
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
|
318
|
44
|
100
|
|
|
|
107
|
if (my $query = $self->query) { |
319
|
15
|
|
|
|
|
37
|
push @parts, "?$query"; |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
|
322
|
44
|
100
|
|
|
|
105
|
if (my $fragment = $self->fragment) { |
323
|
3
|
|
|
|
|
9
|
push @parts, "#$fragment"; |
324
|
|
|
|
|
|
|
} |
325
|
|
|
|
|
|
|
|
326
|
44
|
|
|
|
|
254
|
return join('', @parts); |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
=head2 uri |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
Returns a version of this object as a L object. |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
=cut |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
sub uri { |
336
|
11
|
|
|
11
|
1
|
23
|
my $self = shift; |
337
|
|
|
|
|
|
|
|
338
|
11
|
|
|
|
|
51
|
return URI->new($self->as_string); |
339
|
|
|
|
|
|
|
} |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
=head2 default_port |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
Returns the default port for the current object's scheme. This is obtained |
344
|
|
|
|
|
|
|
from the appropriate L subclass. See L. |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
=head2 secure |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
Returns true if the current scheme is a secure one, false otherwise. See |
349
|
|
|
|
|
|
|
L. |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
=cut |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
sub _implementor { |
354
|
28
|
|
|
28
|
|
32
|
my $self = shift; |
355
|
|
|
|
|
|
|
|
356
|
28
|
|
100
|
|
|
49
|
return URI::implementor($self->scheme || 'http'); |
357
|
|
|
|
|
|
|
} |
358
|
|
|
|
|
|
|
|
359
|
28
|
|
|
28
|
1
|
58
|
sub default_port { shift->_implementor->default_port } |
360
|
0
|
|
|
0
|
1
|
0
|
sub secure { shift->_implementor->secure } |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
=head2 authority |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
Returns the 'authority' section of the URI. In our case this is obtained by |
365
|
|
|
|
|
|
|
combining C, C and C together as appropriate. |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
Note that this is a read-only operation. |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
=cut |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
sub authority { |
372
|
44
|
|
|
44
|
1
|
58
|
my $self = shift; |
373
|
44
|
|
|
|
|
154
|
my ($user, $host) = ($self->userinfo, $self->host_port); |
374
|
|
|
|
|
|
|
|
375
|
44
|
100
|
|
|
|
201
|
return $host ? $user ? "$user\@$host" : $host : ''; |
|
|
100
|
|
|
|
|
|
376
|
|
|
|
|
|
|
} |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
=head2 host_port |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
Returns the host and port in a single string. |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
=cut |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
sub host_port { |
385
|
44
|
|
|
44
|
1
|
59
|
my $self = shift; |
386
|
44
|
|
|
|
|
88
|
my ($host, $port) = ($self->host, $self->port); |
387
|
|
|
|
|
|
|
|
388
|
44
|
100
|
|
|
|
185
|
return $host ? $port ? "$host:$port" : $host : ''; |
|
|
100
|
|
|
|
|
|
389
|
|
|
|
|
|
|
} |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
=head2 path |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
Returns the path portion of the URI as a string. |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
Can be assigned to to populate C. |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
Leading, trailing and doubled slashes are represented faithfully using empty |
398
|
|
|
|
|
|
|
path segments. |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
=cut |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
sub path { |
403
|
54
|
|
|
54
|
1
|
72
|
my $self = shift; |
404
|
|
|
|
|
|
|
|
405
|
54
|
|
|
|
|
247
|
my $old = join '/', $self->path_segments; |
406
|
|
|
|
|
|
|
|
407
|
54
|
100
|
|
|
|
147
|
if (@_) { |
408
|
6
|
|
|
|
|
24
|
my @segments = split '/', shift, -1; |
409
|
6
|
|
|
|
|
17
|
$self->path_segments(@segments); |
410
|
|
|
|
|
|
|
} |
411
|
|
|
|
|
|
|
|
412
|
54
|
|
|
|
|
162
|
return $old; |
413
|
|
|
|
|
|
|
} |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
=head2 query |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
Returns a string representation of the query. This is obtained from either |
418
|
|
|
|
|
|
|
C or C, in that order. |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
If an argument is passed, it is parsed to populate C. |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
=cut |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
sub query { |
425
|
49
|
|
|
49
|
1
|
73
|
my ($self, $query) = @_; |
426
|
|
|
|
|
|
|
|
427
|
49
|
|
|
|
|
52
|
my @new; |
428
|
49
|
100
|
|
|
|
94
|
if ($query) { |
429
|
|
|
|
|
|
|
# Parse the new query string using a URI object |
430
|
1
|
|
|
|
|
4
|
@new = URI->new("?$query", $self->scheme)->query_form; |
431
|
|
|
|
|
|
|
} |
432
|
|
|
|
|
|
|
|
433
|
49
|
50
|
|
|
|
170
|
unless (defined wantarray) { |
434
|
|
|
|
|
|
|
# void context, don't bother building the query string |
435
|
0
|
|
|
|
|
0
|
$self->query_form(@new); |
436
|
0
|
|
|
|
|
0
|
return; |
437
|
|
|
|
|
|
|
} |
438
|
|
|
|
|
|
|
|
439
|
49
|
|
|
|
|
51
|
my $old; |
440
|
49
|
100
|
|
|
|
111
|
if (my @form = $self->query_form) { |
441
|
15
|
100
|
|
|
|
49
|
push @form, '' if @form % 2; |
442
|
15
|
|
|
|
|
62
|
my $uri = URI->new; |
443
|
15
|
|
|
|
|
978
|
$uri->query_form(\@form, $self->query_separator); |
444
|
15
|
|
|
|
|
1598
|
$old = $uri->query(); |
445
|
|
|
|
|
|
|
} |
446
|
|
|
|
|
|
|
else { |
447
|
34
|
|
|
|
|
76
|
$old = join '+', $self->query_keywords; |
448
|
|
|
|
|
|
|
} |
449
|
|
|
|
|
|
|
|
450
|
49
|
|
|
|
|
255
|
$self->query_form(@new); |
451
|
|
|
|
|
|
|
|
452
|
49
|
|
|
|
|
175
|
return $old; |
453
|
|
|
|
|
|
|
} |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
=head2 path_query |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
Returns a string representation of the path plus the query string. See |
458
|
|
|
|
|
|
|
L. |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
=cut |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
sub path_query { |
463
|
2
|
|
|
2
|
1
|
3
|
my $self = shift; |
464
|
2
|
|
|
|
|
5
|
my ($path, $query) = ($self->path, $self->query); |
465
|
|
|
|
|
|
|
|
466
|
2
|
50
|
|
|
|
8
|
my $old = $path . ($query ? "?$query" : ''); |
467
|
|
|
|
|
|
|
|
468
|
2
|
100
|
|
|
|
6
|
if (@_) { |
469
|
1
|
|
|
|
|
12
|
my $uri = URI->new($_[0]); |
470
|
1
|
|
|
|
|
33
|
$self->$_([ $uri->$_ ]) for qw( path_segments query_form ); |
471
|
|
|
|
|
|
|
} |
472
|
|
|
|
|
|
|
|
473
|
2
|
|
|
|
|
22
|
return $old |
474
|
|
|
|
|
|
|
} |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
=head2 query_param |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
@keys = $uri->query_param |
479
|
|
|
|
|
|
|
@values = $uri->query_param($key) |
480
|
|
|
|
|
|
|
@old_values = $uri->query_param($key, @new_values); |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
This works exactly like the method of the same name implemented in |
483
|
|
|
|
|
|
|
L. |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
With no arguments, all unique query field names are returned |
486
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
With one argument, all values for the given field name are returned |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
With more than one argument, values for the given key (first argument) are set |
490
|
|
|
|
|
|
|
to the given values (remaining arguments). Care is taken in this case to |
491
|
|
|
|
|
|
|
preserve the ordering of the fields. |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
=cut |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
sub query_param { |
496
|
18
|
|
|
18
|
1
|
74
|
my ($self, $key, @values) = @_; |
497
|
18
|
|
|
|
|
41
|
my @form = $self->query_form; |
498
|
|
|
|
|
|
|
|
499
|
18
|
100
|
|
|
|
38
|
if ($key) { |
500
|
12
|
|
100
|
|
|
174
|
my @indices = grep $_ % 2 == 0 && $form[$_] eq $key, 0 .. $#form; |
501
|
12
|
|
|
|
|
42
|
my @old_values = @form[ map $_ + 1, @indices ]; |
502
|
|
|
|
|
|
|
|
503
|
12
|
100
|
|
|
|
34
|
if (@values) { |
504
|
2
|
|
|
|
|
5
|
@values = _flatten @values; |
505
|
2
|
|
|
|
|
11
|
splice @form, pop @indices, 2 while @indices > @values; |
506
|
|
|
|
|
|
|
|
507
|
2
|
100
|
|
|
|
6
|
my $last_index = @indices ? $indices[-1] + 2 : @form; |
508
|
|
|
|
|
|
|
|
509
|
2
|
|
100
|
|
|
11
|
while (@values && @indices) { |
510
|
3
|
|
|
|
|
15
|
splice @form, shift @indices, 2, $key, shift @values; |
511
|
|
|
|
|
|
|
} |
512
|
|
|
|
|
|
|
|
513
|
2
|
100
|
|
|
|
4
|
if (@values) { |
514
|
1
|
|
|
|
|
3
|
splice @form, $last_index, 0, map { $key => $_ } @values; |
|
1
|
|
|
|
|
3
|
|
515
|
|
|
|
|
|
|
} |
516
|
|
|
|
|
|
|
|
517
|
2
|
|
|
|
|
6
|
$self->query_form(@form); |
518
|
|
|
|
|
|
|
} |
519
|
|
|
|
|
|
|
|
520
|
12
|
100
|
|
|
|
78
|
return wantarray ? @old_values : $old_values[0]; |
521
|
|
|
|
|
|
|
} |
522
|
|
|
|
|
|
|
else { |
523
|
6
|
|
|
|
|
8
|
my %seen; |
524
|
6
|
|
|
|
|
68
|
return grep !$seen{$_}++, map $form[$_], grep $_ % 2 == 0, 0 .. $#form; |
525
|
|
|
|
|
|
|
} |
526
|
|
|
|
|
|
|
} |
527
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
=head2 query_param_append |
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
$uri->query_param_append($key, @values) |
531
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
Appends fields to the end of the C. Returns nothing. |
533
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
=cut |
535
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
sub query_param_append { |
537
|
1
|
|
|
1
|
1
|
4
|
my ($self, $key, @values) = @_; |
538
|
|
|
|
|
|
|
|
539
|
1
|
|
|
|
|
3
|
$self->query_form($self->query_form, map { $key => $_ } _flatten @values); |
|
4
|
|
|
|
|
7
|
|
540
|
|
|
|
|
|
|
|
541
|
1
|
|
|
|
|
4
|
return; |
542
|
|
|
|
|
|
|
} |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
=head2 query_param_delete |
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
@old_values = $uri->query_param_delete($key) |
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
Removes all fields with the given key from the C. |
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
=cut |
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
sub query_param_delete { |
553
|
1
|
|
|
1
|
1
|
2
|
my ($self, $key) = @_; |
554
|
|
|
|
|
|
|
|
555
|
1
|
|
|
|
|
4
|
return $self->query_param($key, []); |
556
|
|
|
|
|
|
|
} |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
=head2 query_form_hash |
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
$hashref = $uri->query_form_hash |
561
|
|
|
|
|
|
|
$old_hashref = $uri->query_form_hash(\%new_hashref) |
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
A hash representation of the C, with multiple values represented |
564
|
|
|
|
|
|
|
as arrayrefs. |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
=cut |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
sub query_form_hash { |
569
|
8
|
|
|
8
|
1
|
13
|
my $self = shift; |
570
|
8
|
|
|
|
|
9
|
my @new; |
571
|
|
|
|
|
|
|
|
572
|
8
|
100
|
100
|
|
|
53
|
if (my %form = @_ == 1 && ref $_[0] eq 'HASH' ? %{ $_[0] } : @_) { |
|
2
|
100
|
|
|
|
10
|
|
573
|
4
|
|
|
|
|
18
|
@new = _flatten_hash(\%form); |
574
|
|
|
|
|
|
|
} |
575
|
|
|
|
|
|
|
|
576
|
8
|
100
|
|
|
|
21
|
unless (defined wantarray) { |
577
|
|
|
|
|
|
|
# void context, don't bother building the hash |
578
|
3
|
|
|
|
|
8
|
$self->query_form(@new); |
579
|
3
|
|
|
|
|
12
|
return; |
580
|
|
|
|
|
|
|
} |
581
|
|
|
|
|
|
|
|
582
|
7
|
|
|
|
|
18
|
my %form = map { |
583
|
5
|
|
|
|
|
14
|
my @values = $self->query_param($_); |
584
|
7
|
100
|
|
|
|
36
|
( $_ => @values == 1 ? $values[0] : \@values ); |
585
|
|
|
|
|
|
|
} $self->query_param; |
586
|
|
|
|
|
|
|
|
587
|
5
|
100
|
|
|
|
15
|
$self->query_form(@new) if @new; |
588
|
|
|
|
|
|
|
|
589
|
5
|
|
|
|
|
43
|
return \%form; |
590
|
|
|
|
|
|
|
} |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
=head1 TODO |
593
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
The following URI methods are currently not implemented: |
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
=over |
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
=item * as_iri |
599
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
=item * ihost |
601
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
=back |
603
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
=head1 LICENSE |
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
L |
607
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
=cut |
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
1; |
611
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
__END__ |