def test_static_file(self): app = flask.Flask(__name__) # default cache timeout is 12 hours with app.test_request_context(): rv = app.send_static_file('index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assert_equal(cc.max_age, 12 * 60 * 60) app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 3600 with app.test_request_context(): rv = app.send_static_file('index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assert_equal(cc.max_age, 3600) # override get_send_file_options with some new values and check them class StaticFileApp(flask.Flask): def get_send_file_options(self, filename): opts = super(StaticFileApp, self).get_send_file_options(filename) opts['cache_timeout'] = 10 # this test catches explicit inclusion of the conditional # keyword arg in the guts opts['conditional'] = True return opts app = StaticFileApp(__name__) with app.test_request_context(): rv = app.send_static_file('index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assert_equal(cc.max_age, 10)
def test_static_file(self): app = flask.Flask(__name__) # default cache timeout is 12 hours with app.test_request_context(): rv = app.send_static_file('index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assert_equal(cc.max_age, 12 * 60 * 60) app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 3600 with app.test_request_context(): rv = app.send_static_file('index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assert_equal(cc.max_age, 3600) # override get_send_file_options with some new values and check them class StaticFileApp(flask.Flask): def get_send_file_options(self, filename): opts = super(StaticFileApp, self).get_send_file_options(filename) opts['cache_timeout'] = 10 # this test catches explicit inclusion of the conditional # keyword arg in the guts opts['conditional'] = True return opts app = StaticFileApp(__name__) with app.test_request_context(): rv = app.send_static_file('index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assert_equal(cc.max_age, 10)
def test_cache_control_header(self): cc = http.parse_cache_control_header("max-age=0, no-cache") assert cc.max_age == 0 assert cc.no_cache cc = http.parse_cache_control_header( 'private, community="UCI"', None, datastructures.ResponseCacheControl ) assert cc.private assert cc["community"] == "UCI" c = datastructures.ResponseCacheControl() assert c.no_cache is None assert c.private is None c.no_cache = True assert c.no_cache == "*" c.private = True assert c.private == "*" del c.private assert c.private is None # max_age is an int, other types are converted c.max_age = 3.1 assert c.max_age == 3 del c.max_age c.s_maxage = 3.1 assert c.s_maxage == 3 del c.s_maxage assert c.to_header() == "no-cache"
def test_static_file(self): app = flask.Flask(__name__) # default cache timeout is 12 hours (hard-coded) with app.test_request_context(): rv = app.send_static_file("index.html") cc = parse_cache_control_header(rv.headers["Cache-Control"]) self.assert_equal(cc.max_age, 12 * 60 * 60) # override get_static_file_options with some new values and check them class StaticFileApp(flask.Flask): def __init__(self): super(StaticFileApp, self).__init__(__name__) def get_static_file_options(self, filename): opts = super(StaticFileApp, self).get_static_file_options(filename) opts["cache_timeout"] = 10 # this test catches explicit inclusion of the conditional # keyword arg in the guts opts["conditional"] = True return opts app = StaticFileApp() with app.test_request_context(): rv = app.send_static_file("index.html") cc = parse_cache_control_header(rv.headers["Cache-Control"]) self.assert_equal(cc.max_age, 10)
def test_default_static_cache_timeout(self): app = flask.Flask(__name__) class MyBlueprint(flask.Blueprint): def get_send_file_max_age(self, filename): return 100 blueprint = MyBlueprint('blueprint', __name__, static_folder='static') app.register_blueprint(blueprint) # try/finally, in case other tests use this app for Blueprint tests. max_age_default = app.config['SEND_FILE_MAX_AGE_DEFAULT'] try: with app.test_request_context(): unexpected_max_age = 3600 if app.config[ 'SEND_FILE_MAX_AGE_DEFAULT'] == unexpected_max_age: unexpected_max_age = 7200 app.config['SEND_FILE_MAX_AGE_DEFAULT'] = unexpected_max_age rv = blueprint.send_static_file('chat.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assert_equal(cc.max_age, 100) rv.close() finally: app.config['SEND_FILE_MAX_AGE_DEFAULT'] = max_age_default
def fix_headers(self, environ, headers, status=None): if self.fix_vary: header = headers.get("content-type", "") mimetype, options = parse_options_header(header) if mimetype not in ("text/html", "text/plain", "text/sgml"): headers.pop("vary", None) if self.fix_attach and "content-disposition" in headers: pragma = parse_set_header(headers.get("pragma", "")) pragma.discard("no-cache") header = pragma.to_header() if not header: headers.pop("pragma", "") else: headers["Pragma"] = header header = headers.get("cache-control", "") if header: cc = parse_cache_control_header(header, cls=ResponseCacheControl) cc.no_cache = None cc.no_store = False header = cc.to_header() if not header: headers.pop("cache-control", "") else: headers["Cache-Control"] = header
def fix_headers(self, environ, headers, status=None): if self.fix_vary: header = headers.get("content-type", "") mimetype, options = parse_options_header(header) if mimetype not in ("text/html", "text/plain", "text/sgml"): headers.pop("vary", None) if self.fix_attach and "content-disposition" in headers: pragma = parse_set_header(headers.get("pragma", "")) pragma.discard("no-cache") header = pragma.to_header() if not header: headers.pop("pragma", "") else: headers["Pragma"] = header header = headers.get("cache-control", "") if header: cc = parse_cache_control_header(header, cls=ResponseCacheControl) cc.no_cache = None cc.no_store = False header = cc.to_header() if not header: headers.pop("cache-control", "") else: headers["Cache-Control"] = header
def fix_headers(self, environ, headers, status=None): if self.fix_vary: header = headers.get('content-type', '') mimetype, options = parse_options_header(header) if mimetype not in ('text/html', 'text/plain', 'text/sgml'): headers.pop('vary', None) if self.fix_attach and 'content-disposition' in headers: pragma = parse_set_header(headers.get('pragma', '')) pragma.discard('no-cache') header = pragma.to_header() if not header: headers.pop('pragma', '') else: headers['Pragma'] = header header = headers.get('cache-control', '') if header: cc = parse_cache_control_header(header, cls=ResponseCacheControl) cc.no_cache = None cc.no_store = False header = cc.to_header() if not header: headers.pop('cache-control', '') else: headers['Cache-Control'] = header
def cache_control(self) -> ResponseCacheControl: def on_update(cache_control: ResponseCacheControl) -> None: self.cache_control = cache_control return parse_cache_control_header( self.headers.get("Cache-Control"), on_update, ResponseCacheControl )
def cache_control(self): def on_update(cache_control): if not cache_control and "cache-control" in self.headers: del self.headers["cache-control"] elif cache_control: self.headers["Cache-Control"] = cache_control.to_header() return parse_cache_control_header(self.headers.get("cache-control"), on_update, ResponseCacheControl)
def cache_control(self): def on_update(cache_control): if not cache_control and 'cache-control' in self.headers: del self.headers['cache-control'] elif cache_control: self.headers['Cache-Control'] = cache_control.to_header() return parse_cache_control_header(self.headers.get('cache-control'), on_update, ResponseCacheControl)
def test_cache_control_header(self): cc = http.parse_cache_control_header("max-age=0, no-cache") assert cc.max_age == 0 assert cc.no_cache cc = http.parse_cache_control_header('private, community="UCI"', None, datastructures.ResponseCacheControl) assert cc.private assert cc["community"] == "UCI" c = datastructures.ResponseCacheControl() assert c.no_cache is None assert c.private is None c.no_cache = True assert c.no_cache == "*" c.private = True assert c.private == "*" del c.private assert c.private is None assert c.to_header() == "no-cache"
def cache_control(self): def on_update(cache_control): if not cache_control and 'cache-control' in self.headers: del self.headers['cache-control'] elif cache_control: self.headers['Cache-Control'] = cache_control.to_header() return parse_cache_control_header(self.headers.get('cache-control'), on_update, ResponseCacheControl)
def get_cache_timeout(r): # Cache the weather data at a rate that the upstream service dictates, but # that also keeps us easily within the 1000 requests per day free limit. header = r.headers.get('Cache-Control') control = parse_cache_control_header(header, cls=ResponseCacheControl) try: return max(control.max_age, CACHE_MIN_SECONDS) except TypeError: return CACHE_MIN_SECONDS
def test_cache_control_header(self): cc = http.parse_cache_control_header('max-age=0, no-cache') assert cc.max_age == 0 assert cc.no_cache cc = http.parse_cache_control_header('private, community="UCI"', None, datastructures.ResponseCacheControl) assert cc.private assert cc['community'] == 'UCI' c = datastructures.ResponseCacheControl() assert c.no_cache is None assert c.private is None c.no_cache = True assert c.no_cache == '*' c.private = True assert c.private == '*' del c.private assert c.private is None assert c.to_header() == 'no-cache'
def test_cache_control_header(self): cc = http.parse_cache_control_header('max-age=0, no-cache') assert cc.max_age == 0 assert cc.no_cache cc = http.parse_cache_control_header('private, community="UCI"', None, datastructures.ResponseCacheControl) assert cc.private assert cc['community'] == 'UCI' c = datastructures.ResponseCacheControl() assert c.no_cache is None assert c.private is None c.no_cache = True assert c.no_cache == '*' c.private = True assert c.private == '*' del c.private assert c.private is None assert c.to_header() == 'no-cache'
def cache_control(self): def on_update(cache_control): if not cache_control and 'cache-control' in self.headers: del self.headers['cache-control'] elif cache_control: self.headers['Cache-Control'] = cache_control.to_header() value = self.headers.get('Cache-Control') if value is not None: value = parse_cache_control_header(value) return CacheControl(value, on_update)
def get_ff_cache(profile_dir, store_body=False): cache_dir = os.path.join(profile_dir, "Cache") if not os.path.isdir(cache_dir): return [] # Firefox updated the cache dir structure since our study cache_map = os.path.join(cache_dir, "_CACHE_MAP_") cache_dump = os.path.join(BASE_TMP_DIR, append_timestamp("cache") + rand_str()) create_dir(cache_dump) subprocess.call([PERL_PATH, CACHE_PERL_SCRIPT, cache_map, "--recover=" + cache_dump]) cache_items = [] db_items = ("Etag", "Request String", "Expires", "Cache-Control") for fname in glob(os.path.join(cache_dump, "*_metadata")): item = {} try: with open(fname) as f: metadata = f.read() item = parse_metadata(metadata) for db_item in db_items: if db_item not in item: item[db_item] = "" # If a response includes both an Expires header and a max-age # directive, the max-age directive overrides the Expires header # (http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html) expiry_delta_sec = 0 if "Expires" in item: # parse expiry date expiry = parse_date(item["Expires"]) if expiry: expiry_delta = expiry - datetime.now() expiry_delta_sec = expiry_delta.total_seconds() if "Cache-Control:" in item: # parse max-age directive cache_directives =\ parse_cache_control_header(item["Cache-Control"], cls=ResponseCacheControl) if "max-age" in cache_directives: expiry_delta_sec = cache_directives["max-age"] if expiry_delta_sec < DELTA_MONTH: continue item["Expiry-Delta"] = expiry_delta_sec with open(fname[:-9]) as f: data = f.read() item["Body"] = data if store_body else "" # store as BLOB item["Hash"] = hash_text(base64.b64encode(data)) except IOError as exc: print "Error processing cache: %s: %s" % (exc, traceback.format_exc()) cache_items.append(item) if os.path.isdir(cache_dump): shutil.rmtree(cache_dump) return cache_items
def get_ff_cache(profile_dir, store_body=False): cache_dir = os.path.join(profile_dir, "Cache") if not os.path.isdir(cache_dir): return [] # Firefox updated the cache dir structure since our study cache_map = os.path.join(cache_dir, "_CACHE_MAP_") cache_dump = os.path.join(BASE_TMP_DIR, append_timestamp("cache") + rand_str()) create_dir(cache_dump) subprocess.call( [PERL_PATH, CACHE_PERL_SCRIPT, cache_map, "--recover=" + cache_dump]) cache_items = [] db_items = ("Etag", "Request String", "Expires", "Cache-Control") for fname in glob(os.path.join(cache_dump, "*_metadata")): item = {} try: with open(fname) as f: metadata = f.read() item = parse_metadata(metadata) for db_item in db_items: if db_item not in item: item[db_item] = "" # If a response includes both an Expires header and a max-age # directive, the max-age directive overrides the Expires header # (http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html) expiry_delta_sec = 0 if "Expires" in item: # parse expiry date expiry = parse_date(item["Expires"]) if expiry: expiry_delta = expiry - datetime.now() expiry_delta_sec = expiry_delta.total_seconds() if "Cache-Control:" in item: # parse max-age directive cache_directives =\ parse_cache_control_header(item["Cache-Control"], cls=ResponseCacheControl) if "max-age" in cache_directives: expiry_delta_sec = cache_directives["max-age"] if expiry_delta_sec < DELTA_MONTH: continue item["Expiry-Delta"] = expiry_delta_sec with open(fname[:-9]) as f: data = f.read() item["Body"] = data if store_body else "" # store as BLOB item["Hash"] = hash_text(base64.b64encode(data)) except IOError as exc: print "Error processing cache: %s: %s" % (exc, traceback.format_exc()) cache_items.append(item) if os.path.isdir(cache_dump): shutil.rmtree(cache_dump) return cache_items
def cache_control(self): """The Cache-Control general-header field is used to specify directives that MUST be obeyed by all caching mechanisms along the request/response chain. """ def on_update(cache_control): if not cache_control and 'cache-control' in self.headers: del self.headers['cache-control'] elif cache_control: self.headers['Cache-Control'] = cache_control.to_header() return parse_cache_control_header(self.headers.get('cache-control'), on_update)
def testStaticFile(self): ConfigManager.removeConfig('development') ConfigManager.addConfig(testConfig) app = shimehari.Shimehari(__name__) app.setStaticFolder('static') with app.testRequestContext(): rv = app.sendStaticFile('index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assertEqual(cc.max_age, 12 * 60 * 60) rv = shimehari.sendFile(os.path.join(app.rootPath, 'static/index.html')) cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assertEqual(cc.max_age, 12 * 60 * 60) app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 3600 with app.testRequestContext(): rv = app.sendStaticFile('index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assertEqual(cc.max_age, 3600) rv = shimehari.sendFile(os.path.join(app.rootPath, 'static/index.html')) cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assertEqual(cc.max_age, 3600) class StaticFileApp(shimehari.Shimehari): def getSendFileMaxAge(self, filename): return 10 app = StaticFileApp(__name__) app.setStaticFolder('static') with app.testRequestContext(): rv = app.sendStaticFile('index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assertEqual(cc.max_age, 10) rv = shimehari.sendFile(os.path.join(app.rootPath, 'static/index.html')) cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assertEqual(cc.max_age, 10)
def test_static_file(self): app = flask.Flask(__name__) # default cache timeout is 12 hours with app.test_request_context(): # Test with static file handler. rv = app.send_static_file('index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assert_equal(cc.max_age, 12 * 60 * 60) # Test again with direct use of send_file utility. rv = flask.send_file('static/index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assert_equal(cc.max_age, 12 * 60 * 60) app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 3600 with app.test_request_context(): # Test with static file handler. rv = app.send_static_file('index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assert_equal(cc.max_age, 3600) # Test again with direct use of send_file utility. rv = flask.send_file('static/index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assert_equal(cc.max_age, 3600) class StaticFileApp(flask.Flask): def get_send_file_max_age(self, filename): return 10 app = StaticFileApp(__name__) with app.test_request_context(): # Test with static file handler. rv = app.send_static_file('index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assert_equal(cc.max_age, 10) # Test again with direct use of send_file utility. rv = flask.send_file('static/index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assert_equal(cc.max_age, 10)
def cache_control(self) -> ResponseCacheControl: """The Cache-Control general-header field is used to specify directives that MUST be obeyed by all caching mechanisms along the request/response chain. """ def on_update(cache_control): if not cache_control and "cache-control" in self.headers: del self.headers["cache-control"] elif cache_control: self.headers["Cache-Control"] = cache_control.to_header() return parse_cache_control_header(self.headers.get("cache-control"), on_update, ResponseCacheControl)
def _get_cache_control_directive(self, name): success, the_values = self._enumerate_header("cache-control") if success: cc = parse_cache_control_header(the_values, cls=ResponseCacheControl) if name == "max-age" and cc.max_age is not None: return True, timedelta(seconds=int(cc.max_age)) elif name == "stale-while-revalidate" and \ cc.stale_while_revalidate is not None: return True, timedelta(seconds=int(cc.stale_while_revalidate)) else: return False, None else: return False, None
def refresh_keys(self): now = monotonic() age = now - self.cached_at if age >= self.max_age: response = requests.get(self.KEYCHAIN_URL) if response.status_code != 200: raise Exception hazmat = default_backend() for kid, text in response.json().items(): certificate = load_pem_x509_certificate( bytes(text, 'utf-8'), hazmat) self.keys[kid] = certificate.public_key() cache_control = response.headers['Cache-Control'] self.max_age = parse_cache_control_header(cache_control).max_age self.cached_at = now
def test_templates_and_static(self): from blueprintapp import app c = app.test_client() rv = c.get('/') self.assert_equal(rv.data, b'Hello from the Frontend') rv = c.get('/admin/') self.assert_equal(rv.data, b'Hello from the Admin') rv = c.get('/admin/index2') self.assert_equal(rv.data, b'Hello from the Admin') rv = c.get('/admin/static/test.txt') self.assert_equal(rv.data.strip(), b'Admin File') rv.close() rv = c.get('/admin/static/css/test.css') self.assert_equal(rv.data.strip(), b'/* nested file */') rv.close() # try/finally, in case other tests use this app for Blueprint tests. max_age_default = app.config['SEND_FILE_MAX_AGE_DEFAULT'] try: expected_max_age = 3600 if app.config['SEND_FILE_MAX_AGE_DEFAULT'] == expected_max_age: expected_max_age = 7200 app.config['SEND_FILE_MAX_AGE_DEFAULT'] = expected_max_age rv = c.get('/admin/static/css/test.css') cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assert_equal(cc.max_age, expected_max_age) rv.close() finally: app.config['SEND_FILE_MAX_AGE_DEFAULT'] = max_age_default with app.test_request_context(): self.assert_equal( flask.url_for('admin.static', filename='test.txt'), '/admin/static/test.txt') with app.test_request_context(): try: flask.render_template('missing.html') except TemplateNotFound as e: self.assert_equal(e.name, 'missing.html') else: self.assert_true(0, 'expected exception') with flask.Flask(__name__).test_request_context(): self.assert_equal(flask.render_template('nested/nested.txt'), 'I\'m nested')
def surrogate_control(self): """ The Cache-Control general-header field is used to specify directives that MUST be obeyed by all caching mechanisms along the request/response chain. """ def on_update(surrogate_control): if not surrogate_control and "surrogate-control" in self.headers: del self.headers["surrogate-control"] elif surrogate_control: # pragma: no cover self.headers["Surrogate-Control"] = \ surrogate_control.to_header() return parse_cache_control_header( self.headers.get("surrogate-control"), on_update, ResponseCacheControl, )
def test_templates_and_static(self): from blueprintapp import app c = app.test_client() rv = c.get('/') self.assert_equal(rv.data, b'Hello from the Frontend') rv = c.get('/admin/') self.assert_equal(rv.data, b'Hello from the Admin') rv = c.get('/admin/index2') self.assert_equal(rv.data, b'Hello from the Admin') rv = c.get('/admin/static/test.txt') self.assert_equal(rv.data.strip(), b'Admin File') rv.close() rv = c.get('/admin/static/css/test.css') self.assert_equal(rv.data.strip(), b'/* nested file */') rv.close() # try/finally, in case other tests use this app for Blueprint tests. max_age_default = app.config['SEND_FILE_MAX_AGE_DEFAULT'] try: expected_max_age = 3600 if app.config['SEND_FILE_MAX_AGE_DEFAULT'] == expected_max_age: expected_max_age = 7200 app.config['SEND_FILE_MAX_AGE_DEFAULT'] = expected_max_age rv = c.get('/admin/static/css/test.css') cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assert_equal(cc.max_age, expected_max_age) rv.close() finally: app.config['SEND_FILE_MAX_AGE_DEFAULT'] = max_age_default with app.test_request_context(): self.assert_equal(flask.url_for('admin.static', filename='test.txt'), '/admin/static/test.txt') with app.test_request_context(): try: flask.render_template('missing.html') except TemplateNotFound as e: self.assert_equal(e.name, 'missing.html') else: self.assert_true(0, 'expected exception') with flask.Flask(__name__).test_request_context(): self.assert_equal(flask.render_template('nested/nested.txt'), 'I\'m nested')
def test_static_file(self, app, req_ctx): # default cache timeout is 12 hours # Test with static file handler. rv = app.send_static_file("index.html") cc = parse_cache_control_header(rv.headers["Cache-Control"]) assert cc.max_age == 12 * 60 * 60 rv.close() # Test again with direct use of send_file utility. rv = flask.send_file("static/index.html") cc = parse_cache_control_header(rv.headers["Cache-Control"]) assert cc.max_age == 12 * 60 * 60 rv.close() app.config["SEND_FILE_MAX_AGE_DEFAULT"] = 3600 # Test with static file handler. rv = app.send_static_file("index.html") cc = parse_cache_control_header(rv.headers["Cache-Control"]) assert cc.max_age == 3600 rv.close() # Test again with direct use of send_file utility. rv = flask.send_file("static/index.html") cc = parse_cache_control_header(rv.headers["Cache-Control"]) assert cc.max_age == 3600 rv.close() # Test with static file handler. rv = app.send_static_file(FakePath("index.html")) cc = parse_cache_control_header(rv.headers["Cache-Control"]) assert cc.max_age == 3600 rv.close() class StaticFileApp(flask.Flask): def get_send_file_max_age(self, filename): return 10 app = StaticFileApp(__name__) with app.test_request_context(): # Test with static file handler. rv = app.send_static_file("index.html") cc = parse_cache_control_header(rv.headers["Cache-Control"]) assert cc.max_age == 10 rv.close() # Test again with direct use of send_file utility. rv = flask.send_file("static/index.html") cc = parse_cache_control_header(rv.headers["Cache-Control"]) assert cc.max_age == 10 rv.close()
def test_static_file(self, app, req_ctx): # default cache timeout is 12 hours # Test with static file handler. rv = app.send_static_file("index.html") cc = parse_cache_control_header(rv.headers["Cache-Control"]) assert cc.max_age == 12 * 60 * 60 rv.close() # Test again with direct use of send_file utility. rv = flask.send_file("static/index.html") cc = parse_cache_control_header(rv.headers["Cache-Control"]) assert cc.max_age == 12 * 60 * 60 rv.close() app.config["SEND_FILE_MAX_AGE_DEFAULT"] = 3600 # Test with static file handler. rv = app.send_static_file("index.html") cc = parse_cache_control_header(rv.headers["Cache-Control"]) assert cc.max_age == 3600 rv.close() # Test again with direct use of send_file utility. rv = flask.send_file("static/index.html") cc = parse_cache_control_header(rv.headers["Cache-Control"]) assert cc.max_age == 3600 rv.close() # Test with static file handler. rv = app.send_static_file(FakePath("index.html")) cc = parse_cache_control_header(rv.headers["Cache-Control"]) assert cc.max_age == 3600 rv.close() class StaticFileApp(flask.Flask): def get_send_file_max_age(self, filename): return 10 app = StaticFileApp(__name__) with app.test_request_context(): # Test with static file handler. rv = app.send_static_file("index.html") cc = parse_cache_control_header(rv.headers["Cache-Control"]) assert cc.max_age == 10 rv.close() # Test again with direct use of send_file utility. rv = flask.send_file("static/index.html") cc = parse_cache_control_header(rv.headers["Cache-Control"]) assert cc.max_age == 10 rv.close()
def test_templates_and_static(test_apps): from blueprintapp import app client = app.test_client() rv = client.get("/") assert rv.data == b"Hello from the Frontend" rv = client.get("/admin/") assert rv.data == b"Hello from the Admin" rv = client.get("/admin/index2") assert rv.data == b"Hello from the Admin" rv = client.get("/admin/static/test.txt") assert rv.data.strip() == b"Admin File" rv.close() rv = client.get("/admin/static/css/test.css") assert rv.data.strip() == b"/* nested file */" rv.close() # try/finally, in case other tests use this app for Blueprint tests. max_age_default = app.config["SEND_FILE_MAX_AGE_DEFAULT"] try: expected_max_age = 3600 if app.config["SEND_FILE_MAX_AGE_DEFAULT"] == expected_max_age: expected_max_age = 7200 app.config["SEND_FILE_MAX_AGE_DEFAULT"] = expected_max_age rv = client.get("/admin/static/css/test.css") cc = parse_cache_control_header(rv.headers["Cache-Control"]) assert cc.max_age == expected_max_age rv.close() finally: app.config["SEND_FILE_MAX_AGE_DEFAULT"] = max_age_default with app.test_request_context(): assert ( flask.url_for("admin.static", filename="test.txt") == "/admin/static/test.txt" ) with app.test_request_context(): with pytest.raises(TemplateNotFound) as e: flask.render_template("missing.html") assert e.value.name == "missing.html" with flask.Flask(__name__).test_request_context(): assert flask.render_template("nested/nested.txt") == "I'm nested"
def test_templates_and_static(test_apps): from blueprintapp import app client = app.test_client() rv = client.get("/") assert rv.data == b"Hello from the Frontend" rv = client.get("/admin/") assert rv.data == b"Hello from the Admin" rv = client.get("/admin/index2") assert rv.data == b"Hello from the Admin" rv = client.get("/admin/static/test.txt") assert rv.data.strip() == b"Admin File" rv.close() rv = client.get("/admin/static/css/test.css") assert rv.data.strip() == b"/* nested file */" rv.close() # try/finally, in case other tests use this app for Blueprint tests. max_age_default = app.config["SEND_FILE_MAX_AGE_DEFAULT"] try: expected_max_age = 3600 if app.config["SEND_FILE_MAX_AGE_DEFAULT"] == expected_max_age: expected_max_age = 7200 app.config["SEND_FILE_MAX_AGE_DEFAULT"] = expected_max_age rv = client.get("/admin/static/css/test.css") cc = parse_cache_control_header(rv.headers["Cache-Control"]) assert cc.max_age == expected_max_age rv.close() finally: app.config["SEND_FILE_MAX_AGE_DEFAULT"] = max_age_default with app.test_request_context(): assert ( flask.url_for("admin.static", filename="test.txt") == "/admin/static/test.txt" ) with app.test_request_context(): with pytest.raises(TemplateNotFound) as e: flask.render_template("missing.html") assert e.value.name == "missing.html" with flask.Flask(__name__).test_request_context(): assert flask.render_template("nested/nested.txt") == "I'm nested"
def test_templates_and_static(test_apps): from blueprintapp import app c = app.test_client() rv = c.get('/') assert rv.data == b'Hello from the Frontend' rv = c.get('/admin/') assert rv.data == b'Hello from the Admin' rv = c.get('/admin/index2') assert rv.data == b'Hello from the Admin' rv = c.get('/admin/static/test.txt') assert rv.data.strip() == b'Admin File' rv.close() rv = c.get('/admin/static/css/test.css') assert rv.data.strip() == b'/* nested file */' rv.close() # try/finally, in case other tests use this app for Blueprint tests. max_age_default = app.config['SEND_FILE_MAX_AGE_DEFAULT'] try: expected_max_age = 3600 if app.config['SEND_FILE_MAX_AGE_DEFAULT'] == expected_max_age: expected_max_age = 7200 app.config['SEND_FILE_MAX_AGE_DEFAULT'] = expected_max_age rv = c.get('/admin/static/css/test.css') cc = parse_cache_control_header(rv.headers['Cache-Control']) assert cc.max_age == expected_max_age rv.close() finally: app.config['SEND_FILE_MAX_AGE_DEFAULT'] = max_age_default with app.test_request_context(): assert keyes.url_for('admin.static', filename='test.txt') == '/admin/static/test.txt' with app.test_request_context(): with pytest.raises(TemplateNotFound) as e: keyes.render_template('missing.html') assert e.value.name == 'missing.html' with keyes.Keyes(__name__).test_request_context(): assert keyes.render_template('nested/nested.txt') == 'I\'m nested'
def test_templates_and_static(test_apps): from blueprintapp import app c = app.test_client() rv = c.get('/') assert rv.data == b'Hello from the Frontend' rv = c.get('/admin/') assert rv.data == b'Hello from the Admin' rv = c.get('/admin/index2') assert rv.data == b'Hello from the Admin' rv = c.get('/admin/static/test.txt') assert rv.data.strip() == b'Admin File' rv.close() rv = c.get('/admin/static/css/test.css') assert rv.data.strip() == b'/* nested file */' rv.close() # try/finally, in case other tests use this app for Blueprint tests. max_age_default = app.config['SEND_FILE_MAX_AGE_DEFAULT'] try: expected_max_age = 3600 if app.config['SEND_FILE_MAX_AGE_DEFAULT'] == expected_max_age: expected_max_age = 7200 app.config['SEND_FILE_MAX_AGE_DEFAULT'] = expected_max_age rv = c.get('/admin/static/css/test.css') cc = parse_cache_control_header(rv.headers['Cache-Control']) assert cc.max_age == expected_max_age rv.close() finally: app.config['SEND_FILE_MAX_AGE_DEFAULT'] = max_age_default with app.test_request_context(): assert keyes.url_for('admin.static', filename='test.txt') == '/admin/static/test.txt' with app.test_request_context(): with pytest.raises(TemplateNotFound) as e: keyes.render_template('missing.html') assert e.value.name == 'missing.html' with keyes.Keyes(__name__).test_request_context(): assert keyes.render_template('nested/nested.txt') == 'I\'m nested'
def test_default_static_cache_timeout(self): app = flask.Flask(__name__) class MyBlueprint(flask.Blueprint): def get_send_file_max_age(self, filename): return 100 blueprint = MyBlueprint('blueprint', __name__, static_folder='static') app.register_blueprint(blueprint) # try/finally, in case other tests use this app for Blueprint tests. max_age_default = app.config['SEND_FILE_MAX_AGE_DEFAULT'] try: with app.test_request_context(): unexpected_max_age = 3600 if app.config['SEND_FILE_MAX_AGE_DEFAULT'] == unexpected_max_age: unexpected_max_age = 7200 app.config['SEND_FILE_MAX_AGE_DEFAULT'] = unexpected_max_age rv = blueprint.send_static_file('index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assert_equal(cc.max_age, 100) finally: app.config['SEND_FILE_MAX_AGE_DEFAULT'] = max_age_default
def test_default_static_cache_timeout(app): class MyBlueprint(flask.Blueprint): def get_send_file_max_age(self, filename): return 100 blueprint = MyBlueprint("blueprint", __name__, static_folder="static") app.register_blueprint(blueprint) # try/finally, in case other tests use this app for Blueprint tests. max_age_default = app.config["SEND_FILE_MAX_AGE_DEFAULT"] try: with app.test_request_context(): unexpected_max_age = 3600 if app.config["SEND_FILE_MAX_AGE_DEFAULT"] == unexpected_max_age: unexpected_max_age = 7200 app.config["SEND_FILE_MAX_AGE_DEFAULT"] = unexpected_max_age rv = blueprint.send_static_file("index.html") cc = parse_cache_control_header(rv.headers["Cache-Control"]) assert cc.max_age == 100 rv.close() finally: app.config["SEND_FILE_MAX_AGE_DEFAULT"] = max_age_default
def test_default_static_max_age(app): class MyBlueprint(flask.Blueprint): def get_send_file_max_age(self, filename): return 100 blueprint = MyBlueprint("blueprint", __name__, static_folder="static") app.register_blueprint(blueprint) # try/finally, in case other tests use this app for Blueprint tests. max_age_default = app.config["SEND_FILE_MAX_AGE_DEFAULT"] try: with app.test_request_context(): unexpected_max_age = 3600 if app.config["SEND_FILE_MAX_AGE_DEFAULT"] == unexpected_max_age: unexpected_max_age = 7200 app.config["SEND_FILE_MAX_AGE_DEFAULT"] = unexpected_max_age rv = blueprint.send_static_file("index.html") cc = parse_cache_control_header(rv.headers["Cache-Control"]) assert cc.max_age == 100 rv.close() finally: app.config["SEND_FILE_MAX_AGE_DEFAULT"] = max_age_default
def test_templates_and_static(self): from blueprintapp import app c = app.test_client() rv = c.get("/") self.assert_equal(rv.data, "Hello from the Frontend") rv = c.get("/admin/") self.assert_equal(rv.data, "Hello from the Admin") rv = c.get("/admin/index2") self.assert_equal(rv.data, "Hello from the Admin") rv = c.get("/admin/static/test.txt") self.assert_equal(rv.data.strip(), "Admin File") rv = c.get("/admin/static/css/test.css") self.assert_equal(rv.data.strip(), "/* nested file */") # try/finally, in case other tests use this app for Blueprint tests. max_age_default = app.config["SEND_FILE_MAX_AGE_DEFAULT"] try: expected_max_age = 3600 if app.config["SEND_FILE_MAX_AGE_DEFAULT"] == expected_max_age: expected_max_age = 7200 app.config["SEND_FILE_MAX_AGE_DEFAULT"] = expected_max_age rv = c.get("/admin/static/css/test.css") cc = parse_cache_control_header(rv.headers["Cache-Control"]) self.assert_equal(cc.max_age, expected_max_age) finally: app.config["SEND_FILE_MAX_AGE_DEFAULT"] = max_age_default with app.test_request_context(): self.assert_equal(flask.url_for("admin.static", filename="test.txt"), "/admin/static/test.txt") with app.test_request_context(): try: flask.render_template("missing.html") except TemplateNotFound, e: self.assert_equal(e.name, "missing.html") else:
def latest_observations(self): response = self.cache.get(self._CACHE_KEY.format(self._config["location_id"])) if not response: self.statsd.incr(__name__ + ".cache_miss") with self.statsd.timer(__name__ + ".request_time"): response = self._make_request() max_age = parse_cache_control_header(response.info().getparam("Cache-Control")).max_age response = json.load(response) self.cache.set(self._CACHE_KEY.format(self._config["location_id"]), response, max_age) else: self.statsd.incr(__name__ + ".cache_hit") source_period = response["SiteRep"]["DV"]["Location"]["Period"] if isinstance(source_period, list): source_period = source_period[-1] source_observation = source_period["Rep"][-1] minutes_since_midnight = timedelta(minutes=int(source_observation["$"])) obs_time = datetime(*time.strptime(source_period["value"], "%Y-%m-%dZ")[:6], tzinfo=utc) obs_time += minutes_since_midnight weather_type, weather_type_id = self.WEATHER_TYPES.get(source_observation["W"]) return { "type": weather_type, "type_id": weather_type_id, "temperature": u"{} °C".format(source_observation["T"]), "wind_speed": "{} mph".format(source_observation["S"]), "gust_speed": "{} mph".format(source_observation["G"]) if "G" in source_observation else "N/A", "wind_direction": source_observation["D"], "pressure": "{} mb".format(source_observation["P"]), "obs_location": capwords(response["SiteRep"]["DV"]["Location"]["name"]), "obs_time": obs_time.isoformat(), }
def test_static_file(self): app = flask.Flask(__name__) # default cache timeout is 12 hours with app.test_request_context(): # Test with static file handler. rv = app.send_static_file('index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assert_equal(cc.max_age, 12 * 60 * 60) rv.close() # Test again with direct use of send_file utility. rv = flask.send_file('static/index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assert_equal(cc.max_age, 12 * 60 * 60) rv.close() app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 3600 with app.test_request_context(): # Test with static file handler. rv = app.send_static_file('index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assert_equal(cc.max_age, 3600) rv.close() # Test again with direct use of send_file utility. rv = flask.send_file('static/index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assert_equal(cc.max_age, 3600) rv.close() class StaticFileApp(flask.Flask): def get_send_file_max_age(self, filename): return 10 app = StaticFileApp(__name__) with app.test_request_context(): # Test with static file handler. rv = app.send_static_file('index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assert_equal(cc.max_age, 10) rv.close() # Test again with direct use of send_file utility. rv = flask.send_file('static/index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assert_equal(cc.max_age, 10) rv.close()
def test_static_file(self): app = keyes.Keyes(__name__) # default cache timeout is 12 hours with app.test_request_context(): # Test with static file handler. rv = app.send_static_file('index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) assert cc.max_age == 12 * 60 * 60 rv.close() # Test again with direct use of send_file utility. rv = keyes.send_file('static/index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) assert cc.max_age == 12 * 60 * 60 rv.close() app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 3600 with app.test_request_context(): # Test with static file handler. rv = app.send_static_file('index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) assert cc.max_age == 3600 rv.close() # Test again with direct use of send_file utility. rv = keyes.send_file('static/index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) assert cc.max_age == 3600 rv.close() class StaticFileApp(keyes.Keyes): def get_send_file_max_age(self, filename): return 10 app = StaticFileApp(__name__) with app.test_request_context(): # Test with static file handler. rv = app.send_static_file('index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) assert cc.max_age == 10 rv.close() # Test again with direct use of send_file utility. rv = keyes.send_file('static/index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) assert cc.max_age == 10 rv.close()
def testStaticFile(self): ConfigManager.removeConfig('development') ConfigManager.addConfig(testConfig) app = shimehari.Shimehari(__name__) app.staticFolder = 'static' with app.testRequestContext(): print app.appFolder print app.staticFolder rv = app.sendStaticFile('index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assertEqual(cc.max_age, 12 * 60 * 60) rv = shimehari.sendFile( os.path.join(app.rootPath, 'static/index.html')) cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assertEqual(cc.max_age, 12 * 60 * 60) app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 3600 with app.testRequestContext(): rv = app.sendStaticFile('index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assertEqual(cc.max_age, 3600) rv = shimehari.sendFile( os.path.join(app.rootPath, 'static/index.html')) cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assertEqual(cc.max_age, 3600) class StaticFileApp(shimehari.Shimehari): def getSendFileMaxAge(self, filename): return 10 app = StaticFileApp(__name__) app.staticFolder = 'static' with app.testRequestContext(): rv = app.sendStaticFile('index.html') cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assertEqual(cc.max_age, 10) rv = shimehari.sendFile( os.path.join(app.rootPath, 'static/index.html')) cc = parse_cache_control_header(rv.headers['Cache-Control']) self.assertEqual(cc.max_age, 10)
def test_ie_fixes(self): @fixers.InternetExplorerFix @Request.application def application(request): response = Response('binary data here', mimetype='application/vnd.ms-excel') response.headers['Vary'] = 'Cookie' response.headers[ 'Content-Disposition'] = 'attachment; filename=foo.xls' return response c = Client(application, Response) response = c.get( '/', headers=[('User-Agent', 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)')]) # IE gets no vary assert response.data == 'binary data here' assert 'vary' not in response.headers assert response.headers[ 'content-disposition'] == 'attachment; filename=foo.xls' assert response.headers['content-type'] == 'application/vnd.ms-excel' # other browsers do c = Client(application, Response) response = c.get('/') assert response.data == 'binary data here' assert 'vary' in response.headers cc = ResponseCacheControl() cc.no_cache = True @fixers.InternetExplorerFix @Request.application def application(request): response = Response('binary data here', mimetype='application/vnd.ms-excel') response.headers['Pragma'] = ', '.join(pragma) response.headers['Cache-Control'] = cc.to_header() response.headers[ 'Content-Disposition'] = 'attachment; filename=foo.xls' return response # IE has no pragma or cache control pragma = ('no-cache', ) c = Client(application, Response) response = c.get( '/', headers=[('User-Agent', 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)')]) assert response.data == 'binary data here' assert 'pragma' not in response.headers assert 'cache-control' not in response.headers assert response.headers[ 'content-disposition'] == 'attachment; filename=foo.xls' # IE has simplified pragma pragma = ('no-cache', 'x-foo') cc.proxy_revalidate = True response = c.get( '/', headers=[('User-Agent', 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)')]) assert response.data == 'binary data here' assert response.headers['pragma'] == 'x-foo' assert response.headers['cache-control'] == 'proxy-revalidate' assert response.headers[ 'content-disposition'] == 'attachment; filename=foo.xls' # regular browsers get everything response = c.get('/') assert response.data == 'binary data here' assert response.headers['pragma'] == 'no-cache, x-foo' cc = parse_cache_control_header(response.headers['cache-control'], cls=ResponseCacheControl) assert cc.no_cache assert cc.proxy_revalidate assert response.headers[ 'content-disposition'] == 'attachment; filename=foo.xls'
def cache_control(self): cache_control = self.environ.get('HTTP_CACHE_CONTROL') return parse_cache_control_header(cache_control, None, RequestCacheControl)
def cache_control(self): """A `CacheControl` object for the incoming cache control headers.""" if not 'HTTP_CACHE_CONTROL' in self.environ: return CacheControl(None) return parse_cache_control_header(self.environ['HTTP_CACHE_CONTROL'])
def cache_control(self) -> RequestCacheControl: return parse_cache_control_header(self.headers.get("Cache-Control"), None, RequestCacheControl)
def test_ie_fixes(self): @fixers.InternetExplorerFix @Request.application def application(request): response = Response("binary data here", mimetype="application/vnd.ms-excel") response.headers["Vary"] = "Cookie" response.headers[ "Content-Disposition"] = "attachment; filename=foo.xls" return response c = Client(application, Response) response = c.get( "/", headers=[("User-Agent", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)")], ) # IE gets no vary assert response.get_data() == b"binary data here" assert "vary" not in response.headers assert response.headers[ "content-disposition"] == "attachment; filename=foo.xls" assert response.headers["content-type"] == "application/vnd.ms-excel" # other browsers do c = Client(application, Response) response = c.get("/") assert response.get_data() == b"binary data here" assert "vary" in response.headers cc = ResponseCacheControl() cc.no_cache = True @fixers.InternetExplorerFix @Request.application def application(request): response = Response("binary data here", mimetype="application/vnd.ms-excel") response.headers["Pragma"] = ", ".join(pragma) response.headers["Cache-Control"] = cc.to_header() response.headers[ "Content-Disposition"] = "attachment; filename=foo.xls" return response # IE has no pragma or cache control pragma = ("no-cache", ) c = Client(application, Response) response = c.get( "/", headers=[("User-Agent", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)")], ) assert response.get_data() == b"binary data here" assert "pragma" not in response.headers assert "cache-control" not in response.headers assert response.headers[ "content-disposition"] == "attachment; filename=foo.xls" # IE has simplified pragma pragma = ("no-cache", "x-foo") cc.proxy_revalidate = True response = c.get( "/", headers=[("User-Agent", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)")], ) assert response.get_data() == b"binary data here" assert response.headers["pragma"] == "x-foo" assert response.headers["cache-control"] == "proxy-revalidate" assert response.headers[ "content-disposition"] == "attachment; filename=foo.xls" # regular browsers get everything response = c.get("/") assert response.get_data() == b"binary data here" assert response.headers["pragma"] == "no-cache, x-foo" cc = parse_cache_control_header(response.headers["cache-control"], cls=ResponseCacheControl) assert cc.no_cache assert cc.proxy_revalidate assert response.headers[ "content-disposition"] == "attachment; filename=foo.xls"
def cache_control(self): """A `CacheControl` object for the incoming cache control headers.""" cache_control = self.environ.get('HTTP_CACHE_CONTROL') return parse_cache_control_header(cache_control)
def cache_control(self): cache_control = self.environ.get('HTTP_CACHE_CONTROL') return parse_cache_control_header(cache_control, None, RequestCacheControl)
def test_ie_fixes(self): @fixers.InternetExplorerFix @Request.application def application(request): response = Response('binary data here', mimetype='application/vnd.ms-excel') response.headers['Vary'] = 'Cookie' response.headers['Content-Disposition'] = 'attachment; filename=foo.xls' return response c = Client(application, Response) response = c.get('/', headers=[ ('User-Agent', 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)') ]) # IE gets no vary assert response.get_data() == b'binary data here' assert 'vary' not in response.headers assert response.headers['content-disposition'] == 'attachment; filename=foo.xls' assert response.headers['content-type'] == 'application/vnd.ms-excel' # other browsers do c = Client(application, Response) response = c.get('/') assert response.get_data() == b'binary data here' assert 'vary' in response.headers cc = ResponseCacheControl() cc.no_cache = True @fixers.InternetExplorerFix @Request.application def application(request): response = Response('binary data here', mimetype='application/vnd.ms-excel') response.headers['Pragma'] = ', '.join(pragma) response.headers['Cache-Control'] = cc.to_header() response.headers['Content-Disposition'] = 'attachment; filename=foo.xls' return response # IE has no pragma or cache control pragma = ('no-cache',) c = Client(application, Response) response = c.get('/', headers=[ ('User-Agent', 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)') ]) assert response.get_data() == b'binary data here' assert 'pragma' not in response.headers assert 'cache-control' not in response.headers assert response.headers['content-disposition'] == 'attachment; filename=foo.xls' # IE has simplified pragma pragma = ('no-cache', 'x-foo') cc.proxy_revalidate = True response = c.get('/', headers=[ ('User-Agent', 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)') ]) assert response.get_data() == b'binary data here' assert response.headers['pragma'] == 'x-foo' assert response.headers['cache-control'] == 'proxy-revalidate' assert response.headers['content-disposition'] == 'attachment; filename=foo.xls' # regular browsers get everything response = c.get('/') assert response.get_data() == b'binary data here' assert response.headers['pragma'] == 'no-cache, x-foo' cc = parse_cache_control_header(response.headers['cache-control'], cls=ResponseCacheControl) assert cc.no_cache assert cc.proxy_revalidate assert response.headers['content-disposition'] == 'attachment; filename=foo.xls'