| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
# Perl WebDAV client library |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
package HTTP::DAV; |
|
4
|
|
|
|
|
|
|
|
|
5
|
22
|
|
|
22
|
|
109698
|
use strict; |
|
|
22
|
|
|
|
|
52
|
|
|
|
22
|
|
|
|
|
1436
|
|
|
6
|
22
|
|
|
22
|
|
125
|
use vars qw($VERSION $VERSION_DATE $DEBUG); |
|
|
22
|
|
|
|
|
39
|
|
|
|
22
|
|
|
|
|
2378
|
|
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
# Globals |
|
9
|
|
|
|
|
|
|
$VERSION = '0.47'; |
|
10
|
|
|
|
|
|
|
$VERSION_DATE = '2012/03/24'; |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
# Set this up to 3 |
|
13
|
|
|
|
|
|
|
$DEBUG = 0; |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
#use Carp (cluck); |
|
16
|
22
|
|
|
22
|
|
120
|
use Cwd (); # Can't import all of it, cwd clashes with our namespace. |
|
|
22
|
|
|
|
|
45
|
|
|
|
22
|
|
|
|
|
1435
|
|
|
17
|
22
|
|
|
22
|
|
26656
|
use LWP; |
|
|
22
|
|
|
|
|
1546915
|
|
|
|
22
|
|
|
|
|
944
|
|
|
18
|
22
|
|
|
22
|
|
49150
|
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 () { $content .= $_; } |
|
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__ |