diff options
| author | P. Christeas <p_christ@hol.gr> | 2010-06-23 13:54:37 +0300 |
|---|---|---|
| committer | P. Christeas <p_christ@hol.gr> | 2010-06-23 13:54:37 +0300 |
| commit | a26e8ae2eef6af0d33255f1081cfcc978c0c5138 (patch) | |
| tree | 580b536630a72156b0c32f8ddcfb6afb069426b5 /addons/document_webdav | |
| parent | 0be3a0757ca31d9abe8f78f86c3606200d546941 (diff) | |
Doc Webdav: Cleanup code, fix db listing, children paths.
This is a reshape of the code, since the porting. While the MultiHttpHandler
will strip the '/webdav' part of the path, the DAV code will try to
generate more paths without it. So, there must be consinstent functions
that will convert (at mk_prop_response and mk_propname_response) to the
full path or back. Also, only have one function that will strip the
db name from the path, so that we control the auth requirements (for the
purpose of database listings, which shouldn't require authentication).
bzr revid: p_christ@hol.gr-20100623105437-kmy0ccqihu5h9ydp
Diffstat (limited to 'addons/document_webdav')
| -rw-r--r-- | addons/document_webdav/dav_fs.py | 101 | ||||
| -rw-r--r-- | addons/document_webdav/webdav.py | 45 | ||||
| -rw-r--r-- | addons/document_webdav/webdav_server.py | 25 |
3 files changed, 116 insertions, 55 deletions
diff --git a/addons/document_webdav/dav_fs.py b/addons/document_webdav/dav_fs.py index a0d70704579..8fa3ed5ed88 100644 --- a/addons/document_webdav/dav_fs.py +++ b/addons/document_webdav/dav_fs.py @@ -55,8 +55,6 @@ class openerp_dav_handler(dav_interface): M_NS={ "DAV:" : dav_interface.M_NS['DAV:'],} def __init__(self, parent, verbose=False): - self.db_name = False - self.directory_id=False self.db_name_list=[] self.parent = parent self.baseuri = parent.baseuri @@ -65,10 +63,10 @@ class openerp_dav_handler(dav_interface): def get_propnames(self, uri): props = self.PROPS self.parent.log_message('get propnames: %s' % uri) - if uri[-1]=='/':uri=uri[:-1] cr, uid, pool, dbname, uri2 = self.get_cr(uri) if not dbname: if cr: cr.close() + # TODO: maybe limit props for databases..? return props node = self.uri2object(cr, uid, pool, uri2) if node: @@ -83,7 +81,6 @@ class openerp_dav_handler(dav_interface): raise DAV_NotFound def match_prop(self, uri, match, ns, propname): - if uri[-1]=='/':uri=uri[:-1] cr, uid, pool, dbname, uri2 = self.get_cr(uri) if not dbname: if cr: cr.close() @@ -104,8 +101,7 @@ class openerp_dav_handler(dav_interface): pname -- name of the property """ if self.M_NS.has_key(ns): - return dav_interface.get_prop(self, uri, ns, propname) - if uri[-1]=='/':uri=uri[:-1] + return dav_interface.get_prop(self, uri, ns, propname) cr, uid, pool, dbname, uri2 = self.get_cr(uri) if not dbname: if cr: cr.close() @@ -114,19 +110,46 @@ class openerp_dav_handler(dav_interface): if not node: cr.close() raise DAV_NotFound - res = node.get_dav_eprop(cr, ns, propname) + res = node.get_dav_eprop(cr, ns, propname) cr.close() return res - def get_db(self,uri): - names=self.uri2local(uri).split('/') - self.db_name=False - if len(names) > 1: - self.db_name=self.uri2local(uri).split('/')[1] - if self.db_name=='': - raise Exception,'Plese specify Database name in folder' - return self.db_name - + def get_db(self, uri, rest_ret=False, allow_last=False): + """Parse the uri and get the dbname and the rest. + Db name should be the first component in the unix-like + path supplied in uri. + + @param rest_ret Instead of the db_name, return (db_name, rest), + where rest is the remaining path + @param allow_last If the dbname is the last component in the + path, allow it to be resolved. The default False value means + we will not attempt to use the db, unless there is more + path. + + @return db_name or (dbname, rest) depending on rest_ret, + will return dbname=False when component is not found. + """ + + uri2 = self.uri2local(uri) + if uri2.startswith('/'): + uri2 = uri2[1:] + names=uri2.split('/',1) + db_name=False + rest = None + if allow_last: + ll = 0 + else: + ll = 1 + if len(names) > ll and names[0]: + db_name = names[0] + names = names[1:] + + if rest_ret: + if len(names): + rest = names[0] + return db_name, rest + return db_name + def urijoin(self,*ajoin): """ Return the base URI of this request, or even join it with the @@ -158,8 +181,7 @@ class openerp_dav_handler(dav_interface): def get_childs(self, uri, filters=None): """ return the child objects as self.baseuris for the given URI """ self.parent.log_message('get childs: %s' % uri) - if uri[-1]=='/':uri=uri[:-1] - cr, uid, pool, dbname, uri2 = self.get_cr(uri) + cr, uid, pool, dbname, uri2 = self.get_cr(uri, allow_last=True) if not dbname: if cr: cr.close() @@ -200,38 +222,33 @@ class openerp_dav_handler(dav_interface): # # pos: -1 to get the parent of the uri # - def get_cr(self, uri): + def get_cr(self, uri, allow_last=False): + """ Split the uri, grab a cursor for that db + """ pdb = self.parent.auth_proxy.last_auth - reluri = self.uri2local(uri) - try: - dbname = reluri.split('/')[1] - except: - dbname = False + dbname, uri2 = self.get_db(uri, rest_ret=True, allow_last=allow_last) + uri2 = (uri2 and uri2.split('/')) or [] if not dbname: - return None, None, None, False, None - if not pdb and dbname: - # if dbname was in our uri, we should have authenticated - # against that. - raise Exception("Programming error") - #assert pdb == dbname, " %s != %s" %(pdb, dbname) + return None, None, None, False, uri2 + # if dbname was in our uri, we should have authenticated + # against that. + assert pdb == dbname, " %s != %s" %(pdb, dbname) res = self.parent.auth_proxy.auth_creds.get(dbname, False) - if not res: + if not res: self.parent.auth_proxy.checkRequest(self.parent, uri, dbname) - res = self.parent.auth_proxy.auth_creds[dbname] + res = self.parent.auth_proxy.auth_creds[dbname] user, passwd, dbn2, uid = res db,pool = pooler.get_db_and_pool(dbname) cr = db.cursor() - uri2 = reluri.split('/')[2:] return cr, uid, pool, dbname, uri2 - def uri2object(self, cr, uid, pool,uri): + def uri2object(self, cr, uid, pool, uri): if not uid: return None return pool.get('document.directory').get_object(cr, uid, uri) def get_data(self,uri, rrange=None): self.parent.log_message('GET: %s' % uri) - if uri[-1]=='/':uri=uri[:-1] cr, uid, pool, dbname, uri2 = self.get_cr(uri) try: if not dbname: @@ -265,7 +282,6 @@ class openerp_dav_handler(dav_interface): def _get_dav_resourcetype(self,uri): """ return type of object """ self.parent.log_message('get RT: %s' % uri) - if uri[-1]=='/':uri=uri[:-1] cr, uid, pool, dbname, uri2 = self.get_cr(uri) try: if not dbname: @@ -281,7 +297,6 @@ class openerp_dav_handler(dav_interface): def _get_dav_displayname(self,uri): self.parent.log_message('get DN: %s' % uri) - if uri[-1]=='/':uri=uri[:-1] cr, uid, pool, dbname, uri2 = self.get_cr(uri) if not dbname: cr.close() @@ -297,7 +312,6 @@ class openerp_dav_handler(dav_interface): def _get_dav_getcontentlength(self, uri): """ return the content length of an object """ self.parent.log_message('get length: %s' % uri) - if uri[-1]=='/':uri=uri[:-1] result = 0 cr, uid, pool, dbname, uri2 = self.get_cr(uri) if not dbname: @@ -315,7 +329,6 @@ class openerp_dav_handler(dav_interface): def _get_dav_getetag(self,uri): """ return the ETag of an object """ self.parent.log_message('get etag: %s' % uri) - if uri[-1]=='/':uri=uri[:-1] result = 0 cr, uid, pool, dbname, uri2 = self.get_cr(uri) if not dbname: @@ -332,7 +345,6 @@ class openerp_dav_handler(dav_interface): @memoize(CACHE_SIZE) def get_lastmodified(self, uri): """ return the last modified date of the object """ - if uri[-1]=='/':uri=uri[:-1] today = time.time() cr, uid, pool, dbname, uri2 = self.get_cr(uri) if not dbname: @@ -351,7 +363,6 @@ class openerp_dav_handler(dav_interface): @memoize(CACHE_SIZE) def get_creationdate(self, uri): """ return the last modified date of the object """ - if uri[-1]=='/':uri=uri[:-1] cr, uid, pool, dbname, uri2 = self.get_cr(uri) if not dbname: raise DAV_Error, 409 @@ -370,7 +381,6 @@ class openerp_dav_handler(dav_interface): @memoize(CACHE_SIZE) def _get_dav_getcontenttype(self,uri): self.parent.log_message('get contenttype: %s' % uri) - if uri[-1]=='/':uri=uri[:-1] cr, uid, pool, dbname, uri2 = self.get_cr(uri) if not dbname: return 'httpd/unix-directory' @@ -443,10 +453,8 @@ class openerp_dav_handler(dav_interface): def rmcol(self,uri): """ delete a collection """ - if uri[-1]=='/':uri=uri[:-1] - cr, uid, pool, dbname, uri2 = self.get_cr(uri) - if not dbname: # *-* + if not dbname: raise DAV_Error, 409 node = self.uri2object(cr, uid, pool, uri2) node.rmcol(cr) @@ -456,7 +464,6 @@ class openerp_dav_handler(dav_interface): return 204 def rm(self,uri): - if uri[-1]=='/':uri=uri[:-1] cr, uid, pool,dbname, uri2 = self.get_cr(uri) if not dbname: cr.close() @@ -635,3 +642,5 @@ class openerp_dav_handler(dav_interface): def is_collection(self, uri): """ test if the given uri is a collection """ return self._get_dav_resourcetype(uri)==COLLECTION + +#eof diff --git a/addons/document_webdav/webdav.py b/addons/document_webdav/webdav.py index 2406bc10492..e904d2ecfb7 100644 --- a/addons/document_webdav/webdav.py +++ b/addons/document_webdav/webdav.py @@ -3,6 +3,7 @@ # # OpenERP, Open Source Management Solution # Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>). +# Copyright (c) 1999 Christian Scholz (ruebe@aachen.heimat.de) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -48,7 +49,9 @@ def mk_prop_response(self, uri, good_props, bad_props, doc): uparts=urlparse.urlparse(uri) fileloc=uparts[2] href=doc.createElement("D:href") - huri=doc.createTextNode(uparts[0]+'://'+'/'.join(uparts[1:2]) + urllib.quote(fileloc)) + davpath = self._dataclass.parent.get_davpath() + hurl = '%s://%s%s%s' % (uparts[0], uparts[1], davpath, urllib.quote(fileloc)) + huri=doc.createTextNode(hurl) href.appendChild(huri) re.appendChild(href) @@ -111,5 +114,45 @@ def mk_prop_response(self, uri, good_props, bad_props, doc): return re +def mk_propname_response(self,uri,propnames,doc): + """ make a new <prop> result element for a PROPNAME request + + This will simply format the propnames list. + propnames should have the format {NS1 : [prop1, prop2, ...], NS2: ...} + + """ + re=doc.createElement("D:response") + + # write href information + uparts=urlparse.urlparse(uri) + fileloc=uparts[2] + href=doc.createElement("D:href") + davpath = self._dataclass.parent.get_davpath() + hurl = '%s://%s%s%s' % (uparts[0], uparts[1], davpath, urllib.quote(fileloc)) + huri=doc.createTextNode(hurl) + href.appendChild(huri) + re.appendChild(href) + + ps=doc.createElement("D:propstat") + nsnum=0 + + for ns,plist in propnames.items(): + # write prop element + pr=doc.createElement("D:prop") + nsp="ns"+str(nsnum) + pr.setAttribute("xmlns:"+nsp,ns) + nsnum=nsnum+1 + + # write propertynames + for p in plist: + pe=doc.createElement(nsp+":"+p) + pr.appendChild(pe) + + ps.appendChild(pr) + re.appendChild(ps) + + return re + PROPFIND.mk_prop_response = mk_prop_response +PROPFIND.mk_propname_response = mk_propname_response diff --git a/addons/document_webdav/webdav_server.py b/addons/document_webdav/webdav_server.py index b907ed94df6..c920c84ea72 100644 --- a/addons/document_webdav/webdav_server.py +++ b/addons/document_webdav/webdav_server.py @@ -67,18 +67,17 @@ class DAVHandler(FixSendError,DAVRequestHandler): pass def get_db_from_path(self, uri): - if uri or uri == '/': - dbs = self.IFACE_CLASS.db_list() - res = len(dbs) and dbs[0] or False - else: - res = self.IFACE_CLASS.get_db(uri) + # interface class will handle all cases. + res = self.IFACE_CLASS.get_db(uri, allow_last=True) return res def setup(self): - davpath = '/'+config.get_misc('webdav','vdir','webdav') + self.davpath = '/'+config.get_misc('webdav','vdir','webdav') self.baseuri = "http://%s:%d/"% (self.server.server_name, self.server.server_port) self.IFACE_CLASS = openerp_dav_handler(self, self.verbose) + def get_davpath(self): + return self.davpath def log_message(self, format, *args): netsvc.Logger().notifyChannel('webdav', netsvc.LOG_DEBUG_RPC, format % args) @@ -164,8 +163,18 @@ class DAVHandler(FixSendError,DAVRequestHandler): self.send_body(None, '201', 'Created', '', headers=headers) +from service.http_server import reg_http_service,OpenERPAuthProvider + +class DAVAuthProvider(OpenERPAuthProvider): + def authenticate(self, db, user, passwd, client_address): + """ authenticate, but also allow the False db, meaning to skip + authentication when no db is specified. + """ + if db is False and user is None and passwd is None: + return True + return OpenERPAuthProvider.authenticate(self, db, user, passwd, client_address) + try: - from service.http_server import reg_http_service,OpenERPAuthProvider if (config.get_misc('webdav','enable',True)): directory = '/'+config.get_misc('webdav','vdir','webdav') @@ -180,7 +189,7 @@ try: conf = OpenDAVConfig(**_dc) handler._config = conf - reg_http_service(HTTPDir(directory,DAVHandler,OpenERPAuthProvider())) + reg_http_service(HTTPDir(directory,DAVHandler,DAVAuthProvider())) netsvc.Logger().notifyChannel('webdav', netsvc.LOG_INFO, "WebDAV service registered at path: %s/ "% directory) except Exception, e: logger = netsvc.Logger() |
