109 lines
4.4 KiB
Python
109 lines
4.4 KiB
Python
# ------------------------------------------------------------------------------
|
|
import os, re, httplib, sys, stat
|
|
from StringIO import StringIO
|
|
from mimetypes import guess_type
|
|
from base64 import encodestring
|
|
from appy.shared.utils import copyData
|
|
|
|
# ------------------------------------------------------------------------------
|
|
urlRex = re.compile(r'http://([^:/]+)(:[0-9]+)?(/.+)?', re.I)
|
|
binaryRex = re.compile(r'[\000-\006\177-\277]')
|
|
|
|
# ------------------------------------------------------------------------------
|
|
class Resource:
|
|
'''Every instance of this class represents some web resource accessible
|
|
through WebDAV.'''
|
|
|
|
def __init__(self, url, username=None, password=None):
|
|
self.username = username
|
|
self.password = password
|
|
self.url = url
|
|
|
|
# Split the URL into its components
|
|
res = urlRex.match(url)
|
|
if res:
|
|
host, port, uri = res.group(1,2,3)
|
|
self.host = host
|
|
self.port = port and int(port[1:]) or 80
|
|
self.uri = uri or '/'
|
|
else: raise 'Wrong URL: %s' % str(url)
|
|
|
|
def __repr__(self):
|
|
port = ':' + str(self.port)
|
|
if self.port == 80: port = ''
|
|
return '<Dav resource at %s%s/%s>' % (self.url, port, self.uri)
|
|
|
|
def updateHeaders(self, headers):
|
|
# Add credentials if present
|
|
if not (self.username and self.password): return
|
|
if headers.has_key('Authorization'): return
|
|
credentials = '%s:%s' % (self.username,self.password)
|
|
credentials = credentials.replace('\012','')
|
|
headers['Authorization'] = "Basic %s" % encodestring(credentials)
|
|
headers['User-Agent'] = 'WebDAV.client'
|
|
headers['Host'] = self.host
|
|
headers['Connection'] = 'close'
|
|
headers['Accept'] = '*/*'
|
|
return headers
|
|
|
|
def sendRequest(self, method, uri, body=None, headers={}, bodyType=None):
|
|
'''Sends a HTTP request with p_method, for p_uri.'''
|
|
conn = httplib.HTTP()
|
|
conn.connect(self.host, self.port)
|
|
conn.putrequest(method, uri)
|
|
# Add HTTP headers
|
|
self.updateHeaders(headers)
|
|
for n, v in headers.items(): conn.putheader(n, v)
|
|
conn.endheaders()
|
|
if body: copyData(body, conn, 'send', type=bodyType)
|
|
ver, code, msg = conn.getreply()
|
|
data = conn.getfile().read()
|
|
conn.close()
|
|
return data
|
|
|
|
def mkdir(self, name):
|
|
'''Creates a folder named p_name in this resource.'''
|
|
folderUri = self.uri + '/' + name
|
|
#body = '<d:propertyupdate xmlns:d="DAV:"><d:set><d:prop>' \
|
|
# '<d:displayname>%s</d:displayname></d:prop></d:set>' \
|
|
# '</d:propertyupdate>' % name
|
|
return self.sendRequest('MKCOL', folderUri)
|
|
|
|
def delete(self, name):
|
|
'''Deletes a file or a folder (and all contained files if any) named
|
|
p_name within this resource.'''
|
|
toDeleteUri = self.uri + '/' + name
|
|
return self.sendRequest('DELETE', toDeleteUri)
|
|
|
|
def add(self, content, type='fileName', name=''):
|
|
'''Adds a file in this resource. p_type can be:
|
|
- "fileName" In this case, p_content is the path to a file on disk
|
|
and p_name is ignored;
|
|
- "zope" In this case, p_content is an instance of
|
|
OFS.Image.File and the name of the file is given in
|
|
p_name.
|
|
'''
|
|
if type == 'fileName':
|
|
# p_content is the name of a file on disk
|
|
size = os.stat(content)[stat.ST_SIZE]
|
|
body = file(content, 'rb')
|
|
name = os.path.basename(content)
|
|
fileType, encoding = guess_type(content)
|
|
bodyType = 'file'
|
|
elif type == 'zope':
|
|
# p_content is a "Zope" file, ie a OFS.Image.File instance
|
|
# p_name is given
|
|
fileType = content.content_type
|
|
encoding = None
|
|
size = content.size
|
|
body = content
|
|
bodyType = 'zope'
|
|
fileUri = self.uri + '/' + name
|
|
headers = {'Content-Length': str(size)}
|
|
if fileType: headers['Content-Type'] = fileType
|
|
if encoding: headers['Content-Encoding'] = encoding
|
|
res = self.sendRequest('PUT', fileUri, body, headers, bodyType=bodyType)
|
|
# Close the file when relevant
|
|
if type =='fileName': body.close()
|
|
# ------------------------------------------------------------------------------
|