~openerp-commiter/openobject-addons/extra-6.0

« back to all changes in this revision

Viewing changes to document_webdav_old/webdav/DAV/propfind.py

  • Committer: Fabien Pinckaers
  • Date: 2008-12-12 09:09:57 UTC
  • Revision ID: fp@tinyerp.com-20081212090957-cson0n0jove7dt7i
document_webdav

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
 
 
3
"""
 
4
    python davserver
 
5
    Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de)
 
6
 
 
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.
 
11
 
 
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.
 
16
 
 
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
 
20
 
 
21
"""
 
22
 
 
23
 
 
24
from xml.dom import ext
 
25
from xml.dom.Document import Document
 
26
 
 
27
import sys
 
28
import string
 
29
import urlparse
 
30
import urllib
 
31
from StringIO import StringIO
 
32
 
 
33
import utils
 
34
from constants import COLLECTION, OBJECT, DAV_PROPS, RT_ALLPROP, RT_PROPNAME, RT_PROP
 
35
from errors import *
 
36
 
 
37
class PROPFIND:
 
38
    """ parse a propfind xml element and extract props
 
39
 
 
40
    It will set the following instance vars:
 
41
 
 
42
    request_class   : ALLPROP | PROPNAME | PROP
 
43
    proplist    : list of properties
 
44
    nsmap       : map of namespaces
 
45
 
 
46
    The list of properties will contain tuples of the form
 
47
    (element name, ns_prefix, ns_uri)
 
48
 
 
49
 
 
50
    """
 
51
 
 
52
 
 
53
    def __init__(self,uri,dataclass,depth):
 
54
        self.request_type=None
 
55
        self.nsmap={}
 
56
        self.proplist={}
 
57
        self.default_ns=None
 
58
        self.__dataclass=dataclass
 
59
        self.__depth=str(depth)
 
60
        self.__uri=uri
 
61
        self.__has_body=None    # did we parse a body?
 
62
 
 
63
    def read_propfind(self,xml_doc):
 
64
        self.request_type,self.proplist,self.namespaces=utils.parse_propfind(xml_doc)
 
65
 
 
66
    def createResponse(self):
 
67
        """ create the multistatus response
 
68
 
 
69
        This will be delegated to the specific method
 
70
        depending on which request (allprop, propname, prop)
 
71
        was found.
 
72
 
 
73
        If we get a PROPNAME then we simply return the list with empty
 
74
        values which we get from the interface class
 
75
 
 
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.
 
78
 
 
79
        """
 
80
 
 
81
        if self.request_type==RT_ALLPROP:
 
82
            return self.create_allprop()
 
83
 
 
84
        if self.request_type==RT_PROPNAME:
 
85
            return self.create_propname()
 
86
 
 
87
        if self.request_type==RT_PROP:
 
88
            return self.create_prop()
 
89
 
 
90
        # no body means ALLPROP!
 
91
        return self.create_allprop()
 
92
 
 
93
    def create_propname(self):
 
94
        """ create a multistatus response for the prop names """
 
95
 
 
96
        dc=self.__dataclass
 
97
        # create the document generator
 
98
        doc = Document(None)
 
99
        ms=doc.createElement("D:multistatus")
 
100
        ms.setAttribute("xmlns:D","DAV:")
 
101
        doc.appendChild(ms)
 
102
 
 
103
        if self.__depth=="0":
 
104
            pnames=dc.get_propnames(self.__uri)
 
105
            re=self.mk_propname_response(self.__uri,pnames)
 
106
            ms.appendChild(re)
 
107
 
 
108
        elif self.__depth=="1":
 
109
            pnames=dc.get_propnames(self.__uri)
 
110
            re=self.mk_propname_response(self.__uri,pnames)
 
111
            ms.appendChild(re)
 
112
 
 
113
        for newuri in dc.get_childs(self.__uri):
 
114
            pnames=dc.get_propnames(newuri)
 
115
            re=self.mk_propname_response(newuri,pnames)
 
116
            ms.appendChild(re)
 
117
        # *** depth=="infinity"
 
118
 
 
119
        sfile=StringIO()
 
120
        ext.PrettyPrint(doc,stream=sfile)
 
121
        s=sfile.getvalue()
 
122
        sfile.close()
 
123
        return s
 
124
 
 
125
    def create_allprop(self):
 
126
        """ return a list of all properties """
 
127
        self.proplist={}
 
128
        self.namespaces=[]
 
129
        for ns,plist in self.__dataclass.get_propnames(self.__uri).items():
 
130
            self.proplist[ns]=plist
 
131
            self.namespaces.append(ns)
 
132
 
 
133
        return self.create_prop()
 
134
 
 
135
    def create_prop(self):
 
136
        """ handle a <prop> request
 
137
 
 
138
        This will
 
139
 
 
140
        1. set up the <multistatus>-Framework
 
141
 
 
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.
 
145
 
 
146
        3. For each URI call the append_result() method
 
147
           to append the actual <result>-Tag to the result
 
148
           document.
 
149
 
 
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).
 
154
 
 
155
        """
 
156
 
 
157
 
 
158
        # create the document generator
 
159
        doc = Document(None)
 
160
        ms=doc.createElement("D:multistatus")
 
161
        ms.setAttribute("xmlns:D","DAV:")
 
162
        doc.appendChild(ms)
 
163
 
 
164
        if self.__depth=="0":
 
165
            gp,bp=self.get_propvalues(self.__uri)
 
166
            res=self.mk_prop_response(self.__uri,gp,bp,doc)
 
167
            ms.appendChild(res)
 
168
 
 
169
        elif self.__depth=="1":
 
170
            gp,bp=self.get_propvalues(self.__uri)
 
171
            res=self.mk_prop_response(self.__uri,gp,bp,doc)
 
