3
Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de)
5
This library is free software; you can redistribute it and/or
6
modify it under the terms of the GNU Library General Public
7
License as published by the Free Software Foundation; either
8
version 2 of the License, or (at your option) any later version.
10
This library is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
Library General Public License for more details.
15
You should have received a copy of the GNU Library General Public
16
License along with this library; if not, write to the Free
17
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
This module builds on AuthServer by implementing the standard DAV
22
Subclass this class and specify an IFACE_CLASS. See example.
28
from utils import VERSION, AUTHOR
44
from propfind import PROPFIND
45
from delete import DELETE
46
from davcopy import COPY
47
from davmove import MOVE
49
from string import atoi,split
50
from status import STATUS_CODES
53
class DAVRequestHandler(AuthServer.BufferedAuthRequestHandler):
54
"""Simple DAV request handler with
64
It uses the resource/collection classes for serving and
69
server_version = "DAV/" + __version__
72
def _log(self, message):
75
def send_body(self,DATA,code,msg,desc,ctype='application/octet-stream',headers={}):
76
""" send a body in one part """
78
self.send_response(code,message=msg)
79
self.send_header("Connection", "close")
80
self.send_header("Accept-Ranges", "bytes")
82
for a,v in headers.items():
86
self.send_header("Content-Length", str(len(DATA)))
87
self.send_header("Content-Type", ctype)
89
self.send_header("Content-Length", "0")
95
def send_body_chunks(self,DATA,code,msg,desc,ctype='text/xml; encoding="utf-8"'):
96
""" send a body in chunks """
98
self.responses[207]=(msg,desc)
99
self.send_response(code,message=msg)
100
self.send_header("Content-type", ctype)
101
self.send_header("Connection", "close")
102
self.send_header("Transfer-Encoding", "chunked")
104
self._append(hex(len(DATA))[2:]+"\r\n")
107
self._append("0\r\n")
112
def do_OPTIONS(self):
113
"""return the list of capabilities """
114
self.send_response(200)
115
self.send_header("Allow", "GET, HEAD, COPY, MOVE, POST, PUT, PROPFIND, PROPPATCH, OPTIONS, MKCOL, DELETE, TRACE")
116
self.send_header("Content-Type", "text/plain")
117
self.send_header("DAV", "1")
120
def do_PROPFIND(self):
125
if self.headers.has_key("Content-Length"):
126
l=self.headers['Content-Length']
127
body=self.rfile.read(atoi(l))
128
body = """<?xml version="1.0" encoding="utf-8"?>
129
<propfind xmlns="DAV:"><prop>
130
<getcontentlength xmlns="DAV:"/>
131
<getlastmodified xmlns="DAV:"/>
132
<getcreationdate xmlns="DAV:"/>
133
<checked-in xmlns="DAV:"/>
134
<executable xmlns="http://apache.org/dav/props/"/>
135
<displayname xmlns="DAV:"/>
136
<resourcetype xmlns="DAV:"/>
137
<checked-out xmlns="DAV:"/>
138
</prop></propfind>"""
139
self.write_infp(body)
142
if self.headers.has_key('Depth'):
143
d=self.headers['Depth']
147
uri=urlparse.urljoin(dc.baseuri,self.path)
148
uri=urllib.unquote(uri)
149
print 'PROPFIND', uri, dc, d
150
pf=PROPFIND(uri,dc,d)
154
pf.read_propfind(body)
157
DATA=pf.createResponse()
159
except DAV_Error, (ec,dd):
160
return self.send_status(ec)
163
self.send_body_chunks(DATA,"207","Multi-Status","Multiple responses")
166
"""Serve a GET request."""
168
uri=urlparse.urljoin(dc.baseuri,self.path)
169
uri=urllib.unquote(uri)
171
# get the last modified date
173
lm=dc.get_prop(uri,"DAV:","getlastmodified")
175
lm="Sun, 01 Dec 2014 00:00:00 GMT" # dummy!
176
headers={"Last-Modified":lm}
178
# get the content type
180
ct=dc.get_prop(uri,"DAV:","getcontenttype")
182
ct="application/octet-stream"
186
data=dc.get_data(uri)
187
except DAV_Error, (ec,dd):
192
self.send_body(data,"200","OK","OK",ct,headers)
195
""" Send a HEAD response """
197
uri=urlparse.urljoin(dc.baseuri,self.path)
198
uri=urllib.unquote(uri)
200
# get the last modified date
202
lm=dc.get_prop(uri,"DAV:","getlastmodified")
204
lm="Sun, 01 Dec 2014 00:00:00 GMT" # dummy!
206
headers={"Last-Modified":lm}
208
# get the content type
210
ct=dc.get_prop(uri,"DAV:","getcontenttype")
212
ct="application/octet-stream"
215
data=dc.get_data(uri)
216
headers["Content-Length"]=str(len(data))
218
self.send_body(None,"404","Not Found","")
221
self.send_body(None,"200","OK","OK",ct,headers)
224
self.send_error(404,"File not found")
227
""" create a new collection """
230
uri=urlparse.urljoin(dc.baseuri,self.path)
231
uri=urllib.unquote(uri)
234
self.send_status(200)
235
except DAV_Error, (ec,dd):
239
""" delete an resource """
241
uri=urlparse.urljoin(dc.baseuri,self.path)
242
uri=urllib.unquote(uri)
244
if dc.is_collection(uri):
250
self.send_status(207,body=res)
252
self.send_status(204)
259
if self.headers.has_key("Content-Length"):
260
l=self.headers['Content-Length']
261
body=self.rfile.read(atoi(l))
262
uri=urlparse.urljoin(dc.baseuri,self.path)
263
uri=urllib.unquote(uri)
266
if self.headers.has_key("Content-Type"):
267
ct=self.headers['Content-Type']
270
except DAV_Error, (ec,dd):
273
self.send_status(201)
276
""" copy one resource to another """
279
except DAV_Error, (ec,dd):
283
""" move one resource to another """
286
except DAV_Error, (ec,dd):
289
def copymove(self,CLASS):
290
""" common method for copying or moving objects """
294
source_uri=urlparse.urljoin(dc.baseuri,self.path)
295
source_uri=urllib.unquote(source_uri)
297
# get the destination URI
298
dest_uri=self.headers['Destination']
299
dest_uri=urllib.unquote(dest_uri)
304
if self.headers.has_key("Overwrite"):
305
if self.headers['Overwrite']=="F":
309
# instanciate ACTION class
310
cp=CLASS(dc,source_uri,dest_uri,overwrite)
314
if self.headers.has_key("Depth"):
315
d=self.headers['Depth']
317
if d!="0" and d!="infinity":
318
self.send_status(400)
322
res=cp.single_action()
323
self.send_status(res)
326
# now it only can be "infinity" but we nevertheless check for a collection
327
if dc.is_collection(source_uri):
330
except DAV_Error, (ec,dd):
335
res=cp.single_action()
336
except DAV_Error, (ec,dd):
341
self.send_body_chunks(res,207,STATUS_CODES[207],STATUS_CODES[207],
342
ctype='text/xml; charset="utf-8"')
344
self.send_status(result_code)
346
def get_userinfo(self,user,pw):
347
""" Dummy method which lets all users in """
351
def send_status(self,code=200,mediatype='text/xml; charset="utf-8"', \
354
if not msg: msg=STATUS_CODES[code]
355
self.send_body(body,code,STATUS_CODES[code],msg,mediatype)