5
Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de)
7
This library is free software; you can redistribute it and/or
8
modify it under the terms of the GNU Library General Public
9
License as published by the Free Software Foundation; either
10
version 2 of the License, or (at your option) any later version.
12
This library is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
Library General Public License for more details.
17
You should have received a copy of the GNU Library General Public
18
License along with this library; if not, write to the Free
19
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24
from xml.dom import ext
25
from xml.dom.Document import Document
31
from StringIO import StringIO
34
from constants import COLLECTION, OBJECT, DAV_PROPS, RT_ALLPROP, RT_PROPNAME, RT_PROP
38
""" parse a propfind xml element and extract props
40
It will set the following instance vars:
42
request_class : ALLPROP | PROPNAME | PROP
43
proplist : list of properties
44
nsmap : map of namespaces
46
The list of properties will contain tuples of the form
47
(element name, ns_prefix, ns_uri)
53
def __init__(self,uri,dataclass,depth):
54
self.request_type=None
58
self.__dataclass=dataclass
59
self.__depth=str(depth)
61
self.__has_body=None # did we parse a body?
63
def read_propfind(self,xml_doc):
64
self.request_type,self.proplist,self.namespaces=utils.parse_propfind(xml_doc)
66
def createResponse(self):
67
""" create the multistatus response
69
This will be delegated to the specific method
70
depending on which request (allprop, propname, prop)
73
If we get a PROPNAME then we simply return the list with empty
74
values which we get from the interface class
76
If we get an ALLPROP we first get the list of properties and then
77
we do the same as with a PROP method.
81
if self.request_type==RT_ALLPROP:
82
return self.create_allprop()
84
if self.request_type==RT_PROPNAME:
85
return self.create_propname()
87
if self.request_type==RT_PROP:
88
return self.create_prop()
90
# no body means ALLPROP!
91
return self.create_allprop()
93
def create_propname(self):
94
""" create a multistatus response for the prop names """
97
# create the document generator
99
ms=doc.createElement("D:multistatus")
100
ms.setAttribute("xmlns:D","DAV:")
103
if self.__depth=="0":
104
pnames=dc.get_propnames(self.__uri)
105
re=self.mk_propname_response(self.__uri,pnames)
108
elif self.__depth=="1":
109
pnames=dc.get_propnames(self.__uri)
110
re=self.mk_propname_response(self.__uri,pnames)
113
for newuri in dc.get_childs(self.__uri):
114
pnames=dc.get_propnames(newuri)
115
re=self.mk_propname_response(newuri,pnames)
117
# *** depth=="infinity"
120
ext.PrettyPrint(doc,stream=sfile)
125
def create_allprop(self):
126
""" return a list of all properties """
129
for ns,plist in self.__dataclass.get_propnames(self.__uri).items():
130
self.proplist[ns]=plist
131
self.namespaces.append(ns)
133
return self.create_prop()
135
def create_prop(self):
136
""" handle a <prop> request
140
1. set up the <multistatus>-Framework
142
2. read the property values for each URI
143
(which is dependant on the Depth header)
144
This is done by the get_propvalues() method.
146
3. For each URI call the append_result() method
147
to append the actual <result>-Tag to the result
150
We differ between "good" properties, which have been
151
assigned a value by the interface class and "bad"
152
properties, which resulted in an error, either 404
153
(Not Found) or 403 (Forbidden).
158
# create the document generator
160
ms=doc.createElement("D:multistatus")
161
ms.setAttribute("xmlns:D","DAV:")
164
if self.__depth=="0":
165
gp,bp=self.get_propvalues(self.__uri)
166
res=self.mk_prop_response(self.__uri,gp,bp,doc)
169
elif self.__depth=="1":
170
gp,bp=self.get_propvalues(self.__uri)
171
res=self.mk_prop_response(self.__uri,gp,bp,doc)
175
for newuri in self.__dataclass.get_childs(self.__uri):
176
gp,bp=self.get_propvalues(newuri)
177
res=self.mk_prop_response(newuri,gp,bp,doc)
181
ext.PrettyPrint(doc,stream=sfile)
187
def mk_propname_response(self,uri,propnames,doc):
188
""" make a new <prop> result element for a PROPNAME request
190
This will simply format the propnames list.
191
propnames should have the format {NS1 : [prop1, prop2, ...], NS2: ...}
194
re=doc.createElement("D:response")
196
# write href information
197
uparts=urlparse.urlparse(uri)
199
href=doc.createElement("D:href")
200
huri=doc.createTextNode(urllib.quote(fileloc))
201
href.appendChild(huri)
204
ps=doc.createElement("D:propstat")
207
for ns,plist in propnames.items():
209
pr=doc.createElement("D:prop")
211
pr.setAttribute("xmlns:"+nsp,ns)
214
# write propertynames
216
pe=doc.createElement(nsp+":"+p)
224
def mk_prop_response(self,uri,good_props,bad_props,doc):
225
""" make a new <prop> result element
227
We differ between the good props and the bad ones for
228
each generating an extra <propstat>-Node (for each error
232
re=doc.createElement("D:response")
233
# append namespaces to response
235
for nsname in self.namespaces:
236
re.setAttribute("xmlns:ns"+str(nsnum),nsname)
239
# write href information
240
uparts=urlparse.urlparse(uri)
242
href=doc.createElement("D:href")
243
huri=doc.createTextNode(urllib.quote(fileloc))
244
href.appendChild(huri)
247
# write good properties
249
ps=doc.createElement("D:propstat")
252
gp=doc.createElement("D:prop")
253
for ns in good_props.keys():
254
ns_prefix="ns"+str(self.namespaces.index(ns))+":"
255
for p,v in good_props[ns].items():
256
pe=doc.createElement(ns_prefix+str(p))
257
if p=="resourcetype":
259
ve=doc.createElement("D:collection")
262
ve=doc.createTextNode(str(v))
268
s=doc.createElement("D:status")
269
t=doc.createTextNode("HTTP/1.1 200 OK")
274
# now write the errors!
275
if len(bad_props.items()):
277
# write a propstat for each error code
278
for ecode in bad_props.keys():
279
ps=doc.createElement("D:propstat")
281
bp=doc.createElement("D:prop")
284
for ns in bad_props[ecode].keys():
285
ns_prefix="ns"+str(self.namespaces.index(ns))+":"
287
for p in bad_props[ecode][ns]:
288
pe=doc.createElement(ns_prefix+str(p))
291
s=doc.createElement("D:status")
292
t=doc.createTextNode(utils.gen_estring(ecode))
297
# return the new response element
300
def get_propvalues(self,uri):
301
""" create lists of property values for an URI
303
We create two lists for an URI: the properties for
304
which we found a value and the ones for which we
305
only got an error, either because they haven't been
306
found or the user is not allowed to read them.
312
for (ns,plist) in self.proplist.items():
318
r=self.__dataclass.get_prop(uri,ns,prop)
319
good_props[ns][prop]=str(r)
320
except DAV_Error, error_code:
323
# ignore props with error_code if 0 (invisible)
326
if bad_props.has_key(ec):
327
if bad_props[ec].has_key(ns):
328
bad_props[ec][ns].append(prop)
330
bad_props[ec][ns]=[prop]
332
bad_props[ec]={ns:[prop]}
334
return good_props, bad_props