172
            ms.appendChild(res)
 
173
 
 
174
 
 
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)
 
178
            ms.appendChild(res)
 
179
 
 
180
        sfile=StringIO()
 
181
        ext.PrettyPrint(doc,stream=sfile)
 
182
        s=sfile.getvalue()
 
183
        sfile.close()
 
184
        return s
 
185
 
 
186
 
 
187
    def mk_propname_response(self,uri,propnames,doc):
 
188
        """ make a new <prop> result element for a PROPNAME request
 
189
 
 
190
        This will simply format the propnames list.
 
191
        propnames should have the format {NS1 : [prop1, prop2, ...], NS2: ...}
 
192
 
 
193
        """
 
194
        re=doc.createElement("D:response")
 
195
 
 
196
        # write href information
 
197
        uparts=urlparse.urlparse(uri)
 
198
        fileloc=uparts[2]
 
199
        href=doc.createElement("D:href")
 
200
        huri=doc.createTextNode(urllib.quote(fileloc))
 
201
        href.appendChild(huri)
 
202
        re.appendChild(href)
 
203
 
 
204
        ps=doc.createElement("D:propstat")
 
205
        nsnum=0
 
206
 
 
207
        for ns,plist in propnames.items():
 
208
            # write prop element
 
209
            pr=doc.createElement("D:prop")
 
210
            nsp="ns"+str(nsnum)
 
211
            pr.setAttribute("xmlns:"+nsp,ns)
 
212
            nsnum=nsnum+1
 
213
 
 
214
        # write propertynames
 
215
        for p in plist:
 
216
            pe=doc.createElement(nsp+":"+p)
 
217
            pr.appendChild(pe)
 
218
 
 
219
        ps.appendChild(pr)
 
220
        re.appendChild(ps)
 
221
 
 
222
        return re
 
223
 
 
224
    def mk_prop_response(self,uri,good_props,bad_props,doc):
 
225
        """ make a new <prop> result element
 
226
 
 
227
        We differ between the good props and the bad ones for
 
228
        each generating an extra <propstat>-Node (for each error
 
229
        one, that means).
 
230
 
 
231
        """
 
232
        re=doc.createElement("D:response")
 
233
        # append namespaces to response
 
234
        nsnum=0
 
235
        for nsname in self.namespaces:
 
236
            re.setAttribute("xmlns:ns"+str(nsnum),nsname)
 
237
            nsnum=nsnum+1
 
238
 
 
239
        # write href information
 
240
        uparts=urlparse.urlparse(uri)
 
241
        fileloc=uparts[2]
 
242
        href=doc.createElement("D:href")
 
243
        huri=doc.createTextNode(urllib.quote(fileloc))
 
244
        href.appendChild(huri)
 
245
        re.appendChild(href)
 
246
 
 
247
        # write good properties
 
248
        if good_props:
 
249
            ps=doc.createElement("D:propstat")
 
250
            re.appendChild(ps)
 
251
 
 
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":
 
258
                    if v=="1":
 
259
                        ve=doc.createElement("D:collection")
 
260
                        pe.appendChild(ve)
 
261
                else:
 
262
                    ve=doc.createTextNode(str(v))
 
263
                    pe.appendChild(ve)
 
264
 
 
265
                gp.appendChild(pe)
 
266
 
 
267
        ps.appendChild(gp)
 
268
        s=doc.createElement("D:status")
 
269
        t=doc.createTextNode("HTTP/1.1 200 OK")
 
270
        s.appendChild(t)
 
271
        ps.appendChild(s)
 
272
        re.appendChild(ps)
 
273
 
 
274
        # now write the errors!
 
275
        if len(bad_props.items()):
 
276
 
 
277
            # write a propstat for each error code
 
278
            for ecode in bad_props.keys():
 
279
                ps=doc.createElement("D:propstat")
 
280
                re.appendChild(ps)
 
281
                bp=doc.createElement("D:prop")
 
282
                ps.appendChild(bp)
 
283
 
 
284
                for ns in bad_props[ecode].keys():
 
285
                    ns_prefix="ns"+str(self.namespaces.index(ns))+":"
 
286
 
 
287
                for p in bad_props[ecode][ns]:
 
288
                    pe=doc.createElement(ns_prefix+str(p))
 
289
                    bp.appendChild(pe)
 
290
 
 
291
                s=doc.createElement("D:status")
 
292
                t=doc.createTextNode(utils.gen_estring(ecode))
 
293
                s.appendChild(t)
 
294
                ps.appendChild(s)
 
295
                re.appendChild(ps)
 
296
 
 
297
        # return the new response element
 
298
        return re
 
299
 
 
300
    def get_propvalues(self,uri):
 
301
        """ create lists of property values for an URI
 
302
 
 
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.
 
307
 
 
308
        """
 
309
        good_props={}
 
310
        bad_props={}
 
311
 
 
312
        for (ns,plist) in self.proplist.items():
 
313
            good_props[ns]={}
 
314
            bad_props={}
 
315
            ec = 0
 
316
            for prop in plist:
 
317
                try:
 
318
                    r=self.__dataclass.get_prop(uri,ns,prop)
 
319
                    good_props[ns][prop]=str(r)
 
320
                except DAV_Error, error_code:
 
321
                    ec=error_code[0]
 
322
 
 
323
                # ignore props with error_code if 0 (invisible)
 
324
                if ec==0: continue
 
325
 
 
326
                if bad_props.has_key(ec):
 
327
                    if bad_props[ec].has_key(ns):
 
328
                        bad_props[ec][ns].append(prop)
 
329
                    else:
 
330
                        bad_props[ec][ns]=[prop]
 
331
                else:
 
332
                    bad_props[ec]={ns:[prop]}
 
333
 
 
334
        return good_props, bad_props
 
335