def mkdir(self, remote_path): try: directory_urn = Urn(remote_path, directory=True) if not self.check(directory_urn.parent()): raise RemoteParentNotFound(directory_urn.path()) url = { 'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': directory_urn.quote() } options = { 'URL': "{hostname}{root}{path}".format(**url), 'CUSTOMREQUEST': Client.requests['mkdir'], 'HTTPHEADER': self.get_header('mkdir') } request = self.Request(options=options) request.perform() request.close() except pycurl.error: raise NotConnection(self.webdav.hostname)
def upload_from(self, buff, remote_path): try: urn = Urn(remote_path) if urn.is_dir(): raise OptionNotValid(name="remote_path", value=remote_path) if not self.check(urn.parent()): raise RemoteParentNotFound(urn.path()) url = { 'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': urn.quote() } options = { 'URL': "{hostname}{root}{path}".format(**url), 'HTTPHEADER': self.get_header('upload_from'), 'UPLOAD': 1, 'READFUNCTION': buff.read, } request = self.Request(options=options) request.perform() code = request.getinfo(pycurl.HTTP_CODE) if code == "507": raise NotEnoughSpace() request.close() except pycurl.error: raise NotConnection(self.webdav.hostname)
def download_to(self, buff, remote_path): try: urn = Urn(remote_path) if self.is_dir(urn.path()): raise OptionNotValid(name="remote_path", value=remote_path) if not self.check(urn.path()): raise RemoteResourceNotFound(urn.path()) url = { 'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': urn.quote() } options = { 'URL': "{hostname}{root}{path}".format(**url), 'WRITEFUNCTION': buff.write, 'HTTPHEADER': self.get_header('download_to'), 'NOBODY': 0 } request = self.Request(options=options) request.perform() request.close() except pycurl.error: raise NotConnection(self.webdav.hostname)
def check(self, remote_path=root): try: urn = Urn(remote_path) response = BytesIO() url = { 'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': urn.quote() } options = { 'URL': "{hostname}{root}{path}".format(**url), 'CUSTOMREQUEST': Client.requests['check'], 'HTTPHEADER': self.get_header('check'), 'WRITEDATA': response, 'NOBODY': 1 } request = self.Request(options=options) request.perform() code = request.getinfo(pycurl.HTTP_CODE) request.close() if int(code) == 200: return True return False except pycurl.error: raise NotConnection(self.webdav.hostname)
def upload_file(self, remote_path, local_path, progress=None): """Uploads file to remote path on WebDAV server. File should be 2Gb or less. More information you can find by link http://webdav.org/specs/rfc4918.html#METHOD_PUT :param remote_path: the path to uploading file on WebDAV server. :param local_path: the path to local file for uploading. :param progress: Progress function. Not supported now. """ if not os.path.exists(local_path): raise LocalResourceNotFound(local_path) urn = Urn(remote_path) if urn.is_dir(): raise OptionNotValid(name='remote_path', value=remote_path) if os.path.isdir(local_path): raise OptionNotValid(name='local_path', value=local_path) if not self.check(urn.parent()): raise RemoteParentNotFound(urn.path()) with open(local_path, 'rb') as local_file: file_size = os.path.getsize(local_path) if file_size > self.large_size: raise ResourceTooBig(path=local_path, size=file_size, max_size=self.large_size) self.execute_request(action='upload', path=urn.quote(), data=local_file)
def clean(self, remote_path, matrix_params=None, query_params=None): try: urn = Urn(remote_path, matrix_params=matrix_params, query_params=query_params) url = { 'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': urn.quote() } options = { 'URL': "{hostname}{root}{path}".format(**url), 'CUSTOMREQUEST': Client.requests['clean'], 'HTTPHEADER': self.get_header('clean') } request = self.Request(options=options) request.perform() request.close() except pycurl.error: raise NotConnection(self.webdav.hostname)
def download_file(self, remote_path, local_path, progress=None): """Downloads file from WebDAV server and save it locally. More information you can find by link http://webdav.org/specs/rfc4918.html#rfc.section.9.4 :param remote_path: the path to remote file for downloading. :param local_path: the path to save file locally. :param progress: progress function. Not supported now. """ urn = Urn(remote_path) if self.is_dir(urn.path()): raise OptionNotValid(name='remote_path', value=remote_path) if os.path.isdir(local_path): raise OptionNotValid(name='local_path', value=local_path) if os.path.sep in local_path: os.makedirs(local_path.rsplit(os.path.sep, 1)[0], exist_ok=True) if not self.check(urn.path()): raise RemoteResourceNotFound(urn.path()) with open(local_path, 'wb') as local_file: response = self.execute_request('download', urn.quote()) for block in response.iter_content(1024): local_file.write(block)
def get_property(self, remote_path, option, matrix_params=None, query_params=None): def parse(response, option): response_str = response.getvalue() tree = etree.fromstring(response_str) xpath = "{xpath_prefix}{xpath_exp}".format( xpath_prefix=".//", xpath_exp=option['name']) return tree.findtext(xpath) def data(option): root = etree.Element("propfind", xmlns="DAV:") prop = etree.SubElement(root, "prop") etree.SubElement(prop, option.get('name', ""), xmlns=option.get('namespace', "")) tree = etree.ElementTree(root) buff = BytesIO() tree.write(buff) return buff.getvalue() try: urn = Urn(remote_path, matrix_params=matrix_params, query_params=query_params) if not self.check(urn.path()): raise RemoteResourceNotFound(urn.path()) response = BytesIO() url = { 'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': urn.quote() } options = { 'URL': "{hostname}{root}{path}".format(**url), 'CUSTOMREQUEST': Client.requests['get_metadata'], 'HTTPHEADER': self.get_header('get_metadata'), 'POSTFIELDS': data(option), 'WRITEDATA': response, 'NOBODY': 0 } request = self.Request(options=options) request.perform() request.close() return parse(response, option) except pycurl.error: raise NotConnection(self.webdav.hostname)
def list(self, remote_path="/"): def parse(response): try: response_str = response.getvalue() print(response_str) tree = etree.fromstring(response_str) hrees = [ unquote(hree.text) for hree in tree.findall(".//{DAV:}href") ] etags = [ unquote(etag.text) for etag in tree.findall(".//{DAV:}getetag") ] i = 0 ret = [] for hree in hrees: ret.append(MyUrn(hree, etags[i])) i = i + 1 return ret except etree.XMLSyntaxError: return list() try: directory_urn = Urn(remote_path, directory=True) if directory_urn.path() != wc.Client.root: if not self.client.check(directory_urn.path()): raise RemoteResourceNotFound(directory_urn.path()) response = BytesIO() url = { 'hostname': self.client.webdav.hostname, 'root': self.client.webdav.root, 'path': directory_urn.quote() } options = { 'URL': "{hostname}{root}{path}".format(**url), 'CUSTOMREQUEST': wc.Client.requests['list'], 'HTTPHEADER': self.client.get_header('list'), 'WRITEDATA': response, 'NOBODY': 0 } request = self.client.Request(options=options) request.perform() request.close() urns = parse(response) #path = "{root}{path}".format(root=self.client.webdav.root, path=directory_urn.path()) #return [urn.filename() for urn in urns if urn.path() != path and urn.path() != path[:-1]] return urns except pycurl.error: raise NotConnection(self.client.webdav.hostname)
def clean(self, remote_path): """Cleans (Deletes) a remote resource on WebDAV server. The name of method is not changed for back compatibility with original library. More information you can find by link http://webdav.org/specs/rfc4918.html#METHOD_DELETE :param remote_path: the remote resource whisch will be deleted. """ urn = Urn(remote_path) self.execute_request(action='clean', path=urn.quote())
def check(self, remote_path=root): def parse(response, path): try: response_str = response.getvalue() tree = etree.fromstring(response_str) resps = tree.findall("{DAV:}response") for resp in resps: href = resp.findtext("{DAV:}href") urn = unquote(href) if path.endswith(Urn.separate): if path == urn or path[:-1] == urn: return True else: if path == urn: return True return False except etree.XMLSyntaxError: raise MethodNotSupported(name="check", server=self.webdav.hostname) try: urn = Urn(remote_path) parent_urn = Urn(urn.parent()) response = BytesIO() url = { 'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': parent_urn.quote() } options = { 'URL': "{hostname}{root}{path}".format(**url), 'CUSTOMREQUEST': Client.requests['info'], 'HTTPHEADER': self.get_header('info'), 'WRITEDATA': response, 'NOBODY': 0 } request = self.Request(options=options) request.perform() request.close() path = "{root}{path}".format(root=self.webdav.root, path=urn.path()) return parse(response, path) except pycurl.error: raise NotConnection(self.webdav.hostname)
def upload_file(self, remote_path, local_path, progress=None): try: if not os.path.exists(local_path): raise LocalResourceNotFound(local_path) urn = Urn(remote_path) if urn.is_dir(): raise OptionNotValid(name="remote_path", value=remote_path) if os.path.isdir(local_path): raise OptionNotValid(name="local_path", value=local_path) if not os.path.exists(local_path): raise LocalResourceNotFound(local_path) if not self.check(urn.parent()): raise RemoteParentNotFound(urn.path()) with open(local_path, "rb") as local_file: url = { 'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': urn.quote() } options = { 'URL': "{hostname}{root}{path}".format(**url), 'HTTPHEADER': self.get_header('upload_file'), 'UPLOAD': 1, 'READFUNCTION': local_file.read, 'NOPROGRESS': 0 if progress else 1 } if progress: options["PROGRESSFUNCTION"] = progress file_size = os.path.getsize(local_path) if file_size > self.large_size: options['INFILESIZE_LARGE'] = file_size else: options['INFILESIZE'] = file_size request = self.Request(options=options) request.perform() code = request.getinfo(pycurl.HTTP_CODE) if code == "507": raise NotEnoughSpace() request.close() except pycurl.error: raise NotConnection(self.webdav.hostname)
def list(self, remote_path=root, matrix_params=None, query_params=None): def parse(response): try: response_str = response.getvalue() tree = etree.fromstring(response_str) hrees = [ unquote(hree.text) for hree in tree.findall(".//{DAV:}href") ] return [Urn(hree) for hree in hrees] except etree.XMLSyntaxError: return list() try: directory_urn = Urn(remote_path, directory=True, matrix_params=matrix_params, query_params=query_params) if directory_urn.path() != Client.root: if not self.check(directory_urn.path()): raise RemoteResourceNotFound(directory_urn.path()) response = BytesIO() url = { 'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': directory_urn.quote() } options = { 'URL': "{hostname}{root}{path}".format(**url), 'CUSTOMREQUEST': Client.requests['list'], 'HTTPHEADER': self.get_header('list'), 'WRITEDATA': response, 'NOBODY': 0 } request = self.Request(options=options) request.perform() request.close() urns = parse(response) path = "{root}{path}".format(root=self.webdav.root, path=directory_urn.path()) return [ urn.filename() for urn in urns if urn.path() != path and urn.path() != path[:-1] ] except pycurl.error: raise NotConnection(self.webdav.hostname)
def set_property(self, remote_path, option, matrix_params=None, query_params=None): def data(option): root_node = etree.Element("propertyupdate", xmlns="DAV:") root_node.set('xmlns:u', option.get('namespace', "")) set_node = etree.SubElement(root_node, "set") prop_node = etree.SubElement(set_node, "prop") opt_node = etree.SubElement( prop_node, "{namespace}:{name}".format(namespace='u', name=option['name'])) opt_node.text = option.get('value', "") tree = etree.ElementTree(root_node) buff = BytesIO() tree.write(buff) return buff.getvalue() try: urn = Urn(remote_path, matrix_params=matrix_params, query_params=query_params) if not self.check(urn.path()): raise RemoteResourceNotFound(urn.path()) url = { 'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': urn.quote() } options = { 'URL': "{hostname}{root}{path}".format(**url), 'CUSTOMREQUEST': Client.requests['set_metadata'], 'HTTPHEADER': self.get_header('get_metadata'), 'POSTFIELDS': data(option) } request = self.Request(options=options) request.perform() request.close() except pycurl.error: raise NotConnection(self.webdav.hostname)
def upload_to(self, buff, remote_path): """Uploads file from buffer to remote path on WebDAV server. More information you can find by link http://webdav.org/specs/rfc4918.html#METHOD_PUT :param buff: the buffer with content for file. :param remote_path: the path to save file remotely on WebDAV server. """ urn = Urn(remote_path) if urn.is_dir(): raise OptionNotValid(name='remote_path', value=remote_path) if not self.check(urn.parent()): raise RemoteParentNotFound(urn.path()) self.execute_request(action='upload', path=urn.quote(), data=buff)
def download_from(self, buff, remote_path): """Downloads file from WebDAV and writes it in buffer. :param buff: buffer object for writing of downloaded file content. :param remote_path: path to file on WebDAV server. """ urn = Urn(remote_path) if self.is_dir(urn.path()): raise OptionNotValid(name='remote_path', value=remote_path) if not self.check(urn.path()): raise RemoteResourceNotFound(urn.path()) response = self.execute_request(action='download', path=urn.quote()) buff.write(response.content)
def is_dir(self, remote_path): """Checks is the remote resource directory. More information you can find by link http://webdav.org/specs/rfc4918.html#METHOD_PROPFIND :param remote_path: the path to remote resource. :return: True in case the remote resource is directory and False otherwise. """ urn = Urn(remote_path) parent_urn = Urn(urn.parent()) if not self.check(urn.path()) and not self.check( Urn(remote_path, directory=True).path()): raise RemoteResourceNotFound(remote_path) response = self.execute_request(action='info', path=parent_urn.quote()) path = self.get_full_path(urn) return WebDavXmlUtils.parse_is_dir_response( content=response.content, path=path, hostname=self.webdav.hostname)
def download_file(self, remote_path, local_path, progress=None, matrix_params=None, query_params=None): try: urn = Urn(remote_path, matrix_params=matrix_params, query_params=query_params) if self.is_dir(urn.path()): raise OptionNotValid(name="remote_path", value=remote_path) if os.path.isdir(local_path): raise OptionNotValid(name="local_path", value=local_path) if not self.check(urn.path()): raise RemoteResourceNotFound(urn.path()) with open(local_path, 'wb') as local_file: url = { 'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': urn.quote() } options = { 'URL': "{hostname}{root}{path}".format(**url), 'HTTPHEADER': self.get_header('download_file'), 'WRITEDATA': local_file, 'NOPROGRESS': 0 if progress else 1, 'NOBODY': 0 } if progress: options["PROGRESSFUNCTION"] = progress request = self.Request(options=options) request.perform() request.close() except pycurl.error: raise NotConnection(self.webdav.hostname)
def check(self, remote_path=root): """Checks an existence of remote resource on WebDAV server by remote path. More information you can find by link http://webdav.org/specs/rfc4918.html#rfc.section.9.4 :param remote_path: (optional) path to resource on WebDAV server. Defaults is root directory of WebDAV. :return: True if resource is exist or False otherwise """ urn = Urn(remote_path) try: response = self.execute_request(action='check', path=urn.quote()) except ResponseErrorCode: return False if int(response.status_code) == 200: return True return False
def set_property_batch(self, remote_path, option): """Sets batch metadata properties of remote resource on WebDAV server in batch. More information you can find by link http://webdav.org/specs/rfc4918.html#METHOD_PROPPATCH :param remote_path: the path to remote resource. :param option: the property attributes as list of dictionaries with following keys: `namespace`: (optional) the namespace for XML property which will be set, `name`: the name of property which will be set, `value`: (optional) the value of property which will be set. Defaults is empty string. """ urn = Urn(remote_path) if not self.check(urn.path()): raise RemoteResourceNotFound(urn.path()) data = WebDavXmlUtils.create_set_property_batch_request_content(option) self.execute_request(action='set_property', path=urn.quote(), data=data)
def copy(self, remote_path_from, remote_path_to): """Copies resource from one place to another on WebDAV server. More information you can find by link http://webdav.org/specs/rfc4918.html#METHOD_COPY :param remote_path_from: the path to resource which will be copied, :param remote_path_to: the path where resource will be copied. """ urn_from = Urn(remote_path_from) if not self.check(urn_from.path()): raise RemoteResourceNotFound(urn_from.path()) urn_to = Urn(remote_path_to) if not self.check(urn_to.parent()): raise RemoteParentNotFound(urn_to.path()) header_destination = f'Destination: {self.get_full_path(urn_to)}' self.execute_request(action='copy', path=urn_from.quote(), headers_ext=[header_destination])
def copy(self, remote_path_from, remote_path_to): def header(remote_path_to): path = Urn(remote_path_to).path() destination = "{root}{path}".format(root=self.webdav.root, path=path) header_item = "Destination: {destination}".format( destination=destination) header = self.get_header('copy') header.append(header_item) return header try: urn_from = Urn(remote_path_from) if not self.check(urn_from.path()): raise RemoteResourceNotFound(urn_from.path()) urn_to = Urn(remote_path_to) if not self.check(urn_to.parent()): raise RemoteParentNotFound(urn_to.path()) url = { 'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': urn_from.quote() } options = { 'URL': "{hostname}{root}{path}".format(**url), 'CUSTOMREQUEST': Client.requests['copy'], 'HTTPHEADER': header(remote_path_to) } request = self.Request(options=options) request.perform() request.close() except pycurl.error: raise NotConnection(self.webdav.hostname)
def mkdir(self, remote_path): """Makes new directory on WebDAV server. More information you can find by link http://webdav.org/specs/rfc4918.html#METHOD_MKCOL :param remote_path: path to directory :return: True if request executed with code 200 or 201 and False otherwise. """ directory_urn = Urn(remote_path, directory=True) try: response = self.execute_request(action='mkdir', path=directory_urn.quote()) return response.status_code in (200, 201) except ResponseErrorCode as e: if e.code == 405: return True raise
def info(self, remote_path): """Gets information about resource on WebDAV. More information you can find by link http://webdav.org/specs/rfc4918.html#METHOD_PROPFIND :param remote_path: the path to remote resource. :return: a dictionary of information attributes and them values with following keys: `created`: date of resource creation, `name`: name of resource, `size`: size of resource, `modified`: date of resource modification. """ urn = Urn(remote_path) if not self.check(urn.path()) and not self.check( Urn(remote_path, directory=True).path()): raise RemoteResourceNotFound(remote_path) response = self.execute_request(action='info', path=urn.quote()) path = self.get_full_path(urn) return WebDavXmlUtils.parse_info_response( content=response.content, path=path, hostname=self.webdav.hostname)
def get_property(self, remote_path, option): """Gets metadata property of remote resource on WebDAV server. More information you can find by link http://webdav.org/specs/rfc4918.html#METHOD_PROPFIND :param remote_path: the path to remote resource. :param option: the property attribute as dictionary with following keys: `namespace`: (optional) the namespace for XML property which will be set, `name`: the name of property which will be set. :return: the value of property or None if property is not found. """ urn = Urn(remote_path) if not self.check(urn.path()): raise RemoteResourceNotFound(urn.path()) data = WebDavXmlUtils.create_get_property_request_content(option) response = self.execute_request(action='get_property', path=urn.quote(), data=data) return WebDavXmlUtils.parse_get_property_response( response.content, option['name'])
def list(self, remote_path=root): """Returns list of nested files and directories for remote WebDAV directory by path. More information you can find by link http://webdav.org/specs/rfc4918.html#METHOD_PROPFIND :param remote_path: path to remote directory. :return: list of nested file or directory names. """ directory_urn = Urn(remote_path, directory=True) if directory_urn.path() != Client.root: if not self.check(directory_urn.path()): raise RemoteResourceNotFound(directory_urn.path()) response = self.execute_request(action='list', path=directory_urn.quote()) urns = WebDavXmlUtils.parse_get_list_response(response.content) path = Urn.normalize_path(self.get_full_path(directory_urn)) return [ urn.filename() for urn in urns if Urn.compare_path(path, urn.path()) is False ]
def unpublish(self, remote_path): def data(for_server): root = etree.Element("propertyupdate", xmlns="DAV:") remove = etree.SubElement(root, "remove") prop = etree.SubElement(remove, "prop") xmlns = Client.meta_xmlns.get(for_server, "") etree.SubElement(prop, "public_url", xmlns=xmlns) tree = etree.ElementTree(root) buff = BytesIO() tree.write(buff) return buff.getvalue() try: urn = Urn(remote_path) if not self.check(urn.path()): raise RemoteResourceNotFound(urn.path()) url = { 'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': urn.quote() } options = { 'URL': "{hostname}{root}{path}".format(**url), 'CUSTOMREQUEST': Client.requests['unpublish'], 'HTTPHEADER': self.get_header('unpublish'), 'POSTFIELDS': data(for_server=self.webdav.hostname) } request = self.Request(options=options) request.perform() request.close() except pycurl.error: raise NotConnection(self.webdav.hostname)
def move(self, remote_path_from, remote_path_to, overwrite=False): """Moves resource from one place to another on WebDAV server. More information you can find by link http://webdav.org/specs/rfc4918.html#METHOD_MOVE :param remote_path_from: the path to resource which will be moved, :param remote_path_to: the path where resource will be moved. :param overwrite: (optional) the flag, overwrite file if it exists. Defaults is False """ urn_from = Urn(remote_path_from) if not self.check(urn_from.path()): raise RemoteResourceNotFound(urn_from.path()) urn_to = Urn(remote_path_to) if not self.check(urn_to.parent()): raise RemoteParentNotFound(urn_to.path()) header_destination = f'Destination: {self.get_full_path(urn_to)}' header_overwrite = f'Overwrite: {"T" if overwrite else "F"}' self.execute_request( action='move', path=urn_from.quote(), headers_ext=[header_destination, header_overwrite])
def list(self, remote_path=root): def parse(response): try: response_str = response.getvalue() tree = etree.fromstring(response_str) hrees = [unquote(hree.text) for hree in tree.findall(".//{DAV:}href")] return [Urn(hree) for hree in hrees] except etree.XMLSyntaxError: return list() try: directory_urn = Urn(remote_path, directory=True) if directory_urn.path() != Client.root: if not self.check(directory_urn.path()): raise RemoteResourceNotFound(directory_urn.path()) response = BytesIO() url = {'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': directory_urn.quote()} options = { 'URL': "{hostname}{root}{path}".format(**url), 'CUSTOMREQUEST': Client.requests['list'], 'HTTPHEADER': self.get_header('list'), 'WRITEDATA': response, 'NOBODY': 0 } request = self.Request(options=options) request.perform() request.close() urns = parse(response) path = "{root}{path}".format(root=self.webdav.root, path=directory_urn.path()) return [urn.filename() for urn in urns if urn.path() != path and urn.path() != path[:-1]] except pycurl.error: raise NotConnection(self.webdav.hostname)
def check(self, remote_path=root): def parse(response, path): try: response_str = response.getvalue() tree = etree.fromstring(response_str) resps = tree.findall("{DAV:}response") for resp in resps: href = resp.findtext("{DAV:}href") urn = unquote(href) if path.endswith(Urn.separate): if path == urn or path[:-1] == urn: return True else: if path == urn: return True return False except etree.XMLSyntaxError: raise MethodNotSupported(name="check", server=self.webdav.hostname) try: urn = Urn(remote_path) parent_urn = Urn(urn.parent()) response = BytesIO() url = {'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': parent_urn.quote()} options = { 'URL': "{hostname}{root}{path}".format(**url), 'CUSTOMREQUEST': Client.requests['info'], 'HTTPHEADER': self.get_header('info'), 'WRITEDATA': response, 'NOBODY': 0 } request = self.Request(options=options) request.perform() request.close() path = "{root}{path}".format(root=self.webdav.root, path=urn.path()) return parse(response, path) except pycurl.error: raise NotConnection(self.webdav.hostname)
def mkdir(self, remote_path): try: directory_urn = Urn(remote_path, directory=True) if not self.check(directory_urn.parent()): raise RemoteParentNotFound(directory_urn.path()) url = {'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': directory_urn.quote()} options = { 'URL': "{hostname}{root}{path}".format(**url), 'CUSTOMREQUEST': Client.requests['mkdir'], 'HTTPHEADER': self.get_header('mkdir') } request = self.Request(options=options) request.perform() request.close() except pycurl.error: raise NotConnection(self.webdav.hostname)
def download_to(self, buff, remote_path): try: urn = Urn(remote_path) if self.is_dir(urn.path()): raise OptionNotValid(name="remote_path", value=remote_path) if not self.check(urn.path()): raise RemoteResourceNotFound(urn.path()) url = {'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': urn.quote()} options = { 'URL': "{hostname}{root}{path}".format(**url), 'WRITEFUNCTION': buff.write, 'HTTPHEADER': self.get_header('download_to'), 'NOBODY': 0 } request = self.Request(options=options) request.perform() request.close() except pycurl.error: raise NotConnection(self.webdav.hostname)
def download_file(self, remote_path, local_path, progress=None): try: urn = Urn(remote_path) if self.is_dir(urn.path()): raise OptionNotValid(name="remote_path", value=remote_path) if os.path.isdir(local_path): raise OptionNotValid(name="local_path", value=local_path) if not self.check(urn.path()): raise RemoteResourceNotFound(urn.path()) with open(local_path, 'wb') as local_file: url = {'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': urn.quote()} options = { 'URL': "{hostname}{root}{path}".format(**url), 'HTTPHEADER': self.get_header('download_file'), 'WRITEDATA': local_file, 'NOPROGRESS': 0 if progress else 1, 'NOBODY': 0 } if progress: options["PROGRESSFUNCTION"] = progress request = self.Request(options=options) request.perform() request.close() except pycurl.error: raise NotConnection(self.webdav.hostname)
def upload_from(self, buff, remote_path): try: urn = Urn(remote_path) if urn.is_dir(): raise OptionNotValid(name="remote_path", value=remote_path) if not self.check(urn.parent()): raise RemoteParentNotFound(urn.path()) url = {'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': urn.quote()} options = { 'URL': "{hostname}{root}{path}".format(**url), 'HTTPHEADER': self.get_header('upload_from'), 'UPLOAD': 1, 'READFUNCTION': buff.read, } request = self.Request(options=options) request.perform() code = request.getinfo(pycurl.HTTP_CODE) if code == "507": raise NotEnoughSpace() request.close() except pycurl.error: raise NotConnection(self.webdav.hostname)
def is_dir(self, remote_path): def parse(response, path): try: response_str = response.getvalue() tree = etree.fromstring(response_str) resps = tree.findall("{DAV:}response") for resp in resps: href = resp.findtext("{DAV:}href") urn = unquote(href) if path[-1] == Urn.separate: if not path == urn: continue else: path_with_sep = "{path}{sep}".format(path=path, sep=Urn.separate) if not path == urn and not path_with_sep == urn: continue type = resp.find(".//{DAV:}resourcetype") if type is None: raise MethodNotSupported(name="is_dir", server=self.webdav.hostname) dir_type = type.find("{DAV:}collection") return True if dir_type is not None else False raise RemoteResourceNotFound(path) except etree.XMLSyntaxError: raise MethodNotSupported(name="is_dir", server=self.webdav.hostname) try: urn = Urn(remote_path) parent_urn = Urn(urn.parent()) if not self.check(urn.path()) and not self.check(Urn(remote_path, directory=True).path()): raise RemoteResourceNotFound(remote_path) response = BytesIO() url = {'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': parent_urn.quote()} options = { 'URL': "{hostname}{root}{path}".format(**url), 'CUSTOMREQUEST': Client.requests['info'], 'HTTPHEADER': self.get_header('info'), 'WRITEDATA': response, 'NOBODY': 0 } request = self.Request(options=options) request.perform() request.close() path = "{root}{path}".format(root=self.webdav.root, path=urn.path()) return parse(response, path) except pycurl.error: raise NotConnection(self.webdav.hostname)
def check(self, remote_path=root): try: urn = Urn(remote_path) response = BytesIO() url = {'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': urn.quote()} options = { 'URL': "{hostname}{root}{path}".format(**url), 'CUSTOMREQUEST': Client.requests['check'], 'HTTPHEADER': self.get_header('check'), 'WRITEDATA': response, 'NOBODY': 1 } request = self.Request(options=options) request.perform() code = request.getinfo(pycurl.HTTP_CODE) request.close() if int(code) == 200: return True return False except pycurl.error: raise NotConnection(self.webdav.hostname)
def clean(self, remote_path): try: urn = Urn(remote_path) url = {'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': urn.quote()} options = { 'URL': "{hostname}{root}{path}".format(**url), 'CUSTOMREQUEST': Client.requests['clean'], 'HTTPHEADER': self.get_header('clean') } request = self.Request(options=options) request.perform() request.close() except pycurl.error: raise NotConnection(self.webdav.hostname)
def publish(self, remote_path): def parse(response): try: response_str = response.getvalue() tree = etree.fromstring(response_str) result = tree.xpath("//*[local-name() = 'public_url']") public_url = result[0] return public_url.text except IndexError: raise MethodNotSupported(name="publish", server=self.webdav.hostname) except etree.XMLSyntaxError: return "" def data(for_server): root_node = etree.Element("propertyupdate", xmlns="DAV:") set_node = etree.SubElement(root_node, "set") prop_node = etree.SubElement(set_node, "prop") xmlns = Client.meta_xmlns.get(for_server, "") public_url = etree.SubElement(prop_node, "public_url", xmlns=xmlns) public_url.text = "true" tree = etree.ElementTree(root_node) buff = BytesIO() tree.write(buff) return buff.getvalue() try: urn = Urn(remote_path) if not self.check(urn.path()): raise RemoteResourceNotFound(urn.path()) response = BytesIO() url = {'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': urn.quote()} options = { 'URL': "{hostname}{root}{path}".format(**url), 'CUSTOMREQUEST': Client.requests['publish'], 'HTTPHEADER': self.get_header('publish'), 'POSTFIELDS': data(for_server=self.webdav.hostname), 'WRITEDATA': response, 'NOBODY': 0 } request = self.Request(options=options) request.perform() request.close() return parse(response) except pycurl.error: raise NotConnection(self.webdav.hostname)
def unpublish(self, remote_path): def data(for_server): root = etree.Element("propertyupdate", xmlns="DAV:") remove = etree.SubElement(root, "remove") prop = etree.SubElement(remove, "prop") xmlns = Client.meta_xmlns.get(for_server, "") etree.SubElement(prop, "public_url", xmlns=xmlns) tree = etree.ElementTree(root) buff = BytesIO() tree.write(buff) return buff.getvalue() try: urn = Urn(remote_path) if not self.check(urn.path()): raise RemoteResourceNotFound(urn.path()) url = {'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': urn.quote()} options = { 'URL': "{hostname}{root}{path}".format(**url), 'CUSTOMREQUEST': Client.requests['unpublish'], 'HTTPHEADER': self.get_header('unpublish'), 'POSTFIELDS': data(for_server=self.webdav.hostname) } request = self.Request(options=options) request.perform() request.close() except pycurl.error: raise NotConnection(self.webdav.hostname)
def set_property(self, remote_path, option): def data(option): root_node = etree.Element("propertyupdate", xmlns="DAV:") root_node.set('xmlns:u', option.get('namespace', "")) set_node = etree.SubElement(root_node, "set") prop_node = etree.SubElement(set_node, "prop") opt_node = etree.SubElement(prop_node, "{namespace}:{name}".format(namespace='u', name=option['name'])) opt_node.text = option.get('value', "") tree = etree.ElementTree(root_node) buff = BytesIO() tree.write(buff) return buff.getvalue() try: urn = Urn(remote_path) if not self.check(urn.path()): raise RemoteResourceNotFound(urn.path()) url = {'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': urn.quote()} options = { 'URL': "{hostname}{root}{path}".format(**url), 'CUSTOMREQUEST': Client.requests['set_metadata'], 'HTTPHEADER': self.get_header('get_metadata'), 'POSTFIELDS': data(option) } request = self.Request(options=options) request.perform() request.close() except pycurl.error: raise NotConnection(self.webdav.hostname)
def get_property(self, remote_path, option): def parse(response, option): response_str = response.getvalue() tree = etree.fromstring(response_str) xpath = "{xpath_prefix}{xpath_exp}".format(xpath_prefix=".//", xpath_exp=option['name']) return tree.findtext(xpath) def data(option): root = etree.Element("propfind", xmlns="DAV:") prop = etree.SubElement(root, "prop") etree.SubElement(prop, option.get('name', ""), xmlns=option.get('namespace', "")) tree = etree.ElementTree(root) buff = BytesIO() tree.write(buff) return buff.getvalue() try: urn = Urn(remote_path) if not self.check(urn.path()): raise RemoteResourceNotFound(urn.path()) response = BytesIO() url = {'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': urn.quote()} options = { 'URL': "{hostname}{root}{path}".format(**url), 'CUSTOMREQUEST': Client.requests['get_metadata'], 'HTTPHEADER': self.get_header('get_metadata'), 'POSTFIELDS': data(option), 'WRITEDATA': response, 'NOBODY': 0 } request = self.Request(options=options) request.perform() request.close() return parse(response, option) except pycurl.error: raise NotConnection(self.webdav.hostname)
def info(self, remote_path): def parse(response, path): try: response_str = response.getvalue() tree = etree.fromstring(response_str) find_attributes = { 'created': ".//{DAV:}creationdate", 'name': ".//{DAV:}displayname", 'size': ".//{DAV:}getcontentlength", 'modified': ".//{DAV:}getlastmodified" } resps = tree.findall("{DAV:}response") for resp in resps: href = resp.findtext("{DAV:}href") urn = unquote(href) if path[-1] == Urn.separate: if not path == urn: continue else: path_with_sep = "{path}{sep}".format(path=path, sep=Urn.separate) if not path == urn and not path_with_sep == urn: continue info = dict() for (name, value) in find_attributes.items(): info[name] = resp.findtext(value) return info raise RemoteResourceNotFound(path) except etree.XMLSyntaxError: raise MethodNotSupported(name="info", server=self.webdav.hostname) try: urn = Urn(remote_path) response = BytesIO() if not self.check(urn.path()) and not self.check( Urn(remote_path, directory=True).path()): raise RemoteResourceNotFound(remote_path) url = { 'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': urn.quote() } options = { 'URL': "{hostname}{root}{path}".format(**url), 'CUSTOMREQUEST': Client.requests['info'], 'HTTPHEADER': self.get_header('info'), 'WRITEDATA': response, 'NOBODY': 0 } request = self.Request(options=options) request.perform() request.close() path = "{root}{path}".format(root=self.webdav.root, path=urn.path()) return parse(response, path) except pycurl.error: raise NotConnection(self.webdav.hostname)
def upload_file(self, remote_path, local_path, progress=None): try: if not os.path.exists(local_path): raise LocalResourceNotFound(local_path) urn = Urn(remote_path) if urn.is_dir(): raise OptionNotValid(name="remote_path", value=remote_path) if os.path.isdir(local_path): raise OptionNotValid(name="local_path", value=local_path) if not os.path.exists(local_path): raise LocalResourceNotFound(local_path) if not self.check(urn.parent()): raise RemoteParentNotFound(urn.path()) with open(local_path, "rb") as local_file: url = {'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': urn.quote()} options = { 'URL': "{hostname}{root}{path}".format(**url), 'HTTPHEADER': self.get_header('upload_file'), 'UPLOAD': 1, 'READFUNCTION': local_file.read, 'NOPROGRESS': 0 if progress else 1 } if progress: options["PROGRESSFUNCTION"] = progress file_size = os.path.getsize(local_path) if file_size > self.large_size: options['INFILESIZE_LARGE'] = file_size else: options['INFILESIZE'] = file_size request = self.Request(options=options) request.perform() code = request.getinfo(pycurl.HTTP_CODE) if code == "507": raise NotEnoughSpace() request.close() except pycurl.error: raise NotConnection(self.webdav.hostname)
def info(self, remote_path): def parse(response, path): try: response_str = response.getvalue() tree = etree.fromstring(response_str) find_attributes = { 'created': ".//{DAV:}creationdate", 'name': ".//{DAV:}displayname", 'size': ".//{DAV:}getcontentlength", 'modified': ".//{DAV:}getlastmodified" } resps = tree.findall("{DAV:}response") for resp in resps: href = resp.findtext("{DAV:}href") urn = unquote(href) if path[-1] == Urn.separate: if not path == urn: continue else: path_with_sep = "{path}{sep}".format(path=path, sep=Urn.separate) if not path == urn and not path_with_sep == urn: continue info = dict() for (name, value) in find_attributes.items(): info[name] = resp.findtext(value) return info raise RemoteResourceNotFound(path) except etree.XMLSyntaxError: raise MethodNotSupported(name="info", server=self.webdav.hostname) try: urn = Urn(remote_path) response = BytesIO() if not self.check(urn.path()) and not self.check(Urn(remote_path, directory=True).path()): raise RemoteResourceNotFound(remote_path) url = {'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': urn.quote()} options = { 'URL': "{hostname}{root}{path}".format(**url), 'CUSTOMREQUEST': Client.requests['info'], 'HTTPHEADER': self.get_header('info'), 'WRITEDATA': response, 'NOBODY': 0 } request = self.Request(options=options) request.perform() request.close() path = "{root}{path}".format(root=self.webdav.root, path=urn.path()) return parse(response, path) except pycurl.error: raise NotConnection(self.webdav.hostname)
def is_dir(self, remote_path): def parse(response, path): try: response_str = response.getvalue() tree = etree.fromstring(response_str) resps = tree.findall("{DAV:}response") for resp in resps: href = resp.findtext("{DAV:}href") urn = unquote(href) if path[-1] == Urn.separate: if not path == urn: continue else: path_with_sep = "{path}{sep}".format(path=path, sep=Urn.separate) if not path == urn and not path_with_sep == urn: continue type = resp.find(".//{DAV:}resourcetype") if type is None: raise MethodNotSupported(name="is_dir", server=self.webdav.hostname) dir_type = type.find("{DAV:}collection") return True if dir_type is not None else False raise RemoteResourceNotFound(path) except etree.XMLSyntaxError: raise MethodNotSupported(name="is_dir", server=self.webdav.hostname) try: urn = Urn(remote_path) parent_urn = Urn(urn.parent()) if not self.check(urn.path()) and not self.check( Urn(remote_path, directory=True).path()): raise RemoteResourceNotFound(remote_path) response = BytesIO() url = { 'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': parent_urn.quote() } options = { 'URL': "{hostname}{root}{path}".format(**url), 'CUSTOMREQUEST': Client.requests['info'], 'HTTPHEADER': self.get_header('info'), 'WRITEDATA': response, 'NOBODY': 0 } request = self.Request(options=options) request.perform() request.close() path = "{root}{path}".format(root=self.webdav.root, path=urn.path()) return parse(response, path) except pycurl.error: raise NotConnection(self.webdav.hostname)
def move(self, remote_path_from, remote_path_to): def header(remote_path_to): path = Urn(remote_path_to).path() destination = "{root}{path}".format(root=self.webdav.root, path=path) header_item = "Destination: {destination}".format(destination=destination) header = self.get_header('move') header.append(header_item) return header try: urn_from = Urn(remote_path_from) if not self.check(urn_from.path()): raise RemoteResourceNotFound(urn_from.path()) urn_to = Urn(remote_path_to) if not self.check(urn_to.parent()): raise RemoteParentNotFound(urn_to.path()) url = {'hostname': self.webdav.hostname, 'root': self.webdav.root, 'path': urn_from.quote()} options = { 'URL': "{hostname}{root}{path}".format(**url), 'CUSTOMREQUEST': Client.requests['move'], 'HTTPHEADER': header(remote_path_to) } request = self.Request(options=options) request.perform() request.close() except pycurl.error: raise NotConnection(self.webdav.hostname)