def parse_etags(value): """Parse an etag header. :param value: the tag header to parse :return: an :class:`~werkzeug.datastructures.ETags` object. """ if not value: return ETags() strong = [] weak = [] end = len(value) pos = 0 while pos < end: match = _etag_re.match(value, pos) if match is None: break is_weak, quoted, raw = match.groups() if raw == '*': return ETags(star_tag=True) elif quoted: raw = quoted if is_weak: weak.append(raw) else: strong.append(raw) pos = match.end() return ETags(strong, weak)
def require_etag( etag: ETags, error_details: Optional[Dict[str, str]] = None, ) -> None: """Ensure the current request matches the given ETag. Args: etag: An Werkzeug ETag instance to compare the global request instance to. error_details: An optional dict, which will be communicated to the client whenever there is an etag mismatch. Raises: ProblemException: When If-Match missing or ETag doesn't match. """ etags_required = active_config.rest_api_etag_locking if not request.if_match: if not etags_required: return raise ProblemException( HTTPStatus.PRECONDITION_REQUIRED, "Precondition required", "If-Match header required for this operation. See documentation.", ext=error_details, ) if request.if_match.as_set() != etag.as_set(): raise ProblemException( HTTPStatus.PRECONDITION_FAILED, "Precondition failed", f"ETag didn't match. Expected {etag}. Probable cause: Object changed by another user.", ext=error_details, )
def etag_of_dict(dict_: Dict[str, Any]) -> ETags: """Build a sha256 hash over a dictionary's content. Keys are sorted first to ensure a stable hash. Examples: >>> etag_of_dict({'a': 'b', 'c': 'd'}) <ETags '"88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589"'> >>> etag_of_dict({'a': 'b', 'c': {'d': {'e': 'f'}}}) <ETags '"bef57ec7f53a6d40beb640a780a639c83bc29ac8a9816f1fc6c5c6dcd93c4721"'> Args: dict_ (dict): A dictionary. Returns: str: The hex-digest of the built hash. """ def _update(_hash_obj, _d): if isinstance(_d, list): for value in sorted(_d): _update(_hash_obj, value) else: for key, value in sorted(_d.items()): _hash_obj.update(key.encode('utf-8')) if isinstance(value, (dict, list)): _update(_hash_obj, value) else: _hash_obj.update(value.encode('utf-8')) _hash = hashlib.sha256() _update(_hash, dict_) return ETags(strong_etags=[_hash.hexdigest()])
def require_etag(etag: ETags) -> None: """Ensure the current request matches the given ETag. Args: etag: An Werkzeug ETag instance to compare the global request instance to. Raises: ProblemException: When If-Match missing or ETag doesn't match. """ etags_required = config.rest_api_etag_locking if not request.if_match: if not etags_required: return raise ProblemException( HTTPStatus.PRECONDITION_REQUIRED, "Precondition required", "If-Match header required for this operation. See documentation.", ) if request.if_match.as_set() != etag.as_set(): raise ProblemException( HTTPStatus.PRECONDITION_FAILED, "Precondition failed", "ETag didn't match. Probable cause: Object changed by another user.", )
def _get_etag(folder): attributes = folder.attributes() if 'meta_data' in attributes: etags = [str(attributes['meta_data']['updated_at'])] return ETags(strong_etags=etags) else: raise ProblemException( 500, "Folder %r has no meta_data." % (folder.name(), ), "Can't create ETag.")
def etag_of_dict(dict_: Dict[str, Any]) -> ETags: """Build a sha256 hash over a dictionary's content. Keys are sorted first to ensure a stable hash. Examples: >>> etag_of_dict({'a': 'b', 'c': 'd'}) <ETags '"88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589"'> >>> etag_of_dict({'a': 'b', 'c': {'d': {'e': 'f'}}}) <ETags '"bef57ec7f53a6d40beb640a780a639c83bc29ac8a9816f1fc6c5c6dcd93c4721"'> >>> etag_of_dict({'a': [{'b': 1, 'd': 2}, {'d': 2, 'b': 3}]}) <ETags '"6ea899bec9b061d54f1f8fcdb7405363126c0e96d198d09792eff0996590ee3e"'> Args: dict_ (dict): A dictionary. Returns: str: The hex-digest of the built hash. """ def _first(sequence): try: return sequence[0] except IndexError: pass def _update(_hash_obj, _d): if isinstance(_d, (list, tuple)): first = _first(_d) if isinstance(first, dict): for entry in _d: _update(_hash_obj, entry) else: for value in sorted(_d): _update(_hash_obj, value) else: if isinstance(_d, dict): for key, value in sorted(_d.items()): _hash_obj.update(key.encode('utf-8')) if isinstance(value, (dict, list, tuple)): _update(_hash_obj, value) elif isinstance(value, bool): _hash_obj.update(str(value).lower().encode('utf-8')) else: _hash_obj.update(str(value).encode('utf-8')) else: _hash_obj.update(str(_d).encode('utf-8')) _hash = hashlib.sha256() _update(_hash, dict_) return ETags(strong_etags=[_hash.hexdigest()])
def parse_etags(value): if not value: return ETags() strong = [] weak = [] end = len(value) pos = 0 while pos < end: match = _etag_re.match(value, pos) if match is None: break is_weak, quoted, raw = match.groups() if raw == '*': return ETags(star_tag=True) if quoted: raw = quoted if is_weak: weak.append(raw) else: strong.append(raw) pos = match.end() return ETags(strong, weak)
def require_etag(etag: ETags) -> None: """Ensure the current request matches the given ETag. Args: etag: An Werkzeug ETag instance to compare the global request instance to. Raises: ProblemException: When ETag doesn't match. """ if request.if_match.as_set() != etag.as_set(): raise ProblemException( 412, "Precondition failed", "ETag didn't match. Probable cause: Object changed by another user.", )
def etag_of_dict(dict_): """Build a sha256 hash over a dictionary's content. Keys are sorted first to ensure a stable hash. Args: dict_ (dict): A dictionary. Returns: str: The hex-digest of the built hash. """ _hash = hashlib.sha256() for key in sorted(dict_.keys()): _hash.update(dict_[key]) return ETags(strong_etags=_hash.hexdigest())
def etag_of_obj(obj): """Build an ETag from an objects last updated time. Args: obj: An object with a `updated_at` method. Returns: The value which the method returns, else raises a `ProblemException`. """ updated_at = obj.updated_at() assert updated_at is not None if updated_at is None: raise ProblemException(500, "Object %r has no meta_data." % (obj.name(),), "Can't create ETag.") return ETags(strong_etags=[str(updated_at)])