def test_etags(self): assert http.quote_etag('foo') == '"foo"' assert http.quote_etag('foo', True) == 'W/"foo"' assert http.unquote_etag('"foo"') == ('foo', False) assert http.unquote_etag('W/"foo"') == ('foo', True) es = http.parse_etags('"foo", "bar", W/"baz", blar') assert sorted(es) == ['bar', 'blar', 'foo'] assert 'foo' in es assert 'baz' not in es assert es.contains_weak('baz') assert 'blar' in es assert es.contains_raw('W/"baz"') assert es.contains_raw('"foo"') assert sorted(es.to_header().split(', ')) == ['"bar"', '"blar"', '"foo"', 'W/"baz"']
def test_etags(self): assert http.quote_etag('foo') == '"foo"' assert http.quote_etag('foo', True) == 'w/"foo"' assert http.unquote_etag('"foo"') == ('foo', False) assert http.unquote_etag('w/"foo"') == ('foo', True) es = http.parse_etags('"foo", "bar", w/"baz", blar') assert sorted(es) == ['bar', 'blar', 'foo'] assert 'foo' in es assert 'baz' not in es assert es.contains_weak('baz') assert 'blar' in es assert es.contains_raw('w/"baz"') assert es.contains_raw('"foo"') assert sorted(es.to_header().split(', ')) == ['"bar"', '"blar"', '"foo"', 'w/"baz"']
def test_etags(self): assert http.quote_etag("foo") == '"foo"' assert http.quote_etag("foo", True) == 'w/"foo"' assert http.unquote_etag('"foo"') == ("foo", False) assert http.unquote_etag('w/"foo"') == ("foo", True) es = http.parse_etags('"foo", "bar", w/"baz", blar') assert sorted(es) == ["bar", "blar", "foo"] assert "foo" in es assert "baz" not in es assert es.contains_weak("baz") assert "blar" in es assert es.contains_raw('w/"baz"') assert es.contains_raw('"foo"') assert sorted(es.to_header().split(", ")) == ['"bar"', '"blar"', '"foo"', 'w/"baz"']
def test_exception_header_forwarded(self): """Test that HTTPException's headers are extended properly""" app = Flask(__name__) app.config['DEBUG'] = True api = flask_restful.Api(app) class NotModified(HTTPException): code = 304 def __init__(self, etag, *args, **kwargs): super(NotModified, self).__init__(*args, **kwargs) self.etag = quote_etag(etag) def get_headers(self, *args, **kwargs): """Get a list of headers.""" return [('ETag', self.etag)] class Foo1(flask_restful.Resource): def get(self): flask_abort(304, etag='myETag') api.add_resource(Foo1, '/foo') _aborter.mapping.update({304: NotModified}) with app.test_client() as client: foo = client.get('/foo') self.assertEquals(foo.get_etag(), unquote_etag(quote_etag('myETag')))
def feed(config, tz, template, page=None): include_day = config.include_day start = datetime.fromtimestamp(config.start_timestamp, tz) now = datetime.now(start.tzinfo) total_posts = count_dates(start, now, include_day) per_page = 50 last_page = total_posts // per_page - 1 headers = { 'Date': http_date(now), } links = [] if page is None: etag = quote_etag(str(total_posts)) next_date, dates = recent_dates(start, now, include_day, per_page) max_age = int((next_date - now).total_seconds()) if last_page >= 0: links.append(('prev-archive', last_page)) elif page <= last_page: etag = '"0"' dates = archived_dates(start, include_day, page * per_page, per_page) max_age = 7 * 24 * 60 * 60 links.append(('current', None)) if page < last_page: links.append(('next-archive', page + 1)) if page > 0: links.append(('prev-archive', page - 1)) else: abort(404) headers['Cache-Control'] = "public, max-age={}, immutable".format(max_age) headers['Expires'] = http_date(now + timedelta(seconds=max_age)) headers['ETag'] = etag if not is_resource_modified(request.environ, etag): return Response(status=304, headers=headers) day_names = [ calendar.day_name[day] for day, included in enumerate(include_day) if included ] if len(day_names) > 1: days_description = '{} and {}'.format( ', '.join(day_names[:-1]), day_names[-1], ) else: days_description = day_names[0] feed = render_template( "feed.xml", template=template, days_description=days_description, start=start, config=config, links=links, dates=dates, ) return Response(feed, mimetype='application/rss+xml', headers=headers)
def response(self, request, data, etag=None, cache_policy=None): """Renders `data` to a JSON response. An ETag may be specified. When it is not specified one will be generated based on the data. The caching policy can be optionally configured. By default it takes the policy from the controller object: `cache_policy`. """ if etag is None and data is not None: etag = self.etag(data) # FIXME: Check content-type headers if data is None: if etag is None: raise TypeError('response requires an etag when ' 'the response body is None') resp = Response(status=304, content_type='application/json') else: # Avoid sending the resource when an ETag matches request_etags = parse_etags( request.environ.get('HTTP_IF_NONE_MATCH')) if request_etags.contains(etag): resp = Response(status=304, content_type='application/json') # Render the given data to a response object else: resp = Response(self.data_encoder.encode(data), content_type='application/json') resp.headers['ETag'] = quote_etag(etag) if cache_policy is None: cache_policy = self.cache_policy return cache_policy(resp)
def build_etag(self, response, include_etag=True, **kwargs): """ Add an etag to the response body. Uses spooky where possible because it is empirically fast and well-regarded. See: http://blog.reverberate.org/2012/01/state-of-hash-functions-2012.html """ if not include_etag: return if not spooky: # use built-in md5 response.add_etag() return # use spooky response.headers["ETag"] = quote_etag( hexlify( spooky.hash128( response.get_data(), ).to_bytes(16, "little"), ).decode("utf-8"), )
def test_exception_header_forwarded(self): '''Ensure that HTTPException's headers are extended properly''' self.app.config['DEBUG'] = True api = restplus.Api(self.app) class NotModified(HTTPException): code = 304 def __init__(self, etag, *args, **kwargs): super(NotModified, self).__init__(*args, **kwargs) self.etag = quote_etag(etag) def get_headers(self, *args, **kwargs): return [('ETag', self.etag)] @api.route('/foo') class Foo1(restplus.Resource): def get(self): abort(304, etag='myETag') abort.mapping.update({304: NotModified}) with self.app.test_client() as client: foo = client.get('/foo') self.assertEquals(foo.get_etag(), unquote_etag(quote_etag('myETag')))
def make_headers(self, content=None): """Add `ETag` header to response.""" headers = super().make_headers(content=content) etag = content.get("revision_id") if content else None if etag: headers["ETag"] = quote_etag(str(etag), False) return headers
def test_exception_header_forwarded(self): """Test that HTTPException's headers are extended properly""" app = Flask(__name__) app.config['DEBUG'] = True api = flask_restful.Api(app) class NotModified(HTTPException): code = 304 def __init__(self, etag, *args, **kwargs): super(NotModified, self).__init__(*args, **kwargs) self.etag = quote_etag(etag) def get_headers(self, *args, **kwargs): """Get a list of headers.""" return [('ETag', self.etag)] class Foo1(flask_restful.Resource): def get(self): flask_abort(304, etag='myETag') api.add_resource(Foo1, '/foo') flask_abort.mapping.update({304: NotModified}) with app.test_client() as client: foo = client.get('/foo') self.assertEquals(foo.get_etag(), unquote_etag(quote_etag('myETag')))
def test_etags(self): assert http.quote_etag("foo") == '"foo"' assert http.quote_etag("foo", True) == 'W/"foo"' assert http.unquote_etag('"foo"') == ("foo", False) assert http.unquote_etag('W/"foo"') == ("foo", True) es = http.parse_etags('"foo", "bar", W/"baz", blar') assert sorted(es) == ["bar", "blar", "foo"] assert "foo" in es assert "baz" not in es assert es.contains_weak("baz") assert "blar" in es assert es.contains_raw('W/"baz"') assert es.contains_raw('"foo"') assert sorted(es.to_header().split(", ")) == [ '"bar"', '"blar"', '"foo"', 'W/"baz"', ]
def check_normal_response(res, method): if method != client.head: parsed = json.loads(res.get_data(as_text=True)) expected = {'id': 1, 'method': parsed['method']} assert parsed == expected # check that the right method was called assert method_names[parsed['method']] == method assert res.content_type == 'application/json' assert res.status_code == 200 # check that the ETag is correct assert unquote_etag(res.headers['ETag']) == \ unquote_etag(quote_etag('abc'))
def etag_headers(obj_or_list, code, many=False): """Headers for a single resource item.""" headers = { 'content-type': resource_requestctx.accept_mimetype, } if many: return headers etag = obj_or_list.get("revision_id") if etag: headers["ETag"] = quote_etag(str(etag), False) return headers
def serve_file(path): headers = {} st = os.stat(path) etag = 'clay-{0}-{1}-{2}'.format( os.path.getmtime(path), os.path.getsize(path), adler32(path.encode('utf-8')) & 0xffffffff) headers['ETag'] = quote_etag(etag) # Set the Last-Modified response header, so that # modified-since validation code can work. headers['Last-Modified'] = httputil.HTTPDate(st.st_mtime) _, ext = os.path.splitext(path) content_type = mimetypes.types_map.get(ext, None) headers['Content-Type'] = content_type or 'text/plain' fileobj = open(path, 'rb') return serve_fileobj(fileobj, headers, st.st_size)
def serve_file(path): headers = {} st = os.stat(path) etag = 'clay-{0}-{1}-{2}'.format( os.path.getmtime(path), os.path.getsize(path), adler32(path.encode('utf-8')) & 0xffffffff ) headers['ETag'] = quote_etag(etag) # Set the Last-Modified response header, so that # modified-since validation code can work. headers['Last-Modified'] = httputil.HTTPDate(st.st_mtime) _, ext = os.path.splitext(path) content_type = mimetypes.types_map.get(ext, None) headers['Content-Type'] = content_type or 'text/plain' fileobj = open(path, 'rb') return serve_fileobj(fileobj, headers, st.st_size)
def test_exception_header_forwarded(self, app, client): '''Ensure that HTTPException's headers are extended properly''' api = restplus.Api(app) class NotModified(HTTPException): code = 304 def __init__(self, etag, *args, **kwargs): super(NotModified, self).__init__(*args, **kwargs) self.etag = quote_etag(etag) def get_headers(self, *args, **kwargs): return [('ETag', self.etag)] custom_abort = Aborter(mapping={304: NotModified}) @api.route('/foo') class Foo1(restplus.Resource): def get(self): custom_abort(304, etag='myETag') foo = client.get('/foo') assert foo.get_etag() == unquote_etag(quote_etag('myETag'))
def set_etag(self, etag, weak = False): self.headers['ETag'] = quote_etag(etag, weak)
def __init__(self, etag, *args, **kwargs): super(NotModified, self).__init__(*args, **kwargs) self.etag = quote_etag(etag)
def check_304_response(res): assert res.status_code == 304 # check that the ETag is correct assert unquote_etag(res.headers['ETag']) == \ unquote_etag(quote_etag('abc'))
def set_etag(self, etag: str, weak: bool = False) -> None: """Set the etag, and override the old one if there was one.""" self.headers["ETag"] = quote_etag(etag, weak)
def set_etag(self, etag, weak=False): """Set the etag, and override the old one if there was one.""" self.headers['ETag'] = quote_etag(etag, weak)