""" Does parsing of ETag-related headers: If-None-Matches, If-Matches Also If-Range parsing """ from webob.datetime_utils import ( parse_date, serialize_date, ) from webob.descriptors import _rx_etag from webob.util import header_docstring __all__ = ['AnyETag', 'NoETag', 'ETagMatcher', 'IfRange', 'etag_property'] def etag_property(key, default, rfc_section, strong=True): doc = header_docstring(key, rfc_section) doc += " Converts it as a Etag." def fget(req): value = req.environ.get(key) if not value: return default else: return ETagMatcher.parse(value, strong=strong) def fset(req, val): if val is None: req.environ[key] = None else: req.environ[key] = str(val) def fdel(req): del req.environ[key] return property(fget, fset, fdel, doc=doc) class _AnyETag(object): """ Represents an ETag of *, or a missing ETag when matching is 'safe' """ def __repr__(self): return '' def __nonzero__(self): return False __bool__ = __nonzero__ # python 3 def __contains__(self, other): return True def __str__(self): return '*' AnyETag = _AnyETag() class _NoETag(object): """ Represents a missing ETag when matching is unsafe """ def __repr__(self): return '' def __nonzero__(self): return False __bool__ = __nonzero__ # python 3 def __contains__(self, other): return False def __str__(self): return '' NoETag = _NoETag() # TODO: convert into a simple tuple class ETagMatcher(object): def __init__(self, etags): self.etags = etags def __contains__(self, other): return other in self.etags def __repr__(self): return '' % (' or '.join(self.etags)) @classmethod def parse(cls, value, strong=True): """ Parse this from a header value """ if value == '*': return AnyETag if not value: return cls([]) matches = _rx_etag.findall(value) if not matches: return cls([value]) elif strong: return cls([t for w, t in matches if not w]) else: return cls([t for w, t in matches]) def __str__(self): return ', '.join(map('"%s"'.__mod__, self.etags)) class IfRange(object): def __init__(self, etag): self.etag = etag @classmethod def parse(cls, value): """ Parse this from a header value. """ if not value: return cls(AnyETag) elif value.endswith(' GMT'): # Must be a date return IfRangeDate(parse_date(value)) else: return cls(ETagMatcher.parse(value)) def __contains__(self, resp): """ Return True if the If-Range header matches the given etag or last_modified """ return resp.etag_strong in self.etag def __nonzero__(self): return bool(self.etag) def __repr__(self): return '%s(%r)' % ( self.__class__.__name__, self.etag ) def __str__(self): return str(self.etag) if self.etag else '' __bool__ = __nonzero__ # python 3 class IfRangeDate(object): def __init__(self, date): self.date = date def __contains__(self, resp): last_modified = resp.last_modified return last_modified and (last_modified <= self.date) def __repr__(self): return '%s(%r)' % ( self.__class__.__name__, self.date ) def __str__(self): return serialize_date(self.date)