def patch(self): # Overwrite a region of an existing file req = self.req obj = req.context req.dav.user_acl(req, obj, dprops.ACL_WRITE_CONTENT) self.conditional_request(obj) ctype = req.content_type if ctype == 'application/x-sabredav-partialupdate': if 'Content-Length' not in req.headers: raise dav.DAVLengthRequiredError('SabreDAV PATCH method requires Content-Length: HTTP header.') if 'X-Update-Range' not in req.headers: raise dav.DAVBadRequestError('Patch range must be specified via X-Update-Range: HTTP header.') range_hdr = req.headers.get('X-Update-Range') if ',' in range_hdr: raise dav.DAVBadRequestError('Malformed patch range or multiple ranges supplied via X-Update-Range: HTTP header.') r_start = r_end = None obj_sz = getattr(obj, 'size', None) if callable(obj_sz): obj_sz = obj_sz(req) if range_hdr == 'append': if obj_sz is None: raise dav.DAVNotImplementedError('Node does not support appending data.') r_start = obj_sz r_end = r_start + req.content_length else: patch_range = parse_range(range_hdr) if patch_range is None: raise dav.DAVBadRequestError('Malformed patch range supplied via X-Update-Range: HTTP header.') r_start = patch_range.start r_end = patch_range.end if (r_start is not None) and (r_end is not None): if (r_end - r_start) != req.content_length: raise dav.DAVUnsatisfiableRangeError('Content length and range supplied via X-Update-Range: HTTP header are not consistent.') if r_start < 0: if obj_sz is None: raise dav.DAVNotImplementedError('Node does not support relative file offsets.') r_start = obj_sz + r_start if r_start < 0: raise dav.DAVUnsatisfiableRangeError('Relative offset (supplied via X-Update-Range: HTTP header) is before file start.') r_end = r_start + req.content_length if r_end is None: r_end = r_start + req.content_length putter = getattr(obj, 'dav_put', None) if putter is None: raise dav.DAVNotImplementedError('Unable to patch node.') modified = putter(req, req.body_file_seekable, r_start, r_end - r_start) # TODO: handle IOErrors, handle non-seekable request body if modified: etag = None else: etag = getattr(obj, 'etag', None) if callable(etag): etag = etag(req) resp = dav.DAVOverwriteResponse(request=req, etag=etag) req.dav.set_features(resp, node=obj) resp.headers.add('MS-Author-Via', 'DAV') return resp raise dav.DAVUnsupportedMediaTypeError('Unknown content type specified in PATCH request.')
def test_parse_range_type(): from webob.byterange import Range from webob.descriptors import parse_range val = parse_range("bytes=1-500") assert type(val) is type(Range.parse("bytes=1-500")) # noqa: E701
def test_parse_range_none(): from webob.descriptors import parse_range assert parse_range(None) is None
def test_parse_range_type(): from webob.byterange import Range from webob.descriptors import parse_range val = parse_range("bytes=1-500") assert type(val) == type(Range.parse("bytes=1-500"))
def test_parse_range_none(): from webob.descriptors import parse_range assert parse_range(None) == None
def test_parse_range_type(): from webob.byterange import Range from webob.descriptors import parse_range val = parse_range("bytes=1-500") eq_(type(val), type(Range.parse("bytes=1-500")))
def test_parse_range_none(): from webob.descriptors import parse_range eq_(parse_range(None), None)
def test_parse_range_values(): from webob.byterange import Range from webob.descriptors import parse_range val = parse_range("bytes=1-500") eq_(val.ranges, Range.parse("bytes=1-500").ranges)
def test_parse_range_none(): from webob.descriptors import parse_range val = parse_range(None) eq_(val, None)