line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package HTTP::DAV::Response; |
2
|
|
|
|
|
|
|
|
3
|
4
|
|
|
4
|
|
16
|
use strict; |
|
4
|
|
|
|
|
6
|
|
|
4
|
|
|
|
|
109
|
|
4
|
4
|
|
|
4
|
|
14
|
use vars qw(@ISA $VERSION); |
|
4
|
|
|
|
|
6
|
|
|
4
|
|
|
|
|
3057
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
$VERSION = '0.14'; |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
require HTTP::Response; |
9
|
|
|
|
|
|
|
@ISA = qw(HTTP::Response); |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
my %dav_status_codes = ( |
12
|
|
|
|
|
|
|
102 => "Processing. Server has accepted the request, but has not yet completed it", |
13
|
|
|
|
|
|
|
204 => "No Content", |
14
|
|
|
|
|
|
|
207 => "Multistatus", |
15
|
|
|
|
|
|
|
422 => "Unprocessable Entity. Bad client XML sent?", |
16
|
|
|
|
|
|
|
423 => "Locked. The source or destination resource is locked", |
17
|
|
|
|
|
|
|
424 => "Failed Dependency", |
18
|
|
|
|
|
|
|
507 => "Insufficient Storage. The server is unable to store the request", |
19
|
|
|
|
|
|
|
); |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
# PROTECTED METHODS |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
sub clone_http_resp { |
24
|
0
|
|
|
0
|
0
|
|
my ($class,$http_resp) = @_; |
25
|
0
|
|
|
|
|
|
my %clone = %{$http_resp}; |
|
0
|
|
|
|
|
|
|
26
|
0
|
|
|
|
|
|
my $self = \%clone; |
27
|
0
|
|
0
|
|
|
|
bless $self, (ref($class) || $class); |
28
|
|
|
|
|
|
|
} |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
# This routine resets the base |
31
|
|
|
|
|
|
|
# message in the |
32
|
|
|
|
|
|
|
# object based on the |
33
|
|
|
|
|
|
|
# code and the status_codes above. |
34
|
|
|
|
|
|
|
# set_message('207'); |
35
|
|
|
|
|
|
|
sub set_message { |
36
|
0
|
|
|
0
|
0
|
|
my ($self,$code) = @_; |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# Set the status code |
39
|
0
|
0
|
|
|
|
|
if ( defined $dav_status_codes{$code} ) { |
40
|
0
|
|
|
|
|
|
$self->message( $dav_status_codes{$code} ); |
41
|
|
|
|
|
|
|
} |
42
|
|
|
|
|
|
|
} |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
sub set_responsedescription { |
45
|
0
|
0
|
|
0
|
0
|
|
$_[0]->{'_dav_responsedescription'} = $_[1] if $_[1]; |
46
|
|
|
|
|
|
|
} |
47
|
|
|
|
|
|
|
|
48
|
0
|
|
|
0
|
0
|
|
sub get_responsedescription { $_[0]->{'_dav_responsedescription'}; } |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
sub add_status_line { |
51
|
0
|
|
|
0
|
0
|
|
my($self,$message,$responsedescription,$handle,$url) = @_; |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
# Parse "status-line". See section 6.1 of RFC 2068 |
54
|
|
|
|
|
|
|
# Status-Line= HTTP-Version SP Status-Code SP Reason-Phrase CRLF |
55
|
0
|
0
|
0
|
|
|
|
if (defined $message && $message =~ /^(.*?)\s(.*?)\s(.*?)$/ ) { |
56
|
0
|
|
|
|
|
|
my ($http_version,$status_code,$reason_phrase) = ($1,$2,$3); |
57
|
|
|
|
|
|
|
|
58
|
0
|
|
|
|
|
|
push ( @{$self->{_dav_multistatus}}, |
|
0
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
{ |
60
|
|
|
|
|
|
|
'handle' => $handle, |
61
|
|
|
|
|
|
|
'url' => $url, |
62
|
|
|
|
|
|
|
'HTTP Version' => $http_version, |
63
|
|
|
|
|
|
|
'code' => $status_code, |
64
|
|
|
|
|
|
|
'message' => $reason_phrase, |
65
|
|
|
|
|
|
|
'description' => $responsedescription, |
66
|
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
); |
68
|
0
|
|
|
|
|
|
return 1; |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
} else { |
71
|
0
|
|
|
|
|
|
return 0; |
72
|
|
|
|
|
|
|
} |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
# PUBLIC METHODS |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
sub is_multistatus { |
78
|
0
|
0
|
|
0
|
1
|
|
return ($_[0]->code eq "207" )? 1:0; |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
sub messages { |
82
|
0
|
|
|
0
|
1
|
|
my ($self) = @_; |
83
|
|
|
|
|
|
|
|
84
|
0
|
|
|
|
|
|
my @messages = (); |
85
|
0
|
0
|
|
|
|
|
if ($self->is_multistatus() ) { |
86
|
0
|
|
|
|
|
|
foreach my $num ( 0 .. $self->response_count()) { |
87
|
0
|
|
|
|
|
|
push(@messages, $self->message_bynum($num)); |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
} else { |
90
|
0
|
|
|
|
|
|
push(@messages,$self->message()); |
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
|
93
|
0
|
0
|
|
|
|
|
return wantarray ? @messages : join("\n",@messages); |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
sub codes { |
97
|
0
|
|
|
0
|
0
|
|
my ($self) = @_; |
98
|
|
|
|
|
|
|
|
99
|
0
|
|
|
|
|
|
my @codes = (); |
100
|
0
|
0
|
|
|
|
|
if ($self->is_multistatus() ) { |
101
|
0
|
|
|
|
|
|
foreach my $num ( 0 .. $self->response_count()) { |
102
|
0
|
|
|
|
|
|
push(@codes, $self->code_bynum($num)); |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
} else { |
105
|
0
|
|
|
|
|
|
push(@codes,$self->code()); |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
|
108
|
0
|
|
|
|
|
|
return \@codes; |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
sub response_count { |
112
|
0
|
0
|
|
0
|
1
|
|
return -1 unless exists $_[0]->{_dav_multistatus}; |
113
|
0
|
0
|
|
|
|
|
return -1 unless ref($_[0]->{_dav_multistatus}) =~ /ARRAY/; |
114
|
0
|
|
|
|
|
|
return $#{$_[0]->{_dav_multistatus}}; |
|
0
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
|
117
|
0
|
|
|
0
|
1
|
|
sub message_bynum { $_[0]->{_dav_multistatus}[$_[1]]{'message'}; } |
118
|
0
|
|
|
0
|
1
|
|
sub code_bynum { $_[0]->{_dav_multistatus}[$_[1]]{'code'}; } |
119
|
0
|
|
|
0
|
1
|
|
sub url_bynum { $_[0]->{_dav_multistatus}[$_[1]]{'url'}; } |
120
|
0
|
|
|
0
|
1
|
|
sub description_bynum { $_[0]->{_dav_multistatus}[$_[1]]{'description'}; } |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
sub response_bynum { |
123
|
0
|
|
|
0
|
1
|
|
my ($self,$number) = @_; |
124
|
|
|
|
|
|
|
|
125
|
0
|
0
|
0
|
|
|
|
if (defined $number && $number>=0 ) { |
126
|
|
|
|
|
|
|
return ( |
127
|
0
|
|
|
|
|
|
$self->code_bynum($number), |
128
|
|
|
|
|
|
|
$self->message_bynum($number), |
129
|
|
|
|
|
|
|
$self->url_bynum($number), |
130
|
|
|
|
|
|
|
$self->description_bynum($number), |
131
|
|
|
|
|
|
|
); |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
sub is_success { |
136
|
0
|
|
|
0
|
1
|
|
my ($self) = @_; |
137
|
|
|
|
|
|
|
|
138
|
0
|
0
|
|
|
|
|
if ($self->is_multistatus() ) { |
139
|
0
|
|
|
|
|
|
foreach my $code ( @{ $self->codes() } ) { |
|
0
|
|
|
|
|
|
|
140
|
0
|
0
|
|
|
|
|
return 0 if ( HTTP::Status::is_error($code) ); |
141
|
|
|
|
|
|
|
} |
142
|
|
|
|
|
|
|
} else { |
143
|
0
|
|
0
|
|
|
|
return ($self->SUPER::is_success() || 0); |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
|
146
|
0
|
|
|
|
|
|
return 1; |
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
sub as_string { |
150
|
0
|
|
|
0
|
1
|
|
my ($self) = @_; |
151
|
0
|
|
|
|
|
|
my ($ms, $returnstr) = ""; |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
# use Data::Dumper; |
154
|
|
|
|
|
|
|
# print Data::Dumper->Dump( [\$self] , [ '$self' ] ); |
155
|
0
|
|
|
|
|
|
foreach my $num ( 0 .. $self->response_count() ) { |
156
|
0
|
|
|
|
|
|
my %h = %{$self->{_dav_multistatus}[$num]}; |
|
0
|
|
|
|
|
|
|
157
|
0
|
|
|
|
|
|
$ms .= "Error number $num ($h{handle}):\n"; |
158
|
0
|
0
|
|
|
|
|
$ms .= " Href: $h{url}\n" if defined $h{url}; |
159
|
0
|
0
|
|
|
|
|
$ms .= " Mesg(code): $h{message} ($h{code})\n" if defined $h{code}; |
160
|
0
|
0
|
|
|
|
|
$ms .= " Desc: $h{'description'}\n" if defined $h{'description'}; |
161
|
0
|
|
|
|
|
|
$ms .= "\n"; |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
0
|
|
0
|
|
|
|
my $rd = $self->get_responsedescription() || ""; |
165
|
|
|
|
|
|
|
|
166
|
0
|
0
|
|
|
|
|
$returnstr .= "Multistatus lines:\n$ms\n" if $ms; |
167
|
0
|
0
|
|
|
|
|
$returnstr .= "Overall responsedescription: \"$rd\"\n" if $rd; |
168
|
0
|
|
|
|
|
|
$returnstr .= $self->SUPER::as_string; |
169
|
0
|
|
|
|
|
|
$returnstr; |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
=head1 NAME |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
HTTP::DAV::Response - represents a WebDAV HTTP Response (ala HTTP::Response) |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
=head1 SYNOPSIS |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
require HTTP::DAV::Response; |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
=head1 DESCRIPTION |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
The HTTP::DAV::Response class encapsulates HTTP style responses. A response consists of a response line, some headers, and (potentially empty) content. |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
HTTP::DAV::Response is a subclass of C and therefore inherits its methods. (HTTP::Response in turn inherits it's methods from C). |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
Therefore, this class actually inherits a rich library of functions. You are more likely wanting to read the C class as opposed to this class. |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
Instances of this class are usually created by a C object after it has performed some request (such as get, lock, delete, etc). You use the object to analyse the success or otherwise of the request. |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
HTTP::DAV::Response was created to handle two extra functions that normal HTTP Responses don't require: |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
- WebDAV reponses have 6 extra error codes: 102, 207, 422, 423, 424 and 507. Older versions of the LWP's C class did not have these extra codes. These were added. |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
- WebDAV responses can actually contain more than one response (and often DO contain more than one) in the form of a "Multistatus". These multistatus responses come in the form of an XML document. HTTP::DAV::Response can accurately parse these XML responses and emulate the normal of the C. |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
HTTP::DAV::Response transparently implements these extra features without the user having to be aware, so you really should be reading the C documentation for most of the things you want to do (have I already said that?). |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
There are only a handful of custom functions that HTTP::DAV::Response returns and those are to handle multistatus requests, C and C. |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
The six extra status codes that DAV servers can be returned in an HTTP Response are: |
201
|
|
|
|
|
|
|
102 => "Processing. Server has accepted the request, but has not yet completed it", |
202
|
|
|
|
|
|
|
207 => "Multistatus", |
203
|
|
|
|
|
|
|
422 => "Unprocessable Entity. Bad client XML sent?", |
204
|
|
|
|
|
|
|
423 => "Locked. The source or destination resource is locked", |
205
|
|
|
|
|
|
|
424 => "Failed Dependency", |
206
|
|
|
|
|
|
|
507 => "Insufficient Storage. The server is unable to store the request", |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
See C for the rest. |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
=head1 HANDLING A MULTISTATUS |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
So, many DAV requests may return a multistatus ("207 multistatus") instead of, say, "200 OK" or "403 Forbidden". |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
The HTTP::DAV::Response object stores each "response" sent back in the multistatus. You access them by array number. |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
The following code snippet shows what you will normally want to do: |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
... |
219
|
|
|
|
|
|
|
$response = $resource->lock(); |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
if ( $response->is_multistatus() ) { |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
foreach $num ( 0 .. $response->response_count() ) { |
224
|
|
|
|
|
|
|
($err_code,$mesg,$url,$desc) = |
225
|
|
|
|
|
|
|
$response->response_bynum($num); |
226
|
|
|
|
|
|
|
print "$mesg ($err_code) for $url\n"; |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
Would produce something like this: |
231
|
|
|
|
|
|
|
Failed Dependency (424) for /test/directory |
232
|
|
|
|
|
|
|
Locked (423) for /test/directory/file3 |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
This says that we couldn't lock /test/directory |
235
|
|
|
|
|
|
|
because file3 which exists inside is already locked by somebody else. |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
=head1 METHODS |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
=over 4 |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
=item B |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
This function takes no arguments and returns a 1 or a 0. |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
For example: if ($response->is_multistatus() ) { } |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
If the HTTP reply had "207 Multistatus" in the header then that indicates that there are multiple status messages in the XML content that was returned. |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
In this event, you may be interested in knowing what the individual messages were. To do this you would then use C. |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
=item B |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
Takes no arguments and returns "the number of error responses -1" that we got. |
254
|
|
|
|
|
|
|
Why -1? Because usually you will want to use this like an array operator: |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
foreach $num ( 0 .. $response->response_count() ) { |
257
|
|
|
|
|
|
|
print $response->message_bynum(); |
258
|
|
|
|
|
|
|
} |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
=item B |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
Takes one argument, the "response number" that you're interested in. And returns an array of details: |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
($code,$message,$url,$description) = response_bynum(2); |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
where |
267
|
|
|
|
|
|
|
$code - is the HTTP error code (e.g. 403, 423, etc). |
268
|
|
|
|
|
|
|
$message - is the associated message for that error code. |
269
|
|
|
|
|
|
|
$url - is the url that this error applies to (recall that there can be multiple responses within one response and they all relate to one URL) |
270
|
|
|
|
|
|
|
$description - is server's attempt at an english description of what happened. |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
=item B |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
Takes one argument, the "response number" that you're interested in, and returns it's code. E.g: |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
$code = $response->code_bynum(1); |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
See C |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
=item B |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
Takes one argument, the "response number" that you're interested in, and returns it's message. E.g: |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
$code = $response->message_bynum(1); |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
See C |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
=item B |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
Takes one argument, the "response number" that you're interested in, and returns it's url. E.g: |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
$code = $response->message_bynum(1); |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
See C |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
=item B |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
Takes one argument, the "response number" that you're interested in, and returns it's description. E.g: |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
$code = $response->message_description(1); |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
See C |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
=item B |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
Takes no arguments and returns all of the messages returned in a multistatus response. If called in a scalar context then all of the messages will be returned joined together by newlines. If called in an array context the messages will be returned as an array. |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
$messages = $response->messages(); |
309
|
|
|
|
|
|
|
e.g. $messages eq "Forbidden\nLocked"; |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
@messages = $response->messages(); |
312
|
|
|
|
|
|
|
e.g. @messages eq ["Forbidden", "Locked"]; |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
This routine is a variant on the standard C C. |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
=cut |
317
|
|
|
|
|
|
|
|