line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#!/Applications/Alloy/Library/bin/perl |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
20495
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
37
|
|
4
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
69
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
package HTTP::DAVServer; |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
our $VERSION=0.1; |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
=head1 NAME |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
HTTP::DAVServer - allows you to write server-side functions to accept, process and respond to WebDAV client requests. WebDAV - RFC 2518 - is a protocol which allows clients to manipulate files on a remote server using HTTP. |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
=head1 SYNOPSIS |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
In your favorite NPH CGI script ( for now ) |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
use HTTP::DAVServer; |
19
|
|
|
|
|
|
|
HTTP::DAVServer->handle; |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
You will need to add directives to Apache to request that certain methods be |
22
|
|
|
|
|
|
|
handled by the CGI script: |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
Script PROPFIND /cgi-bin/nph-webdav |
25
|
|
|
|
|
|
|
Script PUT /cgi-bin/nph-webdav |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
See INSTALL for more details. See INSTALL for important warning! |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
=head1 MODULE STATUS |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
This module is a prototype. Please see INSTALL for important warnings. You should try this module |
32
|
|
|
|
|
|
|
if you're interested in developing a customized WebDAV server and you want to use Perl to do |
33
|
|
|
|
|
|
|
most or all of fancy footwork behind the scenes. |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
My short term goal is to provide a reference implementation of a WebDAV server which can be subclassed |
36
|
|
|
|
|
|
|
for specific implementation features. Information to resolve any of the following bugs is most welcome! I will |
37
|
|
|
|
|
|
|
be fixing all the failed items in copymove next. |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
Litmus test results: |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
http and basic tests are good, some errors on copymove and propfind. proppatch not done so skips lots of tests. |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
-> running `http': |
44
|
|
|
|
|
|
|
0. init.................. pass |
45
|
|
|
|
|
|
|
1. begin................. pass |
46
|
|
|
|
|
|
|
2. expect100............. pass |
47
|
|
|
|
|
|
|
3. finish................ pass |
48
|
|
|
|
|
|
|
<- summary for `http': of 4 tests run: 4 passed, 0 failed. 100.0% |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
-> running `basic': |
51
|
|
|
|
|
|
|
0. init.................. pass |
52
|
|
|
|
|
|
|
1. begin................. pass |
53
|
|
|
|
|
|
|
2. options............... WARNING: server does not claim Class 2 compliance |
54
|
|
|
|
|
|
|
...................... pass (with 1 warning) |
55
|
|
|
|
|
|
|
3. put_get............... pass |
56
|
|
|
|
|
|
|
4. put_get_utf8_segment.. pass |
57
|
|
|
|
|
|
|
5. mkcol_over_plain...... pass |
58
|
|
|
|
|
|
|
6. delete................ pass |
59
|
|
|
|
|
|
|
7. delete_null........... pass |
60
|
|
|
|
|
|
|
8. mkcol................. pass |
61
|
|
|
|
|
|
|
9. mkcol_again........... pass |
62
|
|
|
|
|
|
|
10. delete_coll........... pass |
63
|
|
|
|
|
|
|
11. mkcol_no_parent....... pass |
64
|
|
|
|
|
|
|
12. mkcol_with_body....... pass |
65
|
|
|
|
|
|
|
13. finish................ pass |
66
|
|
|
|
|
|
|
<- summary for `basic': of 14 tests run: 14 passed, 0 failed. 100.0% |
67
|
|
|
|
|
|
|
-> 1 warning was issued. |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
-> running `copymove': |
70
|
|
|
|
|
|
|
0. init.................. pass |
71
|
|
|
|
|
|
|
1. begin................. pass |
72
|
|
|
|
|
|
|
2. copy_init............. pass |
73
|
|
|
|
|
|
|
3. copy_simple........... FAIL |
74
|
|
|
|
|
|
|
4. copy_overwrite........ WARNING: COPY-on-existing fails with 412 |
75
|
|
|
|
|
|
|
...................... FAIL |
76
|
|
|
|
|
|
|
5. copy_cleanup.......... pass |
77
|
|
|
|
|
|
|
6. copy_coll............. FAIL |
78
|
|
|
|
|
|
|
7. move.................. FAIL |
79
|
|
|
|
|
|
|
8. move_coll............. FAIL |
80
|
|
|
|
|
|
|
9. move_cleanup.......... pass |
81
|
|
|
|
|
|
|
10. finish................ pass |
82
|
|
|
|
|
|
|
<- summary for `copymove': of 11 tests run: 6 passed, 5 failed. 54.5% |
83
|
|
|
|
|
|
|
-> 1 warning was issued. |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
-> running `props': |
86
|
|
|
|
|
|
|
0. init.................. pass |
87
|
|
|
|
|
|
|
1. begin................. pass |
88
|
|
|
|
|
|
|
2. propfind_invalid...... pass |
89
|
|
|
|
|
|
|
3. propfind_invalid2..... pass |
90
|
|
|
|
|
|
|
4. propfind_d0........... FAIL (No responses returned) |
91
|
|
|
|
|
|
|
5. propinit.............. pass |
92
|
|
|
|
|
|
|
6. propset............... FAIL (PROPPATCH on `/litmus/litmus/prop': 400 Bad Request) |
93
|
|
|
|
|
|
|
7. propget............... SKIPPED |
94
|
|
|
|
|
|
|
8. propmove.............. SKIPPED |
95
|
|
|
|
|
|
|
9. propget............... SKIPPED |
96
|
|
|
|
|
|
|
10. propdeletes........... SKIPPED |
97
|
|
|
|
|
|
|
11. propget............... SKIPPED |
98
|
|
|
|
|
|
|
12. propreplace........... SKIPPED |
99
|
|
|
|
|
|
|
13. propget............... SKIPPED |
100
|
|
|
|
|
|
|
14. propnullns............ SKIPPED |
101
|
|
|
|
|
|
|
15. propget............... SKIPPED |
102
|
|
|
|
|
|
|
16. prophighunicode....... SKIPPED |
103
|
|
|
|
|
|
|
17. propget............... SKIPPED |
104
|
|
|
|
|
|
|
18. propvalnspace......... SKIPPED |
105
|
|
|
|
|
|
|
19. propwformed........... pass |
106
|
|
|
|
|
|
|
20. propinit.............. pass |
107
|
|
|
|
|
|
|
21. propmanyns............ FAIL (PROPPATCH on `/litmus/litmus/prop': 400 Bad Request) |
108
|
|
|
|
|
|
|
22. propget............... FAIL (PROPFIND on `/litmus/litmus/prop': 400 Bad Request) |
109
|
|
|
|
|
|
|
23. propcleanup........... pass |
110
|
|
|
|
|
|
|
24. finish................ pass |
111
|
|
|
|
|
|
|
-> 12 tests were skipped. |
112
|
|
|
|
|
|
|
<- summary for `props': of 13 tests run: 9 passed, 4 failed. 69.2% |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
=head1 DEPENDENCIES |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
This code requires: |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
XML::Simple |
119
|
|
|
|
|
|
|
XML::SAX (for namespace support in XML::Simple) |
120
|
|
|
|
|
|
|
DateTime (THE new Date and Time support in Perl) |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
=cut |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
|
125
|
1
|
|
|
1
|
|
1973
|
use CGI qw(); |
|
1
|
|
|
|
|
16660
|
|
|
1
|
|
|
|
|
24
|
|
126
|
|
|
|
|
|
|
|
127
|
1
|
|
|
1
|
|
366
|
use XML::Simple qw(); |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
use DateTime qw(); |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
sub dateEpoch { DateTime->from_epoch( epoch =>$_[0] )->iso8601 } |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
our $WARN =1; |
133
|
|
|
|
|
|
|
our $TRACE =1; |
134
|
|
|
|
|
|
|
our $PUBLIC=1; |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
use HTTP::DAVServer::AuthDigest qw(); |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
our ($ROOT, $HOST) = ("", ""); |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
sub handle { |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
my $self=shift; |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
if ($TRACE) { |
145
|
|
|
|
|
|
|
eval "use Data::Dumper;"; |
146
|
|
|
|
|
|
|
no warnings; |
147
|
|
|
|
|
|
|
$Data::Dumper::Indent=1; |
148
|
|
|
|
|
|
|
$Data::Dumper::Sortkeys=1; |
149
|
|
|
|
|
|
|
} |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
$ROOT=$ENV{'DOCUMENT_ROOT'}; |
152
|
|
|
|
|
|
|
$ROOT =~ s#/+$##; |
153
|
|
|
|
|
|
|
$HOST =$ENV{'HTTP_HOST'}; |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
my $r=new CGI; |
156
|
|
|
|
|
|
|
my $method =$r->request_method; |
157
|
|
|
|
|
|
|
my $contLen=$ENV{'CONTENT_LENGTH'} || 0; |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
my $responder="${self}::Respond"; |
160
|
|
|
|
|
|
|
eval "use $responder"; |
161
|
|
|
|
|
|
|
die "LOADRESPOND error $@\n" if $@; |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
$responder->badRequest($r, "NOHANDLE", $method) unless $responder->handles( $method ); |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
$responder->badRequest($r, "MISSCONT") if $responder->hasContent( $method ) == 1 && $contLen == 0; |
166
|
|
|
|
|
|
|
if ($responder->hasContent( $method ) == 0 && $contLen != 0) { |
167
|
|
|
|
|
|
|
$method eq "MKCOL" && $responder->unsupported($r); |
168
|
|
|
|
|
|
|
$responder->badRequest($r, "HASCONT" ); |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
$responder->challenge($r) unless $PUBLIC |
172
|
|
|
|
|
|
|
|| $ENV{'REMOTE_USER'} |
173
|
|
|
|
|
|
|
|| HTTP::DAVServer::AuthDigest::authenticate( sub { return $_[0] } ); |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
my $request={}; |
176
|
|
|
|
|
|
|
if ($contLen && $method ne "PUT") { |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
$responder->badRequest($r) unless $r->content_type eq "text/xml"; |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
$request = eval { |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
if ($TRACE) { |
183
|
|
|
|
|
|
|
local undef $/; |
184
|
|
|
|
|
|
|
my $xmlin=<>; |
185
|
|
|
|
|
|
|
warn "REQUEST XML:\n$xmlin\n"; |
186
|
|
|
|
|
|
|
XML::Simple::XMLin( $xmlin, nsexpand => 1 ); |
187
|
|
|
|
|
|
|
} else { |
188
|
|
|
|
|
|
|
XML::Simple::XMLin( "-", nsexpand => 1 ); |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
}; |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
$responder->badRequest($r, "BADXML", $@) if $@; |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
warn ("ENV: ", Dumper (\%ENV), "METHOD: $method\nSUBMITTED XML: ", Dumper ($request)) if $TRACE; |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
my $url=CGI::Util::unescape($ENV{'REQUEST_URI'}); |
201
|
|
|
|
|
|
|
$url=~s#/+$##; |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
eval "use ${self}::$method"; |
204
|
|
|
|
|
|
|
$responder->serverError( $r, "LOAD$method", $@ ) if $@; |
205
|
|
|
|
|
|
|
"${self}::$method"->handle( $r, $url, $responder, $request ); |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
} |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
=head1 SUPPORT |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
For technical support please email to jlawrenc@cpan.org ... |
212
|
|
|
|
|
|
|
for faster service please include "HTTP::DAVServer" and "help" in your subject line. |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
=head1 AUTHOR |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
Jay J. Lawrence - jlawrenc@cpan.org |
217
|
|
|
|
|
|
|
Infonium Inc., Canada |
218
|
|
|
|
|
|
|
http://www.infonium.ca/ |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
=head1 COPYRIGHT |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
Copyright (c) 2003 Jay J. Lawrence, Infonium Inc. All rights reserved. |
223
|
|
|
|
|
|
|
This program is free software; you can redistribute |
224
|
|
|
|
|
|
|
it and/or modify it under the same terms as Perl itself. |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
The full text of the license can be found in the |
227
|
|
|
|
|
|
|
LICENSE file included with this module. |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
Thank you to the authors of my prequisite modules. With out your help this code |
232
|
|
|
|
|
|
|
would be much more difficult to write! |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
XML::Simple - Grant McLean |
235
|
|
|
|
|
|
|
XML::SAX - Matt Sergeant |
236
|
|
|
|
|
|
|
DateTime - Dave Rolsky |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
Also the authors of litmus, a very helpful tool indeed! |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
=head1 SEE ALSO |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
HTTP::DAV, HTTP::Webdav, http://www.webdav.org/, RFC 2518 |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
=cut |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
1; |