Files
tryton/trytond/protocols/webdav.py
T

444 lines
14 KiB
Python
Raw Normal View History

#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
2009-02-12 18:46:43 +01:00
from trytond.protocols.sslsocket import SSLSocket
from trytond.config import CONFIG
from trytond.security import login
from trytond.version import PACKAGE, VERSION, WEBSITE
from trytond.tools.misc import Cache, LocalDict
from trytond.backend import Database
from trytond.pool import Pool
import threading
import SocketServer
2008-02-14 01:43:39 +01:00
import socket
2009-02-12 18:46:43 +01:00
import os
import BaseHTTPServer
import urlparse
2008-02-14 01:43:39 +01:00
import base64
import time
2008-02-14 01:43:39 +01:00
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
import urllib
2008-02-14 01:43:39 +01:00
# 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()
2008-02-14 01:43:39 +01:00
# 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
2008-02-14 01:43:39 +01:00
2008-07-18 20:02:30 +02:00
# Fix for unset _config in DAVRequestHandler
if DAV_VERSION == '0.8':
class DAV:
lockemulation = False
2008-07-23 23:14:37 +02:00
verbose = False
2008-07-18 20:02:30 +02:00
class _Config:
DAV = DAV()
WebDAVServer.DAVRequestHandler._config = _Config()
2009-02-12 18:46:43 +01:00
class BaseThreadedHTTPServer(SocketServer.ThreadingMixIn,
BaseHTTPServer.HTTPServer):
max_children = CONFIG['max_thread']
def server_bind(self):
self.socket.setsockopt(socket.SOL_SOCKET,
socket.SO_REUSEADDR, 1)
BaseHTTPServer.HTTPServer.server_bind(self)
class SecureThreadedHTTPServer(BaseThreadedHTTPServer):
def __init__(self, server_address, HandlerClass):
BaseThreadedHTTPServer.__init__(self, server_address, HandlerClass)
self.socket = SSLSocket(socket.socket(self.address_family,
self.socket_type))
self.server_bind()
self.server_activate()
class WebDAVServerThread(threading.Thread):
def __init__(self, interface, port, secure=False):
threading.Thread.__init__(self)
self.secure = secure
self.running = False
ipv6 = False
if socket.has_ipv6:
try:
socket.getaddrinfo(interface or None, port, socket.AF_INET6)
ipv6 = True
except:
pass
if secure:
handler_class = SecureWebDAVAuthRequestHandler
server_class = SecureThreadedHTTPServer
if ipv6:
server_class = SecureThreadedHTTPServer6
else:
handler_class = WebDAVAuthRequestHandler
server_class = BaseThreadedHTTPServer
if ipv6:
server_class = BaseThreadedHTTPServer6
handler_class.IFACE_CLASS = TrytonDAVInterface(interface, port, secure)
self.server = server_class((interface, port), handler_class)
def stop(self):
self.running = False
if os.name != 'nt':
if hasattr(socket, 'SHUT_RDWR'):
self.server.socket.shutdown(socket.SHUT_RDWR)
else:
self.server.socket.shutdown(2)
self.server.socket.close()
def run(self):
self.running = True
while self.running:
self.server.handle_request()
return True
class BaseThreadedHTTPServer6(BaseThreadedHTTPServer):
address_family = socket.AF_INET6
class SecureThreadedHTTPServer6(SecureThreadedHTTPServer):
address_family = socket.AF_INET6
2008-02-14 01:43:39 +01:00
class TrytonDAVInterface(iface.dav_interface):
2008-03-04 16:11:42 +01:00
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)
2008-07-18 20:02:30 +02:00
self.verbose = False
2008-02-14 01:43:39 +01:00
def _get_dburi(self, uri):
uri = urlparse.urlsplit(uri)[2]
if uri[0] == '/':
uri = uri[1:]
2008-02-14 01:43:39 +01:00
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:
2009-02-11 14:52:22 +01:00
database = Database().connect()
try:
try:
cursor = database.cursor()
lists = database.list(cursor)
except:
lists = []
finally:
cursor.close()
for dbname in lists:
2008-02-14 01:43:39 +01:00
res.append(urlparse.urljoin(self.baseuri, dbname))
return res
2009-02-11 14:52:22 +01:00
database = Database(dbname).connect()
cursor = database.cursor()
pool = Pool(dbname)
try:
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))
finally:
cursor.close()
2008-02-14 01:43:39 +01:00
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)):
2008-02-14 15:19:08 +01:00
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>'
2008-05-28 20:40:53 +02:00
res += '<h2>Collection: %s</h2>' % (get_urifilename(uri) or '/')
2008-02-14 15:19:08 +01:00
res += '<ul>'
if dbname:
res += '<li><a href="%s">..</a></li>' \
% (quote_uri(get_uriparentpath(uri) or '/'))
2008-02-16 15:54:18 +01:00
childs = self.get_childs(uri)
childs.sort()
for child in childs:
2008-02-14 15:19:08 +01:00
res += '<li><a href="%s">%s</a></li>' \
% (quote_uri(child), get_urifilename(child))
2008-02-14 15:19:08 +01:00
res += '</ul>'
res += '<hr noshade>'
res += '<em>Powered by <a href="%s">%s</a> version %s</em>' \
% (quote_uri(WEBSITE), PACKAGE, VERSION)
2008-02-14 15:19:08 +01:00
res += '</body>'
res += '</html>'
return res
2009-02-11 14:52:22 +01:00
pool = Pool(dbname)
database = Database(dbname).connect()
cursor = database.cursor()
2008-05-28 20:40:53 +02:00
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
2009-02-11 14:52:22 +01:00
pool = Pool(dbname)
database = Database(dbname).connect()
cursor = database.cursor()
2008-05-28 20:40:53 +02:00
collection_obj = pool.get('webdav.collection')
try:
try:
2008-05-28 20:40:53 +02:00
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
2009-02-11 14:52:22 +01:00
pool = Pool(dbname)
database = Database(dbname).connect()
cursor = database.cursor()
2008-05-28 20:40:53 +02:00
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
2008-02-14 01:43:39 +01:00
def _get_dav_resourcetype(self, uri):
dbname, dburi = self._get_dburi(uri)
if not dbname or not dburi:
return COLLECTION
2009-02-11 14:52:22 +01:00
pool = Pool(dbname)
database = Database(dbname).connect()
cursor = database.cursor()
2008-05-28 20:40:53 +02:00
collection_obj = pool.get('webdav.collection')
2009-02-11 14:52:22 +01:00
try:
res = collection_obj.get_resourcetype(cursor, int(USER_ID), dburi,
cache=CACHE)
finally:
cursor.close()
return res
2008-02-14 01:43:39 +01:00
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'
2009-02-11 14:52:22 +01:00
pool = Pool(dbname)
database = Database(dbname).connect()
cursor = database.cursor()
2008-05-28 20:40:53 +02:00
collection_obj = pool.get('webdav.collection')
2009-02-11 14:52:22 +01:00
try:
res = collection_obj.get_contentlength(cursor, int(USER_ID), dburi,
cache=CACHE)
finally:
cursor.close()
return res
2008-02-14 01:43:39 +01:00
def _get_dav_getcontenttype(self, uri):
2008-02-14 15:19:08 +01:00
dbname, dburi = self._get_dburi(uri)
if not dbname or self.is_collection(uri):
return "text/html"
2009-02-11 14:52:22 +01:00
pool = Pool(dbname)
database = Database(dbname).connect()
cursor = database.cursor()
2008-05-28 20:40:53 +02:00
collection_obj = pool.get('webdav.collection')
2009-02-11 14:52:22 +01:00
try:
res = collection_obj.get_contenttype(cursor, int(USER_ID), dburi,
cache=CACHE)
finally:
cursor.close()
return res
2008-02-14 01:43:39 +01:00
def get_creationdate(self, uri):
dbname, dburi = self._get_dburi(uri)
if not dbname or not dburi:
return time.time()
2009-02-11 14:52:22 +01:00
pool = Pool(dbname)
database = Database(dbname).connect()
cursor = database.cursor()
2008-05-28 20:40:53 +02:00
collection_obj = pool.get('webdav.collection')
2009-02-11 14:52:22 +01:00
try:
res = collection_obj.get_creationdate(cursor, int(USER_ID), dburi,
cache=CACHE)
finally:
cursor.close()
return res
def get_lastmodified(self, uri):
dbname, dburi = self._get_dburi(uri)
if not dbname or not dburi:
return time.time()
2009-02-11 14:52:22 +01:00
pool = Pool(dbname)
database = Database(dbname).connect()
cursor = database.cursor()
2008-05-28 20:40:53 +02:00
collection_obj = pool.get('webdav.collection')
2009-02-11 14:52:22 +01:00
try:
res = collection_obj.get_lastmodified(cursor, int(USER_ID), dburi,
cache=CACHE)
finally:
cursor.close()
return res
def rmcol(self, uri):
dbname, dburi = self._get_dburi(uri)
if not dbname or not dburi:
raise DAV_Forbidden
2009-02-11 14:52:22 +01:00
pool = Pool(dbname)
database = Database(dbname).connect()
cursor = database.cursor()
2008-05-28 20:40:53 +02:00
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
2009-02-11 14:52:22 +01:00
pool = Pool(dbname)
database = Database(dbname).connect()
cursor = database.cursor()
2008-05-28 20:40:53 +02:00
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
2008-02-14 01:43:39 +01:00
def exists(self, uri):
dbname, dburi = self._get_dburi(uri)
if not dbname or not dburi:
return 1
2009-02-11 14:52:22 +01:00
pool = Pool(dbname)
database = Database(dbname)
cursor = database.cursor()
2008-05-28 20:40:53 +02:00
collection_obj = pool.get('webdav.collection')
2009-02-11 14:52:22 +01:00
try:
res = collection_obj.exists(cursor, int(USER_ID), dburi, cache=CACHE)
finally:
cursor.close()
return res
2008-02-14 01:43:39 +01:00
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)
2008-02-14 01:43:39 +01:00
class WebDAVAuthRequestHandler(AuthServer.BufferedAuthRequestHandler,
WebDAVServer.DAVRequestHandler):
2008-05-27 15:22:47 +02:00
def get_userinfo(self, user, password, command=''):
2008-02-14 01:43:39 +01:00
global USER_ID
dbname = self.path.split('/', 2)[1]
if not dbname:
return 1
2009-02-12 18:46:43 +01:00
USER_ID = login(dbname, user, password, cache=False)
2008-04-24 17:20:41 +02:00
Cache.clean(dbname)
2009-02-11 14:52:22 +01:00
Cache.resets(dbname)
if int(USER_ID):
2008-02-14 01:43:39 +01:00
return 1
return 0
2008-03-04 16:11:42 +01:00
class SecureWebDAVAuthRequestHandler(WebDAVAuthRequestHandler):
def setup(self):
self.connection = SSLSocket(self.request)
2008-03-04 16:11:42 +01:00
self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)