line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# Perl WebDAV client library |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
package HTTP::DAV; |
4
|
|
|
|
|
|
|
|
5
|
22
|
|
|
22
|
|
47875
|
use strict; |
|
22
|
|
|
|
|
35
|
|
|
22
|
|
|
|
|
918
|
|
6
|
22
|
|
|
22
|
|
83
|
use vars qw($VERSION $VERSION_DATE $DEBUG); |
|
22
|
|
|
|
|
24
|
|
|
22
|
|
|
|
|
1532
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
# Globals |
9
|
|
|
|
|
|
|
$VERSION = '0.48'; |
10
|
|
|
|
|
|
|
$VERSION_DATE = '2015/03/26'; |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
# Set this up to 3 |
13
|
|
|
|
|
|
|
$DEBUG = 0; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
#use Carp (cluck); |
16
|
22
|
|
|
22
|
|
97
|
use Cwd (); # Can't import all of it, cwd clashes with our namespace. |
|
22
|
|
|
|
|
26
|
|
|
22
|
|
|
|
|
371
|
|
17
|
22
|
|
|
22
|
|
155501
|
use LWP; |
|
22
|
|
|
|
|
953572
|
|
|
22
|
|
|
|
|
744
|
|
18
|
22
|
|
|
22
|
|
18528
|
use XML::DOM; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
use Time::Local; |
20
|
|
|
|
|
|
|
use HTTP::DAV::Lock; |
21
|
|
|
|
|
|
|
use HTTP::DAV::ResourceList; |
22
|
|
|
|
|
|
|
use HTTP::DAV::Resource; |
23
|
|
|
|
|
|
|
use HTTP::DAV::Comms; |
24
|
|
|
|
|
|
|
use URI::file; |
25
|
|
|
|
|
|
|
use URI::Escape; |
26
|
|
|
|
|
|
|
use FileHandle; |
27
|
|
|
|
|
|
|
use File::Glob; |
28
|
|
|
|
|
|
|
use File::Temp (); |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
sub new { |
31
|
|
|
|
|
|
|
my $class = shift; |
32
|
|
|
|
|
|
|
my $self = bless {}, ref($class) || $class; |
33
|
|
|
|
|
|
|
$self->_init(@_); |
34
|
|
|
|
|
|
|
return $self; |
35
|
|
|
|
|
|
|
} |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
########################################################################### |
38
|
|
|
|
|
|
|
sub clone { |
39
|
|
|
|
|
|
|
my $self = @_; |
40
|
|
|
|
|
|
|
my $class = ref($self); |
41
|
|
|
|
|
|
|
my %clone = %{$self}; |
42
|
|
|
|
|
|
|
bless {%clone}, $class; |
43
|
|
|
|
|
|
|
} |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
########################################################################### |
46
|
|
|
|
|
|
|
{ |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
sub _init { |
49
|
|
|
|
|
|
|
my ( $self, @p ) = @_; |
50
|
|
|
|
|
|
|
my ( $uri, $headers, $useragent ) |
51
|
|
|
|
|
|
|
= HTTP::DAV::Utils::rearrange( [ 'URI', 'HEADERS', 'USERAGENT' ], |
52
|
|
|
|
|
|
|
@p ); |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
$self->{_lockedresourcelist} = HTTP::DAV::ResourceList->new(); |
55
|
|
|
|
|
|
|
$self->{_comms} = HTTP::DAV::Comms->new( |
56
|
|
|
|
|
|
|
-useragent => $useragent, |
57
|
|
|
|
|
|
|
-headers => $headers |
58
|
|
|
|
|
|
|
); |
59
|
|
|
|
|
|
|
if ($uri) { |
60
|
|
|
|
|
|
|
$self->set_workingresource( $self->new_resource( -uri => $uri ) ); |
61
|
|
|
|
|
|
|
} |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
return $self; |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
} |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
sub DebugLevel { |
68
|
|
|
|
|
|
|
shift if ref( $_[0] ) =~ /HTTP/; |
69
|
|
|
|
|
|
|
my $level = shift; |
70
|
|
|
|
|
|
|
$level = 256 if !defined $level || $level eq ""; |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
$DEBUG = $level; |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
sub _tempfile { |
76
|
|
|
|
|
|
|
my ($prefix, $tempdir) = @_; |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
$prefix ||= 'dav'; |
79
|
|
|
|
|
|
|
$tempdir ||= '/tmp'; |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
my $template = $prefix . 'XXXXXXXXXXXXX'; |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
my $old_umask = umask 0077; |
84
|
|
|
|
|
|
|
my ($fh, $filename) = File::Temp::tempfile($template, |
85
|
|
|
|
|
|
|
DIR => $tempdir, |
86
|
|
|
|
|
|
|
SUFFIX => '.tmp' |
87
|
|
|
|
|
|
|
); |
88
|
|
|
|
|
|
|
umask $old_umask; |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
return wantarray |
91
|
|
|
|
|
|
|
? ($fh, $filename) |
92
|
|
|
|
|
|
|
: $filename; |
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
###################################################################### |
96
|
|
|
|
|
|
|
# new_resource acts as a resource factory. |
97
|
|
|
|
|
|
|
# It will create a new one for you each time you ask. |
98
|
|
|
|
|
|
|
# Sometimes, if it holds state information about this |
99
|
|
|
|
|
|
|
# URL, it may return an old populated object. |
100
|
|
|
|
|
|
|
sub new_resource { |
101
|
|
|
|
|
|
|
my ($self) = shift; |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
#### |
104
|
|
|
|
|
|
|
# This is the order of the arguments unless used as |
105
|
|
|
|
|
|
|
# named parameters |
106
|
|
|
|
|
|
|
my ($uri) = HTTP::DAV::Utils::rearrange( ['URI'], @_ ); |
107
|
|
|
|
|
|
|
$uri = HTTP::DAV::Utils::make_uri($uri); |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
#cluck "new_resource: now $uri\n"; |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
my $resource = $self->{_lockedresourcelist}->get_member($uri); |
112
|
|
|
|
|
|
|
if ($resource) { |
113
|
|
|
|
|
|
|
print |
114
|
|
|
|
|
|
|
"new_resource: For $uri, returning existing resource $resource\n" |
115
|
|
|
|
|
|
|
if $HTTP::DAV::DEBUG > 2; |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
# Just reset the url to honour trailing slash status. |
118
|
|
|
|
|
|
|
$resource->set_uri($uri); |
119
|
|
|
|
|
|
|
return $resource; |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
else { |
122
|
|
|
|
|
|
|
print "new_resource: For $uri, creating new resource\n" |
123
|
|
|
|
|
|
|
if $HTTP::DAV::DEBUG > 2; |
124
|
|
|
|
|
|
|
return HTTP::DAV::Resource->new( |
125
|
|
|
|
|
|
|
-Comms => $self->{_comms}, |
126
|
|
|
|
|
|
|
-LockedResourceList => $self->{_lockedresourcelist}, |
127
|
|
|
|
|
|
|
-uri => $uri, |
128
|
|
|
|
|
|
|
-Client => $self |
129
|
|
|
|
|
|
|
); |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
########################################################################### |
134
|
|
|
|
|
|
|
# ACCESSOR METHODS |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
# GET |
137
|
|
|
|
|
|
|
sub get_user_agent { $_[0]->{_comms}->get_user_agent(); } |
138
|
|
|
|
|
|
|
sub get_last_request { $_[0]->{_comms}->get_last_request(); } |
139
|
|
|
|
|
|
|
sub get_last_response { $_[0]->{_comms}->get_last_response(); } |
140
|
|
|
|
|
|
|
sub get_workingresource { $_[0]->{_workingresource} } |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
sub get_workingurl { |
143
|
|
|
|
|
|
|
$_[0]->{_workingresource}->get_uri() |
144
|
|
|
|
|
|
|
if defined $_[0]->{_workingresource}; |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
sub get_lockedresourcelist { $_[0]->{_lockedresourcelist} } |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
# SET |
149
|
|
|
|
|
|
|
sub set_workingresource { $_[0]->{_workingresource} = $_[1]; } |
150
|
|
|
|
|
|
|
sub credentials { shift->{_comms}->credentials(@_); } |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
###################################################################### |
153
|
|
|
|
|
|
|
# Error handling |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
## Error conditions |
156
|
|
|
|
|
|
|
my %err = ( |
157
|
|
|
|
|
|
|
'ERR_WRONG_ARGS' => 'Wrong number of arguments supplied.', |
158
|
|
|
|
|
|
|
'ERR_UNAUTHORIZED' => 'Unauthorized. ', |
159
|
|
|
|
|
|
|
'ERR_NULL_RESOURCE' => 'Not connected. Do an open first. ', |
160
|
|
|
|
|
|
|
'ERR_RESP_FAIL' => 'Server response: ', |
161
|
|
|
|
|
|
|
'ERR_501' => 'Server response: ', |
162
|
|
|
|
|
|
|
'ERR_405' => 'Server response: ', |
163
|
|
|
|
|
|
|
'ERR_GENERIC' => '', |
164
|
|
|
|
|
|
|
); |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
sub err { |
167
|
|
|
|
|
|
|
my ( $self, $error, $mesg, $url ) = @_; |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
my $err_msg; |
170
|
|
|
|
|
|
|
$err_msg = ""; |
171
|
|
|
|
|
|
|
$err_msg .= $err{$error} if defined $err{$error}; |
172
|
|
|
|
|
|
|
$err_msg .= $mesg if defined $mesg; |
173
|
|
|
|
|
|
|
$err_msg .= "ERROR" unless defined $err_msg; |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
$self->{_message} = $err_msg; |
176
|
|
|
|
|
|
|
my $callback = $self->{_callback}; |
177
|
|
|
|
|
|
|
&$callback( 0, $err_msg, $url ) if $callback; |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
if ( $self->{_multi_op} ) { |
180
|
|
|
|
|
|
|
push( @{ $self->{_errors} }, $err_msg ); |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
$self->{_status} = 0; |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
return 0; |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
sub ok { |
188
|
|
|
|
|
|
|
my ($self, $mesg, $url, $so_far, $length) = @_; |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
$self->{_message} = $mesg; |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
my $callback = $self->{_callback}; |
193
|
|
|
|
|
|
|
&$callback(1, $mesg, $url, $so_far, $length) if $callback; |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
if ($self->{_multi_op}) { |
196
|
|
|
|
|
|
|
$self->{_status} = 1 unless $self->{_status} == 0; |
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
else { |
199
|
|
|
|
|
|
|
$self->{_status} = 1; |
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
return 1; |
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
sub _start_multi_op { |
205
|
|
|
|
|
|
|
my ($self, $mesg, $callback) = @_; |
206
|
|
|
|
|
|
|
$self->{_multi_mesg} = $mesg || ""; |
207
|
|
|
|
|
|
|
$self->{_status} = 1; |
208
|
|
|
|
|
|
|
$self->{_errors} = []; |
209
|
|
|
|
|
|
|
$self->{_multi_op} = 1; |
210
|
|
|
|
|
|
|
$self->{_callback} = $callback if defined $callback; |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
sub _end_multi_op { |
214
|
|
|
|
|
|
|
my ($self) = @_; |
215
|
|
|
|
|
|
|
$self->{_multi_op} = 0; |
216
|
|
|
|
|
|
|
$self->{_callback} = undef; |
217
|
|
|
|
|
|
|
my $message = $self->{_multi_mesg} . " "; |
218
|
|
|
|
|
|
|
$message .= ( $self->{_status} ) ? "succeeded" : "failed"; |
219
|
|
|
|
|
|
|
$self->{_message} = $message; |
220
|
|
|
|
|
|
|
$self->{_multi_mesg} = undef; |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
sub message { |
224
|
|
|
|
|
|
|
my ($self) = @_; |
225
|
|
|
|
|
|
|
return $self->{_message} || ""; |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
sub errors { |
229
|
|
|
|
|
|
|
my ($self) = @_; |
230
|
|
|
|
|
|
|
my $err_ref = $self->{_errors} || []; |
231
|
|
|
|
|
|
|
return @{ $err_ref }; |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
sub is_success { |
235
|
|
|
|
|
|
|
my ($self) = @_; |
236
|
|
|
|
|
|
|
return $self->{_status}; |
237
|
|
|
|
|
|
|
} |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
###################################################################### |
240
|
|
|
|
|
|
|
# Operations |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
# CWD |
243
|
|
|
|
|
|
|
sub cwd { |
244
|
|
|
|
|
|
|
my ( $self, @p ) = @_; |
245
|
|
|
|
|
|
|
my ($url) = HTTP::DAV::Utils::rearrange( ['URL'], @p ); |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
return $self->err('ERR_WRONG_ARGS') if ( !defined $url || $url eq "" ); |
248
|
|
|
|
|
|
|
return $self->err('ERR_NULL_RESOURCE') |
249
|
|
|
|
|
|
|
unless $self->get_workingresource(); |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
$url = HTTP::DAV::Utils::make_trail_slash($url); |
252
|
|
|
|
|
|
|
my $new_uri = $self->get_absolute_uri($url); |
253
|
|
|
|
|
|
|
($new_uri) = $self->get_globs($new_uri); |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
return 0 unless ($new_uri); |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
print "cwd: Changing to $new_uri\n" if $DEBUG; |
258
|
|
|
|
|
|
|
return $self->open($new_uri); |
259
|
|
|
|
|
|
|
} |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
# DELETE |
262
|
|
|
|
|
|
|
sub delete { |
263
|
|
|
|
|
|
|
my ( $self, @p ) = @_; |
264
|
|
|
|
|
|
|
my ( $url, $callback ) |
265
|
|
|
|
|
|
|
= HTTP::DAV::Utils::rearrange( [ 'URL', 'CALLBACK' ], @p ); |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
return $self->err('ERR_WRONG_ARGS') if ( !defined $url || $url eq "" ); |
268
|
|
|
|
|
|
|
return $self->err('ERR_NULL_RESOURCE') |
269
|
|
|
|
|
|
|
unless $self->get_workingresource(); |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
my $new_url = $self->get_absolute_uri($url); |
272
|
|
|
|
|
|
|
my @urls = $self->get_globs($new_url); |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
$self->_start_multi_op( "delete $url", $callback ) if @urls > 1; |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
foreach my $u (@urls) { |
277
|
|
|
|
|
|
|
my $resource = $self->new_resource( -uri => $u ); |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
my $resp = $resource->delete(); |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
if ( $resp->is_success ) { |
282
|
|
|
|
|
|
|
$self->ok( "deleted $u successfully", $u ); |
283
|
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
else { |
285
|
|
|
|
|
|
|
$self->err( 'ERR_RESP_FAIL', $resp->message(), $u ); |
286
|
|
|
|
|
|
|
} |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
$self->_end_multi_op() if @urls > 1; |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
return $self->is_success; |
292
|
|
|
|
|
|
|
} |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
# GET |
295
|
|
|
|
|
|
|
# Handles globs by doing multiple recursive gets |
296
|
|
|
|
|
|
|
# GET dir* produces |
297
|
|
|
|
|
|
|
# _get dir1, to_local |
298
|
|
|
|
|
|
|
# _get dir2, to_local |
299
|
|
|
|
|
|
|
# _get dir3, to_local |
300
|
|
|
|
|
|
|
sub get { |
301
|
|
|
|
|
|
|
my ( $self, @p ) = @_; |
302
|
|
|
|
|
|
|
my ( $url, $to, $callback, $chunk ) |
303
|
|
|
|
|
|
|
= HTTP::DAV::Utils::rearrange( [ 'URL', 'TO', 'CALLBACK', 'CHUNK' ], |
304
|
|
|
|
|
|
|
@p ); |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
return $self->err('ERR_WRONG_ARGS') if ( !defined $url || $url eq "" ); |
307
|
|
|
|
|
|
|
return $self->err('ERR_NULL_RESOURCE') |
308
|
|
|
|
|
|
|
unless $self->get_workingresource(); |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
$self->_start_multi_op( "get $url", $callback ); |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
my $new_url = $self->get_absolute_uri($url); |
313
|
|
|
|
|
|
|
my (@urls) = $self->get_globs($new_url); |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
return 0 unless ( $#urls > -1 ); |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
############ |
318
|
|
|
|
|
|
|
# HANDLE -TO |
319
|
|
|
|
|
|
|
# |
320
|
|
|
|
|
|
|
$to ||= ''; |
321
|
|
|
|
|
|
|
if ( $to eq '.' ) { |
322
|
|
|
|
|
|
|
$to = Cwd::getcwd(); |
323
|
|
|
|
|
|
|
} |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
# If the TO argument is a file handle or a scalar |
326
|
|
|
|
|
|
|
# then check that we only got one glob. If we got multiple |
327
|
|
|
|
|
|
|
# globs, then we can't keep going because we can't write multiple files |
328
|
|
|
|
|
|
|
# to one FileHandle. |
329
|
|
|
|
|
|
|
if ( $#urls > 0 ) { |
330
|
|
|
|
|
|
|
if ( ref($to) =~ /SCALAR/ ) { |
331
|
|
|
|
|
|
|
return $self->err( 'ERR_WRONG_ARGS', |
332
|
|
|
|
|
|
|
"Can't retrieve multiple files to a single scalar\n" ); |
333
|
|
|
|
|
|
|
} |
334
|
|
|
|
|
|
|
elsif ( ref($to) =~ /GLOB/ ) { |
335
|
|
|
|
|
|
|
return $self->err( 'ERR_WRONG_ARGS', |
336
|
|
|
|
|
|
|
"Can't retrieve multiple files to a single filehandle\n" ); |
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
# If it's a dir, remove last '/' from destination. |
341
|
|
|
|
|
|
|
# Later we need to concatenate the destination filename. |
342
|
|
|
|
|
|
|
if ( defined $to && $to ne '' && -d $to ) { |
343
|
|
|
|
|
|
|
$to =~ s{/$}{}; |
344
|
|
|
|
|
|
|
} |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
# Foreach file... do the get. |
347
|
|
|
|
|
|
|
foreach my $u (@urls) { |
348
|
|
|
|
|
|
|
my ( $left, $leafname ) = HTTP::DAV::Utils::split_leaf($u); |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
# Handle SCALARREF and GLOB cases |
351
|
|
|
|
|
|
|
my $dest_file = $to; |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
# Directories |
354
|
|
|
|
|
|
|
if ( -d $to ) { |
355
|
|
|
|
|
|
|
$dest_file = "$to/$leafname"; |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
# Multiple targets |
358
|
|
|
|
|
|
|
} |
359
|
|
|
|
|
|
|
elsif ( !defined $to || $to eq "" ) { |
360
|
|
|
|
|
|
|
$dest_file = $leafname; |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
warn "get: $u -> $dest_file\n" if $DEBUG; |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
# Setup the resource based on the passed url and do a propfind. |
366
|
|
|
|
|
|
|
my $resource = $self->new_resource( -uri => $u ); |
367
|
|
|
|
|
|
|
my $resp = $resource->propfind( -depth => 1 ); |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
if ( $resp->is_error ) { |
370
|
|
|
|
|
|
|
return $self->err( 'ERR_RESP_FAIL', $resp->message(), $u ); |
371
|
|
|
|
|
|
|
} |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
$self->_get( $resource, $dest_file, $callback, $chunk ); |
374
|
|
|
|
|
|
|
} |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
$self->_end_multi_op(); |
377
|
|
|
|
|
|
|
return $self->is_success; |
378
|
|
|
|
|
|
|
} |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
# Note: is is expected that $resource has had |
381
|
|
|
|
|
|
|
# a propfind depth 1 performed on it. |
382
|
|
|
|
|
|
|
# |
383
|
|
|
|
|
|
|
sub _get { |
384
|
|
|
|
|
|
|
my ( $self, @p ) = @_; |
385
|
|
|
|
|
|
|
my ( $resource, $local_name, $callback, $chunk ) |
386
|
|
|
|
|
|
|
= HTTP::DAV::Utils::rearrange( |
387
|
|
|
|
|
|
|
[ 'RESOURCE', 'TO', 'CALLBACK', 'CHUNK' ], @p ); |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
my $url = $resource->get_uri(); |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
# GET A DIRECTORY |
392
|
|
|
|
|
|
|
if ( $resource->is_collection ) { |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
# If the TO argument is a file handle, a scalar or empty |
395
|
|
|
|
|
|
|
# then we |
396
|
|
|
|
|
|
|
# can't keep going because we can't write multiple files |
397
|
|
|
|
|
|
|
# to one FileHandle, scalar, etc. |
398
|
|
|
|
|
|
|
if ( ref($local_name) =~ /SCALAR/ ) { |
399
|
|
|
|
|
|
|
return $self->err( 'ERR_WRONG_ARGS', |
400
|
|
|
|
|
|
|
"Can't retrieve a collection to a scalar\n", $url ); |
401
|
|
|
|
|
|
|
} |
402
|
|
|
|
|
|
|
elsif ( ref($local_name) =~ /GLOB/ ) { |
403
|
|
|
|
|
|
|
return $self->err( 'ERR_WRONG_ARGS', |
404
|
|
|
|
|
|
|
"Can't retrieve a collection to a filehandle\n", $url ); |
405
|
|
|
|
|
|
|
} |
406
|
|
|
|
|
|
|
elsif ( $local_name eq "" ) { |
407
|
|
|
|
|
|
|
return $self->err( |
408
|
|
|
|
|
|
|
'ERR_GENERIC', |
409
|
|
|
|
|
|
|
"Can't retrieve a collection without a target directory (-to).", |
410
|
|
|
|
|
|
|
$url |
411
|
|
|
|
|
|
|
); |
412
|
|
|
|
|
|
|
} |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
# Try and make the directory locally |
415
|
|
|
|
|
|
|
print "MKDIR $local_name (before escape)\n" if $DEBUG > 2; |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
$local_name = URI::Escape::uri_unescape($local_name); |
418
|
|
|
|
|
|
|
if ( !mkdir $local_name ) { |
419
|
|
|
|
|
|
|
return $self->err( 'ERR_GENERIC', |
420
|
|
|
|
|
|
|
"mkdir local:$local_name failed: $!" ); |
421
|
|
|
|
|
|
|
} |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
$self->ok("mkdir $local_name"); |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
# This is the degenerate case for an empty dir. |
426
|
|
|
|
|
|
|
print "Made directory $local_name\n" if $DEBUG > 2; |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
my $resource_list = $resource->get_resourcelist(); |
429
|
|
|
|
|
|
|
if ($resource_list) { |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
# FOREACH FILE IN COLLECTION, GET IT. |
432
|
|
|
|
|
|
|
foreach my $progeny_r ( $resource_list->get_resources() ) { |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
my $progeny_url = $progeny_r->get_uri(); |
435
|
|
|
|
|
|
|
print "Found progeny:$progeny_url\n" if $DEBUG > 2; |
436
|
|
|
|
|
|
|
my $progeny_local_filename |
437
|
|
|
|
|
|
|
= HTTP::DAV::Utils::get_leafname($progeny_url); |
438
|
|
|
|
|
|
|
$progeny_local_filename |
439
|
|
|
|
|
|
|
= URI::Escape::uri_unescape($progeny_local_filename); |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
$progeny_local_filename |
442
|
|
|
|
|
|
|
= URI::file->new($progeny_local_filename) |
443
|
|
|
|
|
|
|
->abs("$local_name/"); |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
if ( $progeny_r->is_collection() ) { |
446
|
|
|
|
|
|
|
$progeny_r->propfind( -depth => 1 ); |
447
|
|
|
|
|
|
|
} |
448
|
|
|
|
|
|
|
$self->_get( $progeny_r, $progeny_local_filename, $callback, |
449
|
|
|
|
|
|
|
$chunk ); |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
# } else { |
452
|
|
|
|
|
|
|
# $self->_do_get_tofile($progeny_r,$progeny_local_filename); |
453
|
|
|
|
|
|
|
# } |
454
|
|
|
|
|
|
|
} |
455
|
|
|
|
|
|
|
} |
456
|
|
|
|
|
|
|
} |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
# GET A FILE |
459
|
|
|
|
|
|
|
else { |
460
|
|
|
|
|
|
|
my $response; |
461
|
|
|
|
|
|
|
my $name_ref = ref $local_name; |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
if ( $callback || $name_ref =~ /SCALAR/ || $name_ref =~ /GLOB/ ) { |
464
|
|
|
|
|
|
|
$self->{_so_far} = 0; |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
my $fh; |
467
|
|
|
|
|
|
|
my $put_to_scalar = 0; |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
if ( $name_ref =~ /GLOB/ ) { |
470
|
|
|
|
|
|
|
$fh = $local_name; |
471
|
|
|
|
|
|
|
} |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
elsif ( $name_ref =~ /SCALAR/ ) { |
474
|
|
|
|
|
|
|
$put_to_scalar = 1; |
475
|
|
|
|
|
|
|
$$local_name = ""; |
476
|
|
|
|
|
|
|
} |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
else { |
479
|
|
|
|
|
|
|
$fh = FileHandle->new; |
480
|
|
|
|
|
|
|
$local_name = URI::Escape::uri_unescape($local_name); |
481
|
|
|
|
|
|
|
if (! $fh->open(">$local_name") ) { |
482
|
|
|
|
|
|
|
return $self->err( |
483
|
|
|
|
|
|
|
'ERR_GENERIC', |
484
|
|
|
|
|
|
|
"open \">$local_name\" failed: $!", |
485
|
|
|
|
|
|
|
$url |
486
|
|
|
|
|
|
|
); |
487
|
|
|
|
|
|
|
} |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
# RT #29788, avoid file corruptions on Win32 |
490
|
|
|
|
|
|
|
binmode $fh; |
491
|
|
|
|
|
|
|
} |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
$self->{_fh} = $fh; |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
$response = $resource->get( |
496
|
|
|
|
|
|
|
-chunk => $chunk, |
497
|
|
|
|
|
|
|
-progress_callback => |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
sub { |
500
|
|
|
|
|
|
|
my ( $data, $response, $protocol ) = @_; |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
$self->{_so_far} += length($data); |
503
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
my $fh = $self->{_fh}; |
505
|
|
|
|
|
|
|
print $fh $data if defined $fh; |
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
$$local_name .= $data if ($put_to_scalar); |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
my $user_callback = $self->{_callback}; |
510
|
|
|
|
|
|
|
&$user_callback( -1, "transfer in progress", |
511
|
|
|
|
|
|
|
$url, $self->{_so_far}, $response->content_length(), |
512
|
|
|
|
|
|
|
$data ) |
513
|
|
|
|
|
|
|
if defined $user_callback; |
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
} |
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
); # end get( ... ); |
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
# Close the filehandle if it was set. |
520
|
|
|
|
|
|
|
if ( defined $self->{_fh} ) { |
521
|
|
|
|
|
|
|
$self->{_fh}->close(); |
522
|
|
|
|
|
|
|
delete $self->{_fh}; |
523
|
|
|
|
|
|
|
} |
524
|
|
|
|
|
|
|
} |
525
|
|
|
|
|
|
|
else { |
526
|
|
|
|
|
|
|
$local_name = URI::Escape::uri_unescape($local_name); |
527
|
|
|
|
|
|
|
$response = $resource->get( -save_to => $local_name ); |
528
|
|
|
|
|
|
|
} |
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
# Handle response |
531
|
|
|
|
|
|
|
if ( $response->is_error ) { |
532
|
|
|
|
|
|
|
return $self->err( 'ERR_GENERIC', |
533
|
|
|
|
|
|
|
"get $url failed: " . $response->message, $url ); |
534
|
|
|
|
|
|
|
} |
535
|
|
|
|
|
|
|
else { |
536
|
|
|
|
|
|
|
return $self->ok( "get $url", $url, $self->{_so_far}, |
537
|
|
|
|
|
|
|
$response->content_length() ); |
538
|
|
|
|
|
|
|
} |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
} |
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
return 1; |
543
|
|
|
|
|
|
|
} |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
# LOCK |
546
|
|
|
|
|
|
|
sub lock { |
547
|
|
|
|
|
|
|
my ( $self, @p ) = @_; |
548
|
|
|
|
|
|
|
my ( $url, $owner, $depth, $timeout, $scope, $type, @other ) |
549
|
|
|
|
|
|
|
= HTTP::DAV::Utils::rearrange( |
550
|
|
|
|
|
|
|
[ 'URL', 'OWNER', 'DEPTH', 'TIMEOUT', 'SCOPE', 'TYPE' ], @p ); |
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
return $self->err('ERR_NULL_RESOURCE') |
553
|
|
|
|
|
|
|
unless $self->get_workingresource(); |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
my $resource; |
556
|
|
|
|
|
|
|
if ($url) { |
557
|
|
|
|
|
|
|
$url = $self->get_absolute_uri($url); |
558
|
|
|
|
|
|
|
$resource = $self->new_resource( -uri => $url ); |
559
|
|
|
|
|
|
|
} |
560
|
|
|
|
|
|
|
else { |
561
|
|
|
|
|
|
|
$resource = $self->get_workingresource(); |
562
|
|
|
|
|
|
|
$url = $resource->get_uri; |
563
|
|
|
|
|
|
|
} |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
# Make the lock |
566
|
|
|
|
|
|
|
my $resp = $resource->lock( |
567
|
|
|
|
|
|
|
-owner => $owner, |
568
|
|
|
|
|
|
|
-depth => $depth, |
569
|
|
|
|
|
|
|
-timeout => $timeout, |
570
|
|
|
|
|
|
|
-scope => $scope, |
571
|
|
|
|
|
|
|
-type => $type |
572
|
|
|
|
|
|
|
); |
573
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
if ( $resp->is_success() ) { |
575
|
|
|
|
|
|
|
return $self->ok( "lock $url succeeded", $url ); |
576
|
|
|
|
|
|
|
} |
577
|
|
|
|
|
|
|
else { |
578
|
|
|
|
|
|
|
return $self->err( 'ERR_RESP_FAIL', $resp->message, $url ); |
579
|
|
|
|
|
|
|
} |
580
|
|
|
|
|
|
|
} |
581
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
# UNLOCK |
583
|
|
|
|
|
|
|
sub unlock { |
584
|
|
|
|
|
|
|
my ( $self, @p ) = @_; |
585
|
|
|
|
|
|
|
my ($url) = HTTP::DAV::Utils::rearrange( ['URL'], @p ); |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
return $self->err('ERR_NULL_RESOURCE') |
588
|
|
|
|
|
|
|
unless $self->get_workingresource(); |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
my $resource; |
591
|
|
|
|
|
|
|
if ($url) { |
592
|
|
|
|
|
|
|
$url = $self->get_absolute_uri($url); |
593
|
|
|
|
|
|
|
$resource = $self->new_resource( -uri => $url ); |
594
|
|
|
|
|
|
|
} |
595
|
|
|
|
|
|
|
else { |
596
|
|
|
|
|
|
|
$resource = $self->get_workingresource(); |
597
|
|
|
|
|
|
|
$url = $resource->get_uri; |
598
|
|
|
|
|
|
|
} |
599
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
# Make the lock |
601
|
|
|
|
|
|
|
my $resp = $resource->unlock(); |
602
|
|
|
|
|
|
|
if ( $resp->is_success ) { |
603
|
|
|
|
|
|
|
return $self->ok( "unlock $url succeeded", $url ); |
604
|
|
|
|
|
|
|
} |
605
|
|
|
|
|
|
|
else { |
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
# The Resource.pm::lock routine has a hack |
608
|
|
|
|
|
|
|
# where if it doesn't know the locktoken, it will |
609
|
|
|
|
|
|
|
# just return an empty response with message "Client Error". |
610
|
|
|
|
|
|
|
# Make a custom message for this case. |
611
|
|
|
|
|
|
|
my $msg = $resp->message; |
612
|
|
|
|
|
|
|
if ( $msg =~ /Client error/i ) { |
613
|
|
|
|
|
|
|
$msg = "No locks found. Try steal"; |
614
|
|
|
|
|
|
|
return $self->err( 'ERR_GENERIC', $msg, $url ); |
615
|
|
|
|
|
|
|
} |
616
|
|
|
|
|
|
|
else { |
617
|
|
|
|
|
|
|
return $self->err( 'ERR_RESP_FAIL', $msg, $url ); |
618
|
|
|
|
|
|
|
} |
619
|
|
|
|
|
|
|
} |
620
|
|
|
|
|
|
|
} |
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
sub steal { |
623
|
|
|
|
|
|
|
my ( $self, @p ) = @_; |
624
|
|
|
|
|
|
|
my ($url) = HTTP::DAV::Utils::rearrange( ['URL'], @p ); |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
return $self->err('ERR_NULL_RESOURCE') |
627
|
|
|
|
|
|
|
unless $self->get_workingresource(); |
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
my $resource; |
630
|
|
|
|
|
|
|
if ($url) { |
631
|
|
|
|
|
|
|
$url = $self->get_absolute_uri($url); |
632
|
|
|
|
|
|
|
$resource = $self->new_resource( -uri => $url ); |
633
|
|
|
|
|
|
|
} |
634
|
|
|
|
|
|
|
else { |
635
|
|
|
|
|
|
|
$resource = $self->get_workingresource(); |
636
|
|
|
|
|
|
|
} |
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
# Go the steal |
639
|
|
|
|
|
|
|
my $resp = $resource->forcefully_unlock_all(); |
640
|
|
|
|
|
|
|
if ( $resp->is_success() ) { |
641
|
|
|
|
|
|
|
return $self->ok( "steal succeeded", $url ); |
642
|
|
|
|
|
|
|
} |
643
|
|
|
|
|
|
|
else { |
644
|
|
|
|
|
|
|
return $self->err( 'ERR_RESP_FAIL', $resp->message(), $url ); |
645
|
|
|
|
|
|
|
} |
646
|
|
|
|
|
|
|
} |
647
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
# MKCOL |
649
|
|
|
|
|
|
|
sub mkcol { |
650
|
|
|
|
|
|
|
my ( $self, @p ) = @_; |
651
|
|
|
|
|
|
|
my ($url) = HTTP::DAV::Utils::rearrange( ['URL'], @p ); |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
return $self->err('ERR_WRONG_ARGS') if ( !defined $url || $url eq "" ); |
654
|
|
|
|
|
|
|
return $self->err('ERR_NULL_RESOURCE') |
655
|
|
|
|
|
|
|
unless $self->get_workingresource(); |
656
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
$url = HTTP::DAV::Utils::make_trail_slash($url); |
658
|
|
|
|
|
|
|
my $new_url = $self->get_absolute_uri($url); |
659
|
|
|
|
|
|
|
my $resource = $self->new_resource( -uri => $new_url ); |
660
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
# Make the lock |
662
|
|
|
|
|
|
|
my $resp = $resource->mkcol(); |
663
|
|
|
|
|
|
|
if ( $resp->is_success() ) { |
664
|
|
|
|
|
|
|
return $self->ok( "mkcol $new_url", $new_url ); |
665
|
|
|
|
|
|
|
} |
666
|
|
|
|
|
|
|
else { |
667
|
|
|
|
|
|
|
return $self->err( 'ERR_RESP_FAIL', $resp->message(), $new_url ); |
668
|
|
|
|
|
|
|
} |
669
|
|
|
|
|
|
|
} |
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
# OPTIONS |
672
|
|
|
|
|
|
|
sub options { |
673
|
|
|
|
|
|
|
my ( $self, @p ) = @_; |
674
|
|
|
|
|
|
|
my ($url) = HTTP::DAV::Utils::rearrange( ['URL'], @p ); |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
#return $self->err('ERR_WRONG_ARGS') if (!defined $url || $url eq ""); |
677
|
|
|
|
|
|
|
return $self->err('ERR_NULL_RESOURCE') |
678
|
|
|
|
|
|
|
unless $self->get_workingresource(); |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
my $resource; |
681
|
|
|
|
|
|
|
if ($url) { |
682
|
|
|
|
|
|
|
$url = $self->get_absolute_uri($url); |
683
|
|
|
|
|
|
|
$resource = $self->new_resource( -uri => $url ); |
684
|
|
|
|
|
|
|
} |
685
|
|
|
|
|
|
|
else { |
686
|
|
|
|
|
|
|
$resource = $self->get_workingresource(); |
687
|
|
|
|
|
|
|
$url = $resource->get_uri; |
688
|
|
|
|
|
|
|
} |
689
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
# Make the call |
691
|
|
|
|
|
|
|
my $resp = $resource->options(); |
692
|
|
|
|
|
|
|
if ( $resp->is_success() ) { |
693
|
|
|
|
|
|
|
$self->ok( "options $url succeeded", $url ); |
694
|
|
|
|
|
|
|
return $resource->get_options(); |
695
|
|
|
|
|
|
|
} |
696
|
|
|
|
|
|
|
else { |
697
|
|
|
|
|
|
|
$self->err( 'ERR_RESP_FAIL', $resp->message(), $url ); |
698
|
|
|
|
|
|
|
return undef; |
699
|
|
|
|
|
|
|
} |
700
|
|
|
|
|
|
|
} |
701
|
|
|
|
|
|
|
|
702
|
|
|
|
|
|
|
# MOVE |
703
|
|
|
|
|
|
|
sub move { return shift->_move_copy( "move", @_ ); } |
704
|
|
|
|
|
|
|
sub copy { return shift->_move_copy( "copy", @_ ); } |
705
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
sub _move_copy { |
707
|
|
|
|
|
|
|
my ( $self, $method, @p ) = @_; |
708
|
|
|
|
|
|
|
my ( $url, $dest_url, $overwrite, $depth, $text, @other ) |
709
|
|
|
|
|
|
|
= HTTP::DAV::Utils::rearrange( |
710
|
|
|
|
|
|
|
[ 'URL', 'DEST', 'OVERWRITE', 'DEPTH', 'TEXT' ], @p ); |
711
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
return $self->err('ERR_NULL_RESOURCE') |
713
|
|
|
|
|
|
|
unless $self->get_workingresource(); |
714
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
if (!( defined $url && $url ne "" && defined $dest_url && $dest_url ne "" |
716
|
|
|
|
|
|
|
) |
717
|
|
|
|
|
|
|
) |
718
|
|
|
|
|
|
|
{ |
719
|
|
|
|
|
|
|
return $self->err( 'ERR_WRONG_ARGS', |
720
|
|
|
|
|
|
|
"Must supply a source and destination url" ); |
721
|
|
|
|
|
|
|
} |
722
|
|
|
|
|
|
|
|
723
|
|
|
|
|
|
|
$url = $self->get_absolute_uri($url); |
724
|
|
|
|
|
|
|
$dest_url = $self->get_absolute_uri($dest_url); |
725
|
|
|
|
|
|
|
my $resource = $self->new_resource( -uri => $url ); |
726
|
|
|
|
|
|
|
my $dest_resource = $self->new_resource( -uri => $dest_url ); |
727
|
|
|
|
|
|
|
|
728
|
|
|
|
|
|
|
my $resp = $dest_resource->propfind( -depth => 1 ); |
729
|
|
|
|
|
|
|
if ( $resp->is_success && $dest_resource->is_collection ) { |
730
|
|
|
|
|
|
|
my $leafname = HTTP::DAV::Utils::get_leafname($url); |
731
|
|
|
|
|
|
|
$dest_url = "$dest_url/$leafname"; |
732
|
|
|
|
|
|
|
$dest_resource = $self->new_resource( -uri => $dest_url ); |
733
|
|
|
|
|
|
|
} |
734
|
|
|
|
|
|
|
|
735
|
|
|
|
|
|
|
# Make the lock |
736
|
|
|
|
|
|
|
$resp = $resource->$method( |
737
|
|
|
|
|
|
|
-dest => $dest_resource, |
738
|
|
|
|
|
|
|
-overwrite => $overwrite, |
739
|
|
|
|
|
|
|
-depth => $depth, |
740
|
|
|
|
|
|
|
-text => $text, |
741
|
|
|
|
|
|
|
); |
742
|
|
|
|
|
|
|
|
743
|
|
|
|
|
|
|
if ( $resp->is_success() ) { |
744
|
|
|
|
|
|
|
return $self->ok( "$method $url to $dest_url succeeded", $url ); |
745
|
|
|
|
|
|
|
} |
746
|
|
|
|
|
|
|
else { |
747
|
|
|
|
|
|
|
return $self->err( 'ERR_RESP_FAIL', $resp->message, $url ); |
748
|
|
|
|
|
|
|
} |
749
|
|
|
|
|
|
|
} |
750
|
|
|
|
|
|
|
|
751
|
|
|
|
|
|
|
# OPEN |
752
|
|
|
|
|
|
|
# Must be a collection resource |
753
|
|
|
|
|
|
|
# $dav->open( -url => http://localhost/test/ ); |
754
|
|
|
|
|
|
|
# $dav->open( localhost/test/ ); |
755
|
|
|
|
|
|
|
# $dav->open( -url => localhost:81 ); |
756
|
|
|
|
|
|
|
# $dav->open( localhost ); |
757
|
|
|
|
|
|
|
sub open { |
758
|
|
|
|
|
|
|
my ( $self, @p ) = @_; |
759
|
|
|
|
|
|
|
my ($url) = HTTP::DAV::Utils::rearrange( ['URL'], @p ); |
760
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
my $resource; |
762
|
|
|
|
|
|
|
if ( defined $url && $url ne "" ) { |
763
|
|
|
|
|
|
|
$url = HTTP::DAV::Utils::make_trail_slash($url); |
764
|
|
|
|
|
|
|
$resource = $self->new_resource( -uri => $url ); |
765
|
|
|
|
|
|
|
} |
766
|
|
|
|
|
|
|
else { |
767
|
|
|
|
|
|
|
$resource = $self->get_workingresource(); |
768
|
|
|
|
|
|
|
$url = $resource->get_uri() if ($resource); |
769
|
|
|
|
|
|
|
return $self->err('ERR_WRONG_ARGS') |
770
|
|
|
|
|
|
|
if ( !defined $url || $url eq "" ); |
771
|
|
|
|
|
|
|
} |
772
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
my $response = $resource->propfind( -depth => 0 ); |
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
#print $response->as_string; |
776
|
|
|
|
|
|
|
#print $resource->as_string; |
777
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
my $result = $self->what_happened($url, $resource, $response); |
779
|
|
|
|
|
|
|
if ($result->{success} == 0) { |
780
|
|
|
|
|
|
|
return $self->err($result->{error_type}, $result->{error_msg}, $url); |
781
|
|
|
|
|
|
|
} |
782
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
# If it is a collection but the URI doesn't end in a trailing slash. |
784
|
|
|
|
|
|
|
# Then we need to reopen with the / |
785
|
|
|
|
|
|
|
elsif ($resource->is_collection |
786
|
|
|
|
|
|
|
&& $url !~ m#/\s*$# ) |
787
|
|
|
|
|
|
|
{ |
788
|
|
|
|
|
|
|
my $newurl = $url . "/"; |
789
|
|
|
|
|
|
|
print "Redirecting to $newurl\n" if $DEBUG > 1; |
790
|
|
|
|
|
|
|
return $self->open($newurl); |
791
|
|
|
|
|
|
|
} |
792
|
|
|
|
|
|
|
|
793
|
|
|
|
|
|
|
# If it is not a collection then we |
794
|
|
|
|
|
|
|
# can't open it. |
795
|
|
|
|
|
|
|
elsif ( !$resource->is_collection ) { |
796
|
|
|
|
|
|
|
return $self->err( 'ERR_GENERIC', |
797
|
|
|
|
|
|
|
"Operation failed. You can only open a collection (directory)", |
798
|
|
|
|
|
|
|
$url ); |
799
|
|
|
|
|
|
|
} |
800
|
|
|
|
|
|
|
else { |
801
|
|
|
|
|
|
|
$self->set_workingresource($resource); |
802
|
|
|
|
|
|
|
return $self->ok( "Connected to $url", $url ); |
803
|
|
|
|
|
|
|
} |
804
|
|
|
|
|
|
|
|
805
|
|
|
|
|
|
|
return $self->err( 'ERR_GENERIC', $url ); |
806
|
|
|
|
|
|
|
} |
807
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
# Performs a propfind and then returns the populated |
809
|
|
|
|
|
|
|
# resource. The resource will have a resourcelist if |
810
|
|
|
|
|
|
|
# it is a collection. |
811
|
|
|
|
|
|
|
sub propfind { |
812
|
|
|
|
|
|
|
my ( $self, @p ) = @_; |
813
|
|
|
|
|
|
|
my ( $url, $depth ) = HTTP::DAV::Utils::rearrange( [ 'URL', 'DEPTH' ], @p ); |
814
|
|
|
|
|
|
|
|
815
|
|
|
|
|
|
|
# depth = 1 is the default |
816
|
|
|
|
|
|
|
if (! defined $depth) { |
817
|
|
|
|
|
|
|
$depth = 1; |
818
|
|
|
|
|
|
|
} |
819
|
|
|
|
|
|
|
|
820
|
|
|
|
|
|
|
return $self->err('ERR_NULL_RESOURCE') |
821
|
|
|
|
|
|
|
unless $self->get_workingresource(); |
822
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
my $resource; |
824
|
|
|
|
|
|
|
if ($url) { |
825
|
|
|
|
|
|
|
$url = $self->get_absolute_uri($url); |
826
|
|
|
|
|
|
|
$resource = $self->new_resource( -uri => $url ); |
827
|
|
|
|
|
|
|
} |
828
|
|
|
|
|
|
|
else { |
829
|
|
|
|
|
|
|
$resource = $self->get_workingresource(); |
830
|
|
|
|
|
|
|
} |
831
|
|
|
|
|
|
|
|
832
|
|
|
|
|
|
|
# Make the call |
833
|
|
|
|
|
|
|
my $resp = $resource->propfind( -depth => $depth ); |
834
|
|
|
|
|
|
|
if ( $resp->is_success() ) { |
835
|
|
|
|
|
|
|
$resource->build_ls($resource); |
836
|
|
|
|
|
|
|
$self->ok( "propfind " . $resource->get_uri() . " succeeded", $url ); |
837
|
|
|
|
|
|
|
return $resource; |
838
|
|
|
|
|
|
|
} |
839
|
|
|
|
|
|
|
else { |
840
|
|
|
|
|
|
|
return $self->err( 'ERR_RESP_FAIL', $resp->message(), $url ); |
841
|
|
|
|
|
|
|
} |
842
|
|
|
|
|
|
|
} |
843
|
|
|
|
|
|
|
|
844
|
|
|
|
|
|
|
# Set a property on the resource |
845
|
|
|
|
|
|
|
sub set_prop { |
846
|
|
|
|
|
|
|
my ( $self, @p ) = @_; |
847
|
|
|
|
|
|
|
my ( $url, $namespace, $propname, $propvalue, $nsabbr ) |
848
|
|
|
|
|
|
|
= HTTP::DAV::Utils::rearrange( |
849
|
|
|
|
|
|
|
[ 'URL', 'NAMESPACE', 'PROPNAME', 'PROPVALUE', 'NSABBR' ], @p ); |
850
|
|
|
|
|
|
|
$self->proppatch( |
851
|
|
|
|
|
|
|
-url => $url, |
852
|
|
|
|
|
|
|
-namespace => $namespace, |
853
|
|
|
|
|
|
|
-propname => $propname, |
854
|
|
|
|
|
|
|
-propvalue => $propvalue, |
855
|
|
|
|
|
|
|
-action => "set", |
856
|
|
|
|
|
|
|
-nsabbr => $nsabbr, |
857
|
|
|
|
|
|
|
); |
858
|
|
|
|
|
|
|
} |
859
|
|
|
|
|
|
|
|
860
|
|
|
|
|
|
|
# Unsets a property on the resource |
861
|
|
|
|
|
|
|
sub unset_prop { |
862
|
|
|
|
|
|
|
my ( $self, @p ) = @_; |
863
|
|
|
|
|
|
|
my ( $url, $namespace, $propname, $nsabbr ) |
864
|
|
|
|
|
|
|
= HTTP::DAV::Utils::rearrange( |
865
|
|
|
|
|
|
|
[ 'URL', 'NAMESPACE', 'PROPNAME', 'NSABBR' ], @p ); |
866
|
|
|
|
|
|
|
$self->proppatch( |
867
|
|
|
|
|
|
|
-url => $url, |
868
|
|
|
|
|
|
|
-namespace => $namespace, |
869
|
|
|
|
|
|
|
-propname => $propname, |
870
|
|
|
|
|
|
|
-action => "remove", |
871
|
|
|
|
|
|
|
-nsabbr => $nsabbr, |
872
|
|
|
|
|
|
|
); |
873
|
|
|
|
|
|
|
} |
874
|
|
|
|
|
|
|
|
875
|
|
|
|
|
|
|
# Performs a proppatch on the resource |
876
|
|
|
|
|
|
|
sub proppatch { |
877
|
|
|
|
|
|
|
my ( $self, @p ) = @_; |
878
|
|
|
|
|
|
|
my ( $url, $namespace, $propname, $propvalue, $action, $nsabbr ) |
879
|
|
|
|
|
|
|
= HTTP::DAV::Utils::rearrange( |
880
|
|
|
|
|
|
|
[ 'URL', 'NAMESPACE', 'PROPNAME', 'PROPVALUE', 'ACTION', 'NSABBR' ], |
881
|
|
|
|
|
|
|
@p ); |
882
|
|
|
|
|
|
|
|
883
|
|
|
|
|
|
|
return $self->err('ERR_NULL_RESOURCE') |
884
|
|
|
|
|
|
|
unless $self->get_workingresource(); |
885
|
|
|
|
|
|
|
|
886
|
|
|
|
|
|
|
my $resource; |
887
|
|
|
|
|
|
|
if ($url) { |
888
|
|
|
|
|
|
|
$url = $self->get_absolute_uri($url); |
889
|
|
|
|
|
|
|
$resource = $self->new_resource( -uri => $url ); |
890
|
|
|
|
|
|
|
} |
891
|
|
|
|
|
|
|
else { |
892
|
|
|
|
|
|
|
$resource = $self->get_workingresource(); |
893
|
|
|
|
|
|
|
} |
894
|
|
|
|
|
|
|
|
895
|
|
|
|
|
|
|
# Make the call |
896
|
|
|
|
|
|
|
my $resp = $resource->proppatch( |
897
|
|
|
|
|
|
|
-namespace => $namespace, |
898
|
|
|
|
|
|
|
-propname => $propname, |
899
|
|
|
|
|
|
|
-propvalue => $propvalue, |
900
|
|
|
|
|
|
|
-action => $action, |
901
|
|
|
|
|
|
|
-nsabbr => $nsabbr |
902
|
|
|
|
|
|
|
); |
903
|
|
|
|
|
|
|
|
904
|
|
|
|
|
|
|
if ( $resp->is_success() ) { |
905
|
|
|
|
|
|
|
$resource->build_ls($resource); |
906
|
|
|
|
|
|
|
$self->ok( "proppatch " . $resource->get_uri() . " succeeded", $url ); |
907
|
|
|
|
|
|
|
return $resource; |
908
|
|
|
|
|
|
|
} |
909
|
|
|
|
|
|
|
else { |
910
|
|
|
|
|
|
|
return $self->err( 'ERR_RESP_FAIL', $resp->message(), $url ); |
911
|
|
|
|
|
|
|
} |
912
|
|
|
|
|
|
|
} |
913
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
###################################################################### |
915
|
|
|
|
|
|
|
sub put { |
916
|
|
|
|
|
|
|
my ( $self, @p ) = @_; |
917
|
|
|
|
|
|
|
my ( $local, $url, $callback, $custom_headers ) |
918
|
|
|
|
|
|
|
= HTTP::DAV::Utils::rearrange( [ 'LOCAL', 'URL', 'CALLBACK', 'HEADERS' ], @p ); |
919
|
|
|
|
|
|
|
|
920
|
|
|
|
|
|
|
if ( ref($local) eq "SCALAR" ) { |
921
|
|
|
|
|
|
|
$self->_start_multi_op( 'put ' . ${$local}, $callback ); |
922
|
|
|
|
|
|
|
$self->_put(@p); |
923
|
|
|
|
|
|
|
} |
924
|
|
|
|
|
|
|
else { |
925
|
|
|
|
|
|
|
$self->_start_multi_op( 'put ' . $local, $callback ); |
926
|
|
|
|
|
|
|
$local =~ s/\ /\\ /g; |
927
|
|
|
|
|
|
|
my @globs = glob("$local"); |
928
|
|
|
|
|
|
|
|
929
|
|
|
|
|
|
|
#my @globs=glob("\"$local\""); |
930
|
|
|
|
|
|
|
foreach my $file (@globs) { |
931
|
|
|
|
|
|
|
print "Starting put of $file\n" if $HTTP::DAV::DEBUG > 1; |
932
|
|
|
|
|
|
|
$self->_put( |
933
|
|
|
|
|
|
|
-local => $file, |
934
|
|
|
|
|
|
|
-url => $url, |
935
|
|
|
|
|
|
|
-callback => $callback, |
936
|
|
|
|
|
|
|
-headers => $custom_headers, |
937
|
|
|
|
|
|
|
); |
938
|
|
|
|
|
|
|
} |
939
|
|
|
|
|
|
|
} |
940
|
|
|
|
|
|
|
$self->_end_multi_op(); |
941
|
|
|
|
|
|
|
return $self->is_success; |
942
|
|
|
|
|
|
|
} |
943
|
|
|
|
|
|
|
|
944
|
|
|
|
|
|
|
sub _put { |
945
|
|
|
|
|
|
|
my ( $self, @p ) = @_; |
946
|
|
|
|
|
|
|
my ( $local, $url, $custom_headers ) |
947
|
|
|
|
|
|
|
= HTTP::DAV::Utils::rearrange( [ 'LOCAL', 'URL', 'HEADERS' ], @p ); |
948
|
|
|
|
|
|
|
|
949
|
|
|
|
|
|
|
return $self->err('ERR_WRONG_ARGS') |
950
|
|
|
|
|
|
|
if ( !defined $local || $local eq "" ); |
951
|
|
|
|
|
|
|
return $self->err('ERR_NULL_RESOURCE') |
952
|
|
|
|
|
|
|
unless $self->get_workingresource(); |
953
|
|
|
|
|
|
|
|
954
|
|
|
|
|
|
|
# Check if they passed a reference to content rather than a filename. |
955
|
|
|
|
|
|
|
my $content_ptr = ( ref($local) eq "SCALAR" ) ? 1 : 0; |
956
|
|
|
|
|
|
|
|
957
|
|
|
|
|
|
|
# Setup the resource based on the passed url |
958
|
|
|
|
|
|
|
# Check if the remote resource exists and is a collection. |
959
|
|
|
|
|
|
|
$url = $self->get_absolute_uri($url); |
960
|
|
|
|
|
|
|
my $resource = $self->new_resource($url); |
961
|
|
|
|
|
|
|
my $response = $resource->propfind( -depth => 0 ); |
962
|
|
|
|
|
|
|
my $leaf_name; |
963
|
|
|
|
|
|
|
if ( $response->is_success && $resource->is_collection && !$content_ptr ) |
964
|
|
|
|
|
|
|
{ |
965
|
|
|
|
|
|
|
|
966
|
|
|
|
|
|
|
# Add one / to the end of the collection |
967
|
|
|
|
|
|
|
$url =~ s/\/*$//g; #Strip em |
968
|
|
|
|
|
|
|
$url .= "/"; #Add one |
969
|
|
|
|
|
|
|
$leaf_name = HTTP::DAV::Utils::get_leafname($local); |
970
|
|
|
|
|
|
|
} |
971
|
|
|
|
|
|
|
else { |
972
|
|
|
|
|
|
|
$leaf_name = HTTP::DAV::Utils::get_leafname($url); |
973
|
|
|
|
|
|
|
} |
974
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
my $target = $self->get_absolute_uri( $leaf_name, $url ); |
976
|
|
|
|
|
|
|
|
977
|
|
|
|
|
|
|
#print "$local => $target ($url, $leaf_name)\n"; |
978
|
|
|
|
|
|
|
|
979
|
|
|
|
|
|
|
# PUT A DIRECTORY |
980
|
|
|
|
|
|
|
if ( !$content_ptr && -d $local ) { |
981
|
|
|
|
|
|
|
|
982
|
|
|
|
|
|
|
# mkcol |
983
|
|
|
|
|
|
|
# Return 0 if fail because the error will have already |
984
|
|
|
|
|
|
|
# been set by the mkcol routine |
985
|
|
|
|
|
|
|
if ( $self->mkcol($target, -headers => $custom_headers) ) { |
986
|
|
|
|
|
|
|
if ( !opendir( DIR, $local ) ) { |
987
|
|
|
|
|
|
|
$self->err( 'ERR_GENERIC', "chdir to \"$local\" failed: $!" ); |
988
|
|
|
|
|
|
|
} |
989
|
|
|
|
|
|
|
else { |
990
|
|
|
|
|
|
|
my @files = readdir(DIR); |
991
|
|
|
|
|
|
|
close DIR; |
992
|
|
|
|
|
|
|
foreach my $file (@files) { |
993
|
|
|
|
|
|
|
next if $file eq "."; |
994
|
|
|
|
|
|
|
next if $file eq ".."; |
995
|
|
|
|
|
|
|
my $progeny = "$local/$file"; |
996
|
|
|
|
|
|
|
$progeny =~ s#//#/#g; # Fold down double slashes |
997
|
|
|
|
|
|
|
$self->_put( |
998
|
|
|
|
|
|
|
-local => $progeny, |
999
|
|
|
|
|
|
|
-url => "$target/$file", |
1000
|
|
|
|
|
|
|
); |
1001
|
|
|
|
|
|
|
} |
1002
|
|
|
|
|
|
|
} |
1003
|
|
|
|
|
|
|
} |
1004
|
|
|
|
|
|
|
|
1005
|
|
|
|
|
|
|
# PUT A FILE |
1006
|
|
|
|
|
|
|
} |
1007
|
|
|
|
|
|
|
else { |
1008
|
|
|
|
|
|
|
my $content = ""; |
1009
|
|
|
|
|
|
|
my $fail = 0; |
1010
|
|
|
|
|
|
|
if ($content_ptr) { |
1011
|
|
|
|
|
|
|
$content = $$local; |
1012
|
|
|
|
|
|
|
} |
1013
|
|
|
|
|
|
|
else { |
1014
|
|
|
|
|
|
|
if ( !CORE::open( F, $local ) ) { |
1015
|
|
|
|
|
|
|
$self->err( 'ERR_GENERIC', |
1016
|
|
|
|
|
|
|
"Couldn't open local file $local: $!" ); |
1017
|
|
|
|
|
|
|
$fail = 1; |
1018
|
|
|
|
|
|
|
} |
1019
|
|
|
|
|
|
|
else { |
1020
|
|
|
|
|
|
|
binmode F; |
1021
|
|
|
|
|
|
|
while (my $line = ) { $content .= $line; } |
1022
|
|
|
|
|
|
|
close F; |
1023
|
|
|
|
|
|
|
} |
1024
|
|
|
|
|
|
|
} |
1025
|
|
|
|
|
|
|
|
1026
|
|
|
|
|
|
|
if ( !$fail ) { |
1027
|
|
|
|
|
|
|
my $resource = $self->new_resource( -uri => $target ); |
1028
|
|
|
|
|
|
|
my $response = $resource->put($content,$custom_headers); |
1029
|
|
|
|
|
|
|
if ( $response->is_success ) { |
1030
|
|
|
|
|
|
|
$self->ok( "put $target (" . length($content) . " bytes)", |
1031
|
|
|
|
|
|
|
$target ); |
1032
|
|
|
|
|
|
|
} |
1033
|
|
|
|
|
|
|
else { |
1034
|
|
|
|
|
|
|
$self->err( 'ERR_RESP_FAIL', |
1035
|
|
|
|
|
|
|
"put failed " . $response->message(), $target ); |
1036
|
|
|
|
|
|
|
} |
1037
|
|
|
|
|
|
|
} |
1038
|
|
|
|
|
|
|
} |
1039
|
|
|
|
|
|
|
} |
1040
|
|
|
|
|
|
|
|
1041
|
|
|
|
|
|
|
###################################################################### |
1042
|
|
|
|
|
|
|
# UTILITY FUNCTION |
1043
|
|
|
|
|
|
|
# get_absolute_uri: |
1044
|
|
|
|
|
|
|
# Synopsis: $new_url = get_absolute_uri("/foo/bar") |
1045
|
|
|
|
|
|
|
# Takes a URI (or string) |
1046
|
|
|
|
|
|
|
# and returns the absolute URI based |
1047
|
|
|
|
|
|
|
# on the remote current working directory |
1048
|
|
|
|
|
|
|
sub get_absolute_uri { |
1049
|
|
|
|
|
|
|
my ( $self, @p ) = @_; |
1050
|
|
|
|
|
|
|
my ( $rel_uri, $base_uri ) |
1051
|
|
|
|
|
|
|
= HTTP::DAV::Utils::rearrange( [ 'REL_URI', 'BASE_URI' ], @p ); |
1052
|
|
|
|
|
|
|
|
1053
|
|
|
|
|
|
|
local $URI::URL::ABS_REMOTE_LEADING_DOTS = 1; |
1054
|
|
|
|
|
|
|
if ( !defined $base_uri ) { |
1055
|
|
|
|
|
|
|
$base_uri = $self->get_workingresource()->get_uri(); |
1056
|
|
|
|
|
|
|
} |
1057
|
|
|
|
|
|
|
|
1058
|
|
|
|
|
|
|
if ($base_uri) { |
1059
|
|
|
|
|
|
|
my $new_url = URI->new_abs( $rel_uri, $base_uri ); |
1060
|
|
|
|
|
|
|
return $new_url; |
1061
|
|
|
|
|
|
|
} |
1062
|
|
|
|
|
|
|
else { |
1063
|
|
|
|
|
|
|
$rel_uri; |
1064
|
|
|
|
|
|
|
} |
1065
|
|
|
|
|
|
|
} |
1066
|
|
|
|
|
|
|
|
1067
|
|
|
|
|
|
|
## Takes a $dav->get_globs(URI) |
1068
|
|
|
|
|
|
|
# Where URI may contain wildcards at the leaf level: |
1069
|
|
|
|
|
|
|
# URI: |
1070
|
|
|
|
|
|
|
# http://www.host.org/perldav/test*.html |
1071
|
|
|
|
|
|
|
# /perldav/test?.html |
1072
|
|
|
|
|
|
|
# test[12].html |
1073
|
|
|
|
|
|
|
# |
1074
|
|
|
|
|
|
|
# Performs a propfind to determine the url's that match |
1075
|
|
|
|
|
|
|
# |
1076
|
|
|
|
|
|
|
sub get_globs { |
1077
|
|
|
|
|
|
|
my ( $self, $url ) = @_; |
1078
|
|
|
|
|
|
|
my @urls = (); |
1079
|
|
|
|
|
|
|
my ( $left, $leafname ) = HTTP::DAV::Utils::split_leaf($url); |
1080
|
|
|
|
|
|
|
|
1081
|
|
|
|
|
|
|
# We need to unescape it because it may have been encoded. |
1082
|
|
|
|
|
|
|
$leafname = URI::Escape::uri_unescape($leafname); |
1083
|
|
|
|
|
|
|
|
1084
|
|
|
|
|
|
|
if ( $leafname =~ /[\*\?\[]/ ) { |
1085
|
|
|
|
|
|
|
my $resource = $self->new_resource( -uri => $left ); |
1086
|
|
|
|
|
|
|
my $resp = $resource->propfind( -depth => 1 ); |
1087
|
|
|
|
|
|
|
if ( $resp->is_error ) { |
1088
|
|
|
|
|
|
|
$self->err( 'ERR_RESP_FAIL', $resp->message(), $left ); |
1089
|
|
|
|
|
|
|
return (); |
1090
|
|
|
|
|
|
|
} |
1091
|
|
|
|
|
|
|
|
1092
|
|
|
|
|
|
|
$leafname = HTTP::DAV::Utils::glob2regex($leafname); |
1093
|
|
|
|
|
|
|
my $rl = $resource->get_resourcelist(); |
1094
|
|
|
|
|
|
|
if ($rl) { |
1095
|
|
|
|
|
|
|
my $match = 0; |
1096
|
|
|
|
|
|
|
|
1097
|
|
|
|
|
|
|
# We eval this because a bogus leafname could bomb the regex. |
1098
|
|
|
|
|
|
|
eval { |
1099
|
|
|
|
|
|
|
foreach my $progeny ( $rl->get_resources() ) |
1100
|
|
|
|
|
|
|
{ |
1101
|
|
|
|
|
|
|
my $progeny_url = $progeny->get_uri; |
1102
|
|
|
|
|
|
|
my $progeny_leaf |
1103
|
|
|
|
|
|
|
= HTTP::DAV::Utils::get_leafname($progeny_url); |
1104
|
|
|
|
|
|
|
if ( $progeny_leaf =~ /^$leafname$/ ) { |
1105
|
|
|
|
|
|
|
print "Matched $progeny_url\n" |
1106
|
|
|
|
|
|
|
if $HTTP::DAV::DEBUG > 1; |
1107
|
|
|
|
|
|
|
$match++; |
1108
|
|
|
|
|
|
|
push( @urls, $progeny_url ); |
1109
|
|
|
|
|
|
|
} |
1110
|
|
|
|
|
|
|
else { |
1111
|
|
|
|
|
|
|
print "Skipped $progeny_url\n" |
1112
|
|
|
|
|
|
|
if $HTTP::DAV::DEBUG > 1; |
1113
|
|
|
|
|
|
|
} |
1114
|
|
|
|
|
|
|
} |
1115
|
|
|
|
|
|
|
}; |
1116
|
|
|
|
|
|
|
$self->err( 'ERR_GENERIC', "No match found" ) unless ($match); |
1117
|
|
|
|
|
|
|
} |
1118
|
|
|
|
|
|
|
} |
1119
|
|
|
|
|
|
|
else { |
1120
|
|
|
|
|
|
|
push( @urls, $url ); |
1121
|
|
|
|
|
|
|
} |
1122
|
|
|
|
|
|
|
|
1123
|
|
|
|
|
|
|
return @urls; |
1124
|
|
|
|
|
|
|
} |
1125
|
|
|
|
|
|
|
|
1126
|
|
|
|
|
|
|
sub what_happened { |
1127
|
|
|
|
|
|
|
my ($self, $url, $resource, $response) = @_; |
1128
|
|
|
|
|
|
|
|
1129
|
|
|
|
|
|
|
if (! $response->is_error()) { |
1130
|
|
|
|
|
|
|
return { success => 1 } |
1131
|
|
|
|
|
|
|
} |
1132
|
|
|
|
|
|
|
|
1133
|
|
|
|
|
|
|
my $error_type; |
1134
|
|
|
|
|
|
|
my $error_msg; |
1135
|
|
|
|
|
|
|
|
1136
|
|
|
|
|
|
|
# Method not allowed |
1137
|
|
|
|
|
|
|
if ($response->status_line =~ m{405}) { |
1138
|
|
|
|
|
|
|
$error_type = 'ERR_405'; |
1139
|
|
|
|
|
|
|
$error_msg = $response->status_line; |
1140
|
|
|
|
|
|
|
} |
1141
|
|
|
|
|
|
|
# 501 most probably means your LWP doesn't support SSL |
1142
|
|
|
|
|
|
|
elsif ($response->status_line =~ m{501}) { |
1143
|
|
|
|
|
|
|
$error_type = 'ERR_501'; |
1144
|
|
|
|
|
|
|
$error_msg = $response->status_line; |
1145
|
|
|
|
|
|
|
} |
1146
|
|
|
|
|
|
|
elsif ($response->www_authenticate) { |
1147
|
|
|
|
|
|
|
$error_type = 'ERR_UNAUTHORIZED'; |
1148
|
|
|
|
|
|
|
$error_msg = $response->www_authenticate; |
1149
|
|
|
|
|
|
|
} |
1150
|
|
|
|
|
|
|
elsif ( !$resource->is_dav_compliant ) { |
1151
|
|
|
|
|
|
|
$error_type = 'ERR_GENERIC'; |
1152
|
|
|
|
|
|
|
$error_msg = qq{The URL "$url" is not DAV enabled or not accessible.}; |
1153
|
|
|
|
|
|
|
} |
1154
|
|
|
|
|
|
|
else { |
1155
|
|
|
|
|
|
|
$error_type = 'ERR_RESP_FAIL'; |
1156
|
|
|
|
|
|
|
my $message = $response->message(); |
1157
|
|
|
|
|
|
|
$error_msg = qq{Could not access $url: $message}; |
1158
|
|
|
|
|
|
|
} |
1159
|
|
|
|
|
|
|
|
1160
|
|
|
|
|
|
|
return { |
1161
|
|
|
|
|
|
|
success => 0, |
1162
|
|
|
|
|
|
|
error_type => $error_type, |
1163
|
|
|
|
|
|
|
error_msg => $error_msg, |
1164
|
|
|
|
|
|
|
} |
1165
|
|
|
|
|
|
|
|
1166
|
|
|
|
|
|
|
} |
1167
|
|
|
|
|
|
|
|
1168
|
|
|
|
|
|
|
1; |
1169
|
|
|
|
|
|
|
|
1170
|
|
|
|
|
|
|
__END__ |