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
This commit is contained in:
P. Christeas
2010-06-23 13:54:37 +03:00
parent 0be3a0757c
commit a26e8ae2ee
3 changed files with 117 additions and 56 deletions
+55 -46
View File
@@ -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
+45 -2
View File
@@ -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
PROPFIND.mk_prop_response = mk_prop_response
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
+17 -8
View File
@@ -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()