Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
def apply_modify_prop(el, href, resource, properties):
"""Apply property set/remove operations.
:param el: set element to apply.
:param href: Resource href
:param resource: Resource to apply property modifications on
:param properties: Known properties
:yield: PropStatus objects
"""
if el.tag not in ('{DAV:}set', '{DAV:}remove'):
# callers should check tag
raise AssertionError
try:
[requested] = el
except IndexError:
raise BadRequestError(
'Received more than one element in {DAV:}set element.')
if requested.tag != '{DAV:}prop':
raise BadRequestError('Expected prop tag, got ' + requested.tag)
for propel in requested:
try:
handler = properties[propel.tag]
except KeyError:
logging.warning(
'client attempted to modify unknown property %r on %r',
propel.tag, href)
yield PropStatus('404 Not Found', None, ET.Element(propel.tag))
else:
if el.tag == '{DAV:}remove':
newval = None
elif el.tag == '{DAV:}set':
newval = propel
limit = None
requested = None
for el in request_body:
if el.tag == '{DAV:}sync-token':
old_token = el.text
elif el.tag == '{DAV:}sync-level':
sync_level = el.text
elif el.tag == '{DAV:}limit':
limit = el.text
elif el.tag == '{DAV:}prop':
requested = list(el)
else:
raise webdav.BadRequestError('unknown tag %s' % el.tag)
# TODO(jelmer): Implement sync_level infinite
if sync_level not in ("1", ):
raise webdav.BadRequestError(
"sync level %r unsupported" % sync_level)
new_token = resource.get_sync_token()
try:
diff_iter = resource.iter_differences_since(old_token, new_token)
except NotImplementedError:
yield webdav.Status(
href, '403 Forbidden',
error=ET.Element('{DAV:}sync-traversal-supported'))
return
if limit is not None:
try:
[nresults_el] = list(limit)
except ValueError:
raise webdav.BadRequestError(
def __init__(self, message):
super(BadRequestError, self).__init__(message)
self.message = message
async def _handle_request(self, request, environ):
if request.headers.get('Expect', '') != '':
return Response(status='417 Expectation Failed')
try:
do = self.methods[request.method]
except KeyError:
return _send_method_not_allowed(self._get_allowed_methods(request))
try:
return await do.handle(request, environ, self)
except BadRequestError as e:
return Response(
status='400 Bad Request',
body=[e.message.encode(DEFAULT_ENCODING)])
except NotAcceptableError as e:
return Response(
status='406 Not Acceptable',
body=[str(e).encode(DEFAULT_ENCODING)])
except UnsupportedMediaType as e:
return Response(
status='415 Unsupported Media Type',
body=[('Unsupported media type %r' % e.content_type)
.encode(DEFAULT_ENCODING)])
except UnauthorizedError:
return Response(
status='401 Unauthorized',
body=[('Please login.'.encode(DEFAULT_ENCODING))])
base_href, unused_path, base_resource = (
app._get_resource_from_environ(request, environ))
if base_resource is None:
yield Status(request.url, '404 Not Found')
return
# Default depth is infinity, per RFC2518
depth = request.headers.get("Depth", "infinity")
if not request.can_read_body:
requested = None
else:
et = await _readXmlBody(
request, '{DAV:}propfind', strict=app.strict)
try:
[requested] = et
except ValueError:
raise BadRequestError(
'Received more than one element in propfind.')
async for href, resource in traverse_resource(
base_resource, base_href, depth):
propstat = []
if requested is None or requested.tag == '{DAV:}allprop':
propstat = get_all_properties(
href, resource, app.properties, environ)
elif requested.tag == '{DAV:}prop':
propstat = get_properties(
href, resource, app.properties, environ, requested)
elif requested.tag == '{DAV:}propname':
propstat = get_property_names(
href, resource, app.properties, environ, requested)
else:
raise BadRequestError(
'Expected prop/allprop/propname tag, got ' + requested.tag)
limit = None
for el in body:
if el.tag in ('{DAV:}prop', '{DAV:}allprop', '{DAV:}propname'):
requested = el
elif el.tag == ('{%s}filter' % NAMESPACE):
filter_el = el
elif el.tag == ('{%s}limit' % NAMESPACE):
limit = el
else:
raise webdav.BadRequestError(
'Unknown tag %s in report %s' % (el.tag, self.name))
if limit is not None:
try:
[nresults_el] = list(limit)
except ValueError:
raise webdav.BadRequestError(
'Invalid number of subelements in limit')
try:
nresults = int(nresults_el.text)
except ValueError:
raise webdav.BadRequestError(
'nresults not a number')
else:
nresults = None
i = 0
async for (href, resource) in webdav.traverse_resource(
base_resource, base_href, depth):
if not apply_filter(filter_el, resource):
continue
if nresults is not None and i >= nresults:
break
async def _readXmlBody(
request, expected_tag: Optional[str] = None, strict: bool = True):
content_type = request.content_type
base_content_type, params = parse_type(content_type)
if strict and base_content_type not in ('text/xml', 'application/xml'):
raise UnsupportedMediaType(content_type)
body = b''.join(await _readBody(request))
if os.environ.get('XANDIKOS_DUMP_DAV_XML'):
print("IN: " + body.decode('utf-8'))
try:
et = xmlparse(body)
except ET.ParseError:
raise BadRequestError('Unable to parse body.')
if expected_tag is not None and et.tag != expected_tag:
raise BadRequestError('Expected %s tag, got %s' %
(expected_tag, et.tag))
return et
except NotImplementedError:
yield webdav.Status(
href, '403 Forbidden',
error=ET.Element('{DAV:}sync-traversal-supported'))
return
if limit is not None:
try:
[nresults_el] = list(limit)
except ValueError:
raise webdav.BadRequestError(
'Invalid number of subelements in limit')
try:
nresults = int(nresults_el.text)
except ValueError:
raise webdav.BadRequestError(
'nresults not a number')
diff_iter = itertools.islice(diff_iter, nresults)
for (name, old_resource, new_resource) in diff_iter:
subhref = urllib.parse.urljoin(
webdav.ensure_trailing_slash(href), name)
if new_resource is None:
yield webdav.Status(subhref, status='404 Not Found')
else:
propstat = []
for prop in requested:
if old_resource is not None:
old_propstat = webdav.get_property_from_element(
href, old_resource, properties, environ, prop)
else:
old_propstat = None
resource = app.backend.create_collection(path)
except FileNotFoundError:
return webdav.Response(status='409 Conflict')
el = ET.Element('{DAV:}resourcetype')
await app.properties['{DAV:}resourcetype'].get_value(
href, resource, el, environ)
ET.SubElement(el, '{urn:ietf:params:xml:ns:caldav}calendar')
app.properties['{DAV:}resourcetype'].set_value(href, resource, el)
if base_content_type in ('text/xml', 'application/xml'):
et = await webdav._readXmlBody(
request, '{urn:ietf:params:xml:ns:caldav}mkcalendar',
strict=app.strict)
propstat = []
for el in et:
if el.tag != '{DAV:}set':
raise webdav.BadRequestError(
'Unknown tag %s in mkcalendar' % el.tag)
propstat.extend(webdav.apply_modify_prop(
el, href, resource, app.properties))
ret = ET.Element(
'{urn:ietf:params:xml:ns:carldav:}mkcalendar-response')
for propstat_el in webdav.propstat_as_xml(propstat):
ret.append(propstat_el)
return webdav._send_xml_response(
'201 Created', ret, webdav.DEFAULT_ENCODING)
else:
return webdav.Response(status='201 Created')