- add sources.
[platform/framework/web/crosswalk.git] / src / tools / telemetry / third_party / davclient / davclient.py
1 #   Copyright (c) 2006-2007 Open Source Applications Foundation
2 #
3 #   Licensed under the Apache License, Version 2.0 (the "License");
4 #   you may not use this file except in compliance with the License.
5 #   You may obtain a copy of the License at
6 #
7 #       http://www.apache.org/licenses/LICENSE-2.0
8 #
9 #   Unless required by applicable law or agreed to in writing, software
10 #   distributed under the License is distributed on an "AS IS" BASIS,
11 #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 #   See the License for the specific language governing permissions and
13 #   limitations under the License.
14
15 import urlparse, httplib, copy, base64, StringIO
16 import urllib
17
18 try:
19     from xml.etree import ElementTree
20 except:
21     from elementtree import ElementTree
22
23 __all__ = ['DAVClient']
24
25 def object_to_etree(parent, obj, namespace=''):
26     """This function takes in a python object, traverses it, and adds it to an existing etree object"""
27     
28     if type(obj) is int or type(obj) is float or type(obj) is str:
29         # If object is a string, int, or float just add it
30         obj = str(obj)
31         if obj.startswith('{') is False:
32             ElementTree.SubElement(parent, '{%s}%s' % (namespace, obj))
33         else:
34             ElementTree.SubElement(parent, obj)
35         
36     elif type(obj) is dict:
37         # If the object is a dictionary we'll need to parse it and send it back recusively
38         for key, value in obj.items():
39             if key.startswith('{') is False:
40                 key_etree = ElementTree.SubElement(parent, '{%s}%s' % (namespace, key))
41                 object_to_etree(key_etree, value, namespace=namespace)
42             else:
43                 key_etree = ElementTree.SubElement(parent, key)
44                 object_to_etree(key_etree, value, namespace=namespace)
45             
46     elif type(obj) is list:
47         # If the object is a list parse it and send it back recursively
48         for item in obj:
49             object_to_etree(parent, item, namespace=namespace)
50             
51     else:
52         # If it's none of previous types then raise
53         raise TypeError, '%s is an unsupported type' % type(obj)
54         
55
56 class DAVClient(object):
57     
58     def __init__(self, url='http://localhost:8080'):
59         """Initialization"""
60         
61         self._url = urlparse.urlparse(url)
62         
63         self.headers = {'Host':self._url[1], 
64                         'User-Agent': 'python.davclient.DAVClient/0.1'} 
65         
66         
67     def _request(self, method, path='', body=None, headers=None):
68         """Internal request method"""
69         self.response = None
70         
71         if headers is None:
72             headers = copy.copy(self.headers)
73         else:
74             new_headers = copy.copy(self.headers)
75             new_headers.update(headers)
76             headers = new_headers
77         
78         if self._url.scheme == 'http':
79             self._connection = httplib.HTTPConnection(self._url[1])
80         elif self._url.scheme == 'https':
81             self._connection = httplib.HTTPSConnection(self._url[1])
82         else:
83             raise Exception, 'Unsupported scheme'
84         
85         self._connection.request(method, path, body, headers)
86             
87         self.response = self._connection.getresponse()
88         
89         self.response.body = self.response.read()
90         
91         # Try to parse and get an etree
92         try:
93             self._get_response_tree()
94         except:
95             pass
96         
97             
98     def _get_response_tree(self):
99         """Parse the response body into an elementree object"""
100         self.response.tree = ElementTree.fromstring(self.response.body)
101         return self.response.tree
102         
103     def set_basic_auth(self, username, password):
104         """Set basic authentication"""
105         auth = 'Basic %s' % base64.encodestring('%s:%s' % (username, password)).strip()
106         self._username = username
107         self._password = password
108         self.headers['Authorization'] = auth
109         
110     ## HTTP DAV methods ##
111         
112     def get(self, path, headers=None):
113         """Simple get request"""
114         self._request('GET', path, headers=headers)
115         return self.response.body
116         
117     def head(self, path, headers=None):
118         """Basic HEAD request"""
119         self._request('HEAD', path, headers=headers)
120         
121     def put(self, path, body=None, f=None, headers=None):
122         """Put resource with body"""
123         if f is not None:
124             body = f.read()
125             
126         self._request('PUT', path, body=body, headers=headers)
127         
128     def post(self, path, body=None, headers=None):
129         """POST resource with body"""
130
131         self._request('POST', path, body=body, headers=headers)
132         
133     def mkcol(self, path, headers=None):
134         """Make DAV collection"""
135         self._request('MKCOL', path=path, headers=headers)
136         
137     make_collection = mkcol
138         
139     def delete(self, path, headers=None):
140         """Delete DAV resource"""
141         self._request('DELETE', path=path, headers=headers)
142         
143     def copy(self, source, destination, body=None, depth='infinity', overwrite=True, headers=None):
144         """Copy DAV resource"""
145         # Set all proper headers
146         if headers is None:
147             headers = {'Destination':destination}
148         else:
149             headers['Destination'] = self._url.geturl() + destination
150         if overwrite is False:
151             headers['Overwrite'] = 'F'
152         headers['Depth'] = depth
153             
154         self._request('COPY', source, body=body, headers=headers)
155         
156         
157     def copy_collection(self, source, destination, depth='infinity', overwrite=True, headers=None):
158         """Copy DAV collection"""
159         body = '<?xml version="1.0" encoding="utf-8" ?><d:propertybehavior xmlns:d="DAV:"><d:keepalive>*</d:keepalive></d:propertybehavior>'
160         
161         # Add proper headers
162         if headers is None:
163             headers = {}
164         headers['Content-Type'] = 'text/xml; charset="utf-8"'
165         
166         self.copy(source, destination, body=unicode(body, 'utf-8'), depth=depth, overwrite=overwrite, headers=headers)
167         
168         
169     def move(self, source, destination, body=None, depth='infinity', overwrite=True, headers=None):
170         """Move DAV resource"""
171         # Set all proper headers
172         if headers is None:
173             headers = {'Destination':destination}
174         else:
175             headers['Destination'] = self._url.geturl() + destination
176         if overwrite is False:
177             headers['Overwrite'] = 'F'
178         headers['Depth'] = depth
179             
180         self._request('MOVE', source, body=body, headers=headers)
181         
182         
183     def move_collection(self, source, destination, depth='infinity', overwrite=True, headers=None):
184         """Move DAV collection and copy all properties"""
185         body = '<?xml version="1.0" encoding="utf-8" ?><d:propertybehavior xmlns:d="DAV:"><d:keepalive>*</d:keepalive></d:propertybehavior>'
186         
187         # Add proper headers
188         if headers is None:
189             headers = {}
190         headers['Content-Type'] = 'text/xml; charset="utf-8"'
191
192         self.move(source, destination, unicode(body, 'utf-8'), depth=depth, overwrite=overwrite, headers=headers)
193         
194         
195     def propfind(self, path, properties='allprop', namespace='DAV:', depth=None, headers=None):
196         """Property find. If properties arg is unspecified it defaults to 'allprop'"""
197         # Build propfind xml
198         root = ElementTree.Element('{DAV:}propfind')
199         if type(properties) is str:
200             ElementTree.SubElement(root, '{DAV:}%s' % properties)
201         else:
202             props = ElementTree.SubElement(root, '{DAV:}prop')
203             object_to_etree(props, properties, namespace=namespace)
204         tree = ElementTree.ElementTree(root)
205         
206         # Etree won't just return a normal string, so we have to do this
207         body = StringIO.StringIO()
208         tree.write(body)
209         body = body.getvalue()
210                 
211         # Add proper headers
212         if headers is None:
213             headers = {}
214         if depth is not None:
215             headers['Depth'] = depth
216         headers['Content-Type'] = 'text/xml; charset="utf-8"'
217         
218         # Body encoding must be utf-8, 207 is proper response
219         self._request('PROPFIND', path, body=unicode('<?xml version="1.0" encoding="utf-8" ?>\n'+body, 'utf-8'), headers=headers)
220         
221         if self.response is not None and hasattr(self.response, 'tree') is True:
222             property_responses = {}
223             for response in self.response.tree._children:
224                 property_href = response.find('{DAV:}href')
225                 property_stat = response.find('{DAV:}propstat')
226                 
227                 def parse_props(props):
228                     property_dict = {}
229                     for prop in props:
230                         if prop.tag.find('{DAV:}') is not -1:
231                             name = prop.tag.split('}')[-1]
232                         else:
233                             name = prop.tag
234                         if len(prop._children) is not 0:
235                             property_dict[name] = parse_props(prop._children)
236                         else:
237                             property_dict[name] = prop.text
238                     return property_dict
239                 
240                 if property_href is not None and property_stat is not None:
241                     property_dict = parse_props(property_stat.find('{DAV:}prop')._children)
242                     property_responses[property_href.text] = property_dict
243             return property_responses
244         
245     def proppatch(self, path, set_props=None, remove_props=None, namespace='DAV:', headers=None):
246         """Patch properties on a DAV resource. If namespace is not specified the DAV namespace is used for all properties"""
247         root = ElementTree.Element('{DAV:}propertyupdate')
248         
249         if set_props is not None:
250             prop_set = ElementTree.SubElement(root, '{DAV:}set')
251             object_to_etree(prop_set, set_props, namespace=namespace)
252         if remove_props is not None:
253             prop_remove = ElementTree.SubElement(root, '{DAV:}remove')
254             object_to_etree(prop_remove, remove_props, namespace=namespace)
255         
256         tree = ElementTree.ElementTree(root)
257         
258         # Add proper headers
259         if headers is None:
260             headers = {}
261         headers['Content-Type'] = 'text/xml; charset="utf-8"'
262         
263         self._request('PROPPATCH', path, body=unicode('<?xml version="1.0" encoding="utf-8" ?>\n'+body, 'utf-8'), headers=headers)
264         
265         
266     def set_lock(self, path, owner, locktype='exclusive', lockscope='write', depth=None, headers=None):
267         """Set a lock on a dav resource"""
268         root = ElementTree.Element('{DAV:}lockinfo')
269         object_to_etree(root, {'locktype':locktype, 'lockscope':lockscope, 'owner':{'href':owner}}, namespace='DAV:')
270         tree = ElementTree.ElementTree(root)
271         
272         # Add proper headers
273         if headers is None:
274             headers = {}
275         if depth is not None:
276             headers['Depth'] = depth
277         headers['Content-Type'] = 'text/xml; charset="utf-8"'
278         headers['Timeout'] = 'Infinite, Second-4100000000'
279         
280         self._request('LOCK', path, body=unicode('<?xml version="1.0" encoding="utf-8" ?>\n'+body, 'utf-8'), headers=headers)
281         
282         locks = self.response.etree.finall('.//{DAV:}locktoken')
283         lock_list = []
284         for lock in locks:
285             lock_list.append(lock.getchildren()[0].text.strip().strip('\n'))
286         return lock_list
287         
288
289     def refresh_lock(self, path, token, headers=None):
290         """Refresh lock with token"""
291         
292         if headers is None:
293             headers = {}
294         headers['If'] = '(<%s>)' % token
295         headers['Timeout'] = 'Infinite, Second-4100000000'
296         
297         self._request('LOCK', path, body=None, headers=headers)
298         
299         
300     def unlock(self, path, token, headers=None):
301         """Unlock DAV resource with token"""
302         if headers is None:
303             headers = {}
304         headers['Lock-Tocken'] = '<%s>' % token
305         
306         self._request('UNLOCK', path, body=None, headers=headers)
307         
308
309
310
311
312