334 lines
11 KiB
Python
334 lines
11 KiB
Python
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
|
#this repository contains the full copyright notices and license terms.
|
|
import urlparse
|
|
import socket
|
|
import base64
|
|
import time
|
|
from DAV import AuthServer, WebDAVServer, iface
|
|
from DAV.errors import *
|
|
from DAV.constants import COLLECTION, OBJECT
|
|
from DAV.utils import get_uriparentpath, get_urifilename, quote_uri
|
|
from DAV.davcmd import copyone, copytree, moveone, movetree, delone, deltree
|
|
from netsvc import LocalService, SSLSocket
|
|
import security
|
|
import pooler
|
|
from version import PACKAGE, VERSION, WEBSITE
|
|
from tools.misc import Cache, LocalDict
|
|
import urllib
|
|
|
|
# Local int for multi-thread
|
|
import sys
|
|
from threading import local
|
|
|
|
|
|
class LocalInt(local):
|
|
|
|
def __init__(self, value=0):
|
|
self.value = value
|
|
|
|
def __int__(self):
|
|
return int(self.value)
|
|
|
|
USER_ID = LocalInt(0)
|
|
CACHE = LocalDict()
|
|
|
|
# Fix for bad use of Document in DAV.utils make_xmlresponse
|
|
from DAV.utils import VERSION as DAV_VERSION
|
|
if DAV_VERSION == '0.6':
|
|
from xml.dom.Document import Document
|
|
Document.Document = Document
|
|
|
|
# Fix for unset _config in DAVRequestHandler
|
|
if DAV_VERSION == '0.8':
|
|
|
|
|
|
class DAV:
|
|
lockemulation = False
|
|
verbose = False
|
|
|
|
|
|
class _Config:
|
|
DAV = DAV()
|
|
|
|
WebDAVServer.DAVRequestHandler._config = _Config()
|
|
|
|
|
|
class TrytonDAVInterface(iface.dav_interface):
|
|
|
|
def __init__(self, interface, port, secure=False):
|
|
if secure:
|
|
protocol = 'https'
|
|
else:
|
|
protocol = 'http'
|
|
self.baseuri = '%s://%s:%s/' % (protocol, interface or socket.gethostname(), port)
|
|
self.verbose = False
|
|
|
|
def _get_dburi(self, uri):
|
|
uri = urlparse.urlsplit(uri)[2]
|
|
if uri[0] == '/':
|
|
uri = uri[1:]
|
|
dbname, uri = (uri.split('/', 1) + [None])[0:2]
|
|
return dbname, uri
|
|
|
|
def get_childs(self, uri):
|
|
res = []
|
|
dbname, dburi = self._get_dburi(uri)
|
|
if not dbname:
|
|
db = LocalService('db')
|
|
for dbname in db.list():
|
|
res.append(urlparse.urljoin(self.baseuri, dbname))
|
|
return res
|
|
pool = pooler.get_pool(dbname)
|
|
cursor = pooler.get_db(dbname).cursor()
|
|
collection_obj = pool.get('webdav.collection')
|
|
if uri[-1:] != '/':
|
|
uri += '/'
|
|
for child in collection_obj.get_childs(cursor, int(USER_ID), dburi,
|
|
cache=CACHE):
|
|
res.append(urlparse.urljoin(self.baseuri, uri + child))
|
|
cursor.close()
|
|
return res
|
|
|
|
def get_data(self, uri):
|
|
dbname, dburi = self._get_dburi(uri)
|
|
if not dbname or (self.exists(uri) and self.is_collection(uri)):
|
|
res = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">'
|
|
res += '<html>'
|
|
res += '<head>'
|
|
res += '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">'
|
|
res += '<title>%s - WebDAV - %s</title>' \
|
|
% (PACKAGE, dbname or 'root')
|
|
res += '</head>'
|
|
res += '<body>'
|
|
res += '<h2>Collection: %s</h2>' % (get_urifilename(uri) or '/')
|
|
res += '<ul>'
|
|
if dbname:
|
|
res += '<li><a href="%s">..</a></li>' \
|
|
% (quote_uri(get_uriparentpath(uri) or '/'))
|
|
childs = self.get_childs(uri)
|
|
childs.sort()
|
|
for child in childs:
|
|
res += '<li><a href="%s">%s</a></li>' \
|
|
% (quote_uri(child), get_urifilename(child))
|
|
res += '</ul>'
|
|
res += '<hr noshade>'
|
|
res += '<em>Powered by <a href="%s">%s</a> version %s</em>' \
|
|
% (quote_uri(WEBSITE), PACKAGE, VERSION)
|
|
res += '</body>'
|
|
res += '</html>'
|
|
return res
|
|
pool = pooler.get_pool(dbname)
|
|
cursor = pooler.get_db(dbname).cursor()
|
|
collection_obj = pool.get('webdav.collection')
|
|
try:
|
|
res = collection_obj.get_data(cursor, int(USER_ID), dburi,
|
|
cache=CACHE)
|
|
finally:
|
|
cursor.close()
|
|
return res
|
|
|
|
def put(self, uri, data, content_type=''):
|
|
dbname, dburi = self._get_dburi(uri)
|
|
if not dbname or not dburi:
|
|
raise DAV_Forbidden
|
|
pool = pooler.get_pool(dbname)
|
|
cursor = pooler.get_db(dbname).cursor()
|
|
collection_obj = pool.get('webdav.collection')
|
|
try:
|
|
try:
|
|
res = collection_obj.put(cursor, int(USER_ID), dburi, data,
|
|
content_type, cache=CACHE)
|
|
cursor.commit()
|
|
except:
|
|
cursor.rollback()
|
|
raise
|
|
finally:
|
|
cursor.close()
|
|
return res
|
|
|
|
def mkcol(self, uri):
|
|
dbname, dburi = self._get_dburi(uri)
|
|
if not dbname or not dburi:
|
|
raise DAV_Forbidden
|
|
pool = pooler.get_pool(dbname)
|
|
cursor = pooler.get_db(dbname).cursor()
|
|
collection_obj = pool.get('webdav.collection')
|
|
try:
|
|
try:
|
|
res = collection_obj.mkcol(cursor, int(USER_ID), dburi,
|
|
cache=CACHE)
|
|
cursor.commit()
|
|
except:
|
|
cursor.rollback()
|
|
raise
|
|
finally:
|
|
cursor.close()
|
|
return res
|
|
|
|
def _get_dav_resourcetype(self, uri):
|
|
dbname, dburi = self._get_dburi(uri)
|
|
if not dbname or not dburi:
|
|
return COLLECTION
|
|
pool = pooler.get_pool(dbname)
|
|
cursor = pooler.get_db(dbname).cursor()
|
|
collection_obj = pool.get('webdav.collection')
|
|
res = collection_obj.get_resourcetype(cursor, int(USER_ID), dburi,
|
|
cache=CACHE)
|
|
cursor.close()
|
|
return res
|
|
|
|
def _get_dav_displayname(self, uri):
|
|
raise DAV_Secret
|
|
|
|
def _get_dav_getcontentlength(self, uri):
|
|
dbname, dburi = self._get_dburi(uri)
|
|
if not dbname or not dburi:
|
|
return '0'
|
|
pool = pooler.get_pool(dbname)
|
|
cursor = pooler.get_db(dbname).cursor()
|
|
collection_obj = pool.get('webdav.collection')
|
|
res = collection_obj.get_contentlength(cursor, int(USER_ID), dburi,
|
|
cache=CACHE)
|
|
cursor.close()
|
|
return res
|
|
|
|
def _get_dav_getcontenttype(self, uri):
|
|
dbname, dburi = self._get_dburi(uri)
|
|
if not dbname or self.is_collection(uri):
|
|
return "text/html"
|
|
pool = pooler.get_pool(dbname)
|
|
cursor = pooler.get_db(dbname).cursor()
|
|
collection_obj = pool.get('webdav.collection')
|
|
res = collection_obj.get_contenttype(cursor, int(USER_ID), dburi,
|
|
cache=CACHE)
|
|
cursor.close()
|
|
return res
|
|
|
|
def get_creationdate(self, uri):
|
|
dbname, dburi = self._get_dburi(uri)
|
|
if not dbname or not dburi:
|
|
return time.time()
|
|
pool = pooler.get_pool(dbname)
|
|
cursor = pooler.get_db(dbname).cursor()
|
|
collection_obj = pool.get('webdav.collection')
|
|
res = collection_obj.get_creationdate(cursor, int(USER_ID), dburi,
|
|
cache=CACHE)
|
|
cursor.close()
|
|
return res
|
|
|
|
def get_lastmodified(self, uri):
|
|
dbname, dburi = self._get_dburi(uri)
|
|
if not dbname or not dburi:
|
|
return time.time()
|
|
pool = pooler.get_pool(dbname)
|
|
cursor = pooler.get_db(dbname).cursor()
|
|
collection_obj = pool.get('webdav.collection')
|
|
res = collection_obj.get_lastmodified(cursor, int(USER_ID), dburi,
|
|
cache=CACHE)
|
|
cursor.close()
|
|
return res
|
|
|
|
def rmcol(self, uri):
|
|
dbname, dburi = self._get_dburi(uri)
|
|
if not dbname or not dburi:
|
|
raise DAV_Forbidden
|
|
pool = pooler.get_pool(dbname)
|
|
cursor = pooler.get_db(dbname).cursor()
|
|
collection_obj = pool.get('webdav.collection')
|
|
try:
|
|
try:
|
|
res = collection_obj.rmcol(cursor, int(USER_ID), dburi,
|
|
cache=CACHE)
|
|
cursor.commit()
|
|
except:
|
|
cursor.rollback()
|
|
raise
|
|
finally:
|
|
cursor.close()
|
|
return res
|
|
|
|
def rm(self, uri):
|
|
dbname, dburi = self._get_dburi(uri)
|
|
if not dbname or not dburi:
|
|
raise DAV_Forbidden
|
|
pool = pooler.get_pool(dbname)
|
|
cursor = pooler.get_db(dbname).cursor()
|
|
collection_obj = pool.get('webdav.collection')
|
|
try:
|
|
try:
|
|
res = collection_obj.rm(cursor, int(USER_ID), dburi,
|
|
cache=CACHE)
|
|
cursor.commit()
|
|
except:
|
|
cursor.rollback()
|
|
raise
|
|
finally:
|
|
cursor.close()
|
|
return res
|
|
|
|
def exists(self, uri):
|
|
dbname, dburi = self._get_dburi(uri)
|
|
if not dbname or not dburi:
|
|
return 1
|
|
pool = pooler.get_pool(dbname)
|
|
cursor = pooler.get_db(dbname).cursor()
|
|
collection_obj = pool.get('webdav.collection')
|
|
res = collection_obj.exists(cursor, int(USER_ID), dburi, cache=CACHE)
|
|
cursor.close()
|
|
return res
|
|
|
|
def is_collection(self, uri):
|
|
if self._get_dav_resourcetype(uri) == COLLECTION:
|
|
return 1
|
|
return 0
|
|
|
|
def copyone(self, src, dst, overwrite):
|
|
return copyone(self, src, dst, overwrite)
|
|
|
|
def copytree(self, src, dst, overwrite):
|
|
return copytree(self, src, dst, overwrite)
|
|
|
|
def moveone(self, src, dst, overwrite):
|
|
return moveone(self, src, dst, overwrite)
|
|
|
|
def movetree(self, src, dst, overwrite):
|
|
return movetree(self, src, dst, overwrite)
|
|
|
|
def delone(self, uri):
|
|
return delone(self, uri)
|
|
|
|
def deltree(self, uri):
|
|
return deltree(self, uri)
|
|
|
|
def copy(self, src, dst):
|
|
content = self._get_dav_getcontenttype(src)
|
|
data = self.get_data(src)
|
|
self.put(dst, data, content)
|
|
return 201
|
|
|
|
def copycol(self, src, dst):
|
|
return self.mkcol(dst)
|
|
|
|
|
|
class WebDAVAuthRequestHandler(AuthServer.BufferedAuthRequestHandler,
|
|
WebDAVServer.DAVRequestHandler):
|
|
|
|
def get_userinfo(self, user, password, command=''):
|
|
global USER_ID
|
|
dbname = self.path.split('/', 2)[1]
|
|
if not dbname:
|
|
return 1
|
|
USER_ID = security.login(dbname, user, password, cache=False)
|
|
Cache.clean(dbname)
|
|
Cache.resets(database)
|
|
if int(USER_ID):
|
|
return 1
|
|
return 0
|
|
|
|
class SecureWebDAVAuthRequestHandler(WebDAVAuthRequestHandler):
|
|
|
|
def setup(self):
|
|
self.connection = SSLSocket(self.request)
|
|
self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
|
|
self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
|