From 6b2c832f5f9cc1667cd50230f8f0a0139d352201 Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Tue, 7 Dec 2010 15:40:41 +0200 Subject: doc webdav: Implement locking support This replaces the pseydo-locking of python-webdav library with a real db-based locking. Locks are stored as DAV properties, which will effectively also be listed in the PROPFIND response of the nodes. With locking in place, Office suites can collaborate on documents online. bzr revid: p_christ@hol.gr-20101207134041-8negkvxrbscv7fs7 --- addons/document_webdav/webdav_server.py | 136 ++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) (limited to 'addons/document_webdav/webdav_server.py') diff --git a/addons/document_webdav/webdav_server.py b/addons/document_webdav/webdav_server.py index 0e5973c95b3..5d73ae292f2 100644 --- a/addons/document_webdav/webdav_server.py +++ b/addons/document_webdav/webdav_server.py @@ -38,7 +38,9 @@ import urllib import re from string import atoi from DAV.errors import * +from DAV.utils import IfParser, TagList # from DAV.constants import DAV_VERSION_1, DAV_VERSION_2 +from xml.dom import minidom khtml_re = re.compile(r' KHTML/([0-9\.]+) ') @@ -103,6 +105,7 @@ class DAVHandler(HttpOptions, FixSendError, DAVRequestHandler): self.headers['Destination'] = up.path[len(self.davpath):] else: raise DAV_Forbidden("Not allowed to copy/move outside webdav path") + # TODO: locks DAVRequestHandler.copymove(self, CLASS) def get_davpath(self): @@ -262,6 +265,139 @@ class DAVHandler(HttpOptions, FixSendError, DAVRequestHandler): except DAV_Error, (ec, dd): return self.send_status(ec) + def do_UNLOCK(self): + """ Unlocks given resource """ + + dc = self.IFACE_CLASS + self.log_message('UNLOCKing resource %s' % self.headers) + + uri = urlparse.urljoin(self.get_baseuri(dc), self.path) + uri = urllib.unquote(uri) + + token = self.headers.get('Lock-Token', False) + if token: + token = token.strip() + if token[0] == '<' and token[-1] == '>': + token = token[1:-1] + else: + token = False + + if not token: + return self.send_status(400, 'Bad lock token') + + try: + res = dc.unlock(uri, token) + except DAV_Error, (ec, dd): + return self.send_status(ec, dd) + + if res == True: + self.send_body(None, '204', 'OK', 'Resource unlocked.') + else: + # We just differentiate the description, for debugging purposes + self.send_body(None, '204', 'OK', 'Resource not locked.') + + def do_LOCK(self): + """ Attempt to place a lock on the given resource. + """ + + dc = self.IFACE_CLASS + lock_data = {} + + self.log_message('LOCKing resource %s' % self.headers) + + body = None + if self.headers.has_key('Content-Length'): + l = self.headers['Content-Length'] + body = self.rfile.read(atoi(l)) + + depth = self.headers.get('Depth', 'infinity') + + uri = urlparse.urljoin(self.get_baseuri(dc), self.path) + uri = urllib.unquote(uri) + self.log_message('do_LOCK: uri = %s' % uri) + + ifheader = self.headers.get('If') + + if ifheader: + ldif = IfParser(ifheader) + if isinstance(ldif, list): + if len(ldif) !=1 or (not isinstance(ldif[0], TagList)) \ + or len(ldif[0].list) != 1: + raise DAV_Error(400, "Cannot accept multiple tokens") + ldif = ldif[0].list[0] + if ldif[0] == '<' and ldif[-1] == '>': + ldif = ldif[1:-1] + + lock_data['token'] = ldif + + if not body: + lock_data['refresh'] = True + else: + lock_data['refresh'] = False + lock_data.update(self._lock_unlock_parse(body)) + + if lock_data['refresh'] and not lock_data.get('token', False): + raise DAV_Error(400, 'Lock refresh must specify token') + + lock_data['depth'] = depth + + try: + created, data, lock_token = dc.lock(uri, lock_data) + except DAV_Error, (ec, dd): + return self.send_status(ec, dd) + + headers = {} + if not lock_data['refresh']: + headers['Lock-Token'] = '<%s>' % lock_token + + if created: + self.send_body(data, '201', 'Created', ctype='text/xml', headers=headers) + else: + self.send_body(data, '200', 'OK', ctype='text/xml', headers=headers) + + def _lock_unlock_parse(self, body): + # Override the python-webdav function, with some improvements + # Unlike the py-webdav one, we also parse the owner minidom elements into + # pure pythonic struct. + doc = minidom.parseString(body) + + data = {} + owners = [] + for info in doc.getElementsByTagNameNS('DAV:', 'lockinfo'): + for scope in info.getElementsByTagNameNS('DAV:', 'lockscope'): + for scc in scope.childNodes: + if scc.nodeType == info.ELEMENT_NODE \ + and scc.namespaceURI == 'DAV:': + data['lockscope'] = scc.localName + break + for ltype in info.getElementsByTagNameNS('DAV:', 'locktype'): + for ltc in ltype.childNodes: + if ltc.nodeType == info.ELEMENT_NODE \ + and ltc.namespaceURI == 'DAV:': + data['locktype'] = ltc.localName + break + for own in info.getElementsByTagNameNS('DAV:', 'owner'): + for ono in own.childNodes: + if ono.nodeType == info.TEXT_NODE: + if ono.data: + owners.append(ono.data) + elif ono.nodeType == info.ELEMENT_NODE \ + and ono.namespaceURI == 'DAV:' \ + and ono.localName == 'href': + href = '' + for hno in ono.childNodes: + if hno.nodeType == info.TEXT_NODE: + href += hno.data + owners.append(('href','DAV:', href)) + + if len(owners) == 1: + data['lockowner'] = owners[0] + elif not owners: + pass + else: + data['lockowner'] = owners + return data + from service.http_server import reg_http_service,OpenERPAuthProvider class DAVAuthProvider(OpenERPAuthProvider): -- cgit v1.2.3 From 03b7cb90c41a2407053d5e823dd676f2cbe5229f Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Thu, 9 Dec 2010 11:59:50 +0200 Subject: doc webdav: update copyright header, add disclaimer about python-webdav Yes, I have been subclassing the DAV module and improving on the existing code, regarding that we couldn't ship our own version of the whole python-webdav library (as in v5.x). At commit b2a2c3f95416788, on 2010-04-06, we explicitly deleted our custom copies of the DAV module and linked to the upstream project, in fact. bzr revid: p_christ@hol.gr-20101209095950-qf2ppgdxw8y2lake --- addons/document_webdav/webdav_server.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'addons/document_webdav/webdav_server.py') diff --git a/addons/document_webdav/webdav_server.py b/addons/document_webdav/webdav_server.py index 5d73ae292f2..5b0b418e9a1 100644 --- a/addons/document_webdav/webdav_server.py +++ b/addons/document_webdav/webdav_server.py @@ -1,8 +1,14 @@ # -*- encoding: utf-8 -*- # -# Copyright P. Christeas 2008,2009 +# Copyright P. Christeas 2008-2010 # +# Disclaimer: Many of the functions below borrow code from the +# python-webdav library (http://code.google.com/p/pywebdav/ ), +# which they import and override to suit OpenERP functionality. +# python-webdav was written by: Simon Pamies +# Christian Scholz +# Vince Spicer # # WARNING: This program as such is intended to be used by professional # programmers who take the whole responsability of assessing all potential -- cgit v1.2.3