def include_files(self, extensions=None): """ Includes files (usually in the head). Can minify and cache local files By default, caches in ram for 5 minutes. To change, response.cache_includes = (cache_method, time_expire). Example: (cache.disk, 60) # caches to disk for 1 minute. """ app = current.request.application # We start by building a files list in which adjacent files internal to # the application are placed in a list inside the files list. # # We will only minify and concat adjacent internal files as there's # no way to know if changing the order with which the files are apppended # will break things since the order matters in both CSS and JS and # internal files may be interleaved with external ones. files = [] # For the adjacent list we're going to use storage List to both distinguish # from the regular list and so we can add attributes internal = List() internal.has_js = False internal.has_css = False done = set() # to remove duplicates for item in self.files: if not isinstance(item, list): if item in done: continue done.add(item) if isinstance(item, (list, tuple)) or not item.startswith('/' + app): # also consider items in other web2py applications to be external if internal: files.append(internal) internal = List() internal.has_js = False internal.has_css = False files.append(item) continue if extensions and not item.rpartition('.')[2] in extensions: continue internal.append(item) if item.endswith('.js'): internal.has_js = True if item.endswith('.css'): internal.has_css = True if internal: files.append(internal) # We're done we can now minify if have_minify: for i, f in enumerate(files): if isinstance(f, List) and ((self.optimize_css and f.has_css) or (self.optimize_js and f.has_js)): # cache for 5 minutes by default key = hashlib_md5(repr(f)).hexdigest() cache = self.cache_includes or (current.cache.ram, 60 * 5) def call_minify(files=f): return List(minify.minify(files, URL('static', 'temp'), current.request.folder, self.optimize_css, self.optimize_js)) if cache: cache_model, time_expire = cache files[i] = cache_model('response.files.minified/' + key, call_minify, time_expire) else: files[i] = call_minify() def static_map(s, item): if isinstance(item, str): f = item.lower().split('?')[0] ext = f.rpartition('.')[2] # if static_version we need also to check for # static_version_urls. In that case, the _.x.x.x # bit would have already been added by the URL() # function if self.static_version and not self.static_version_urls: item = item.replace( '/static/', '/static/_%s/' % self.static_version, 1) tmpl = template_mapping.get(ext) if tmpl: s.append(tmpl % item) elif isinstance(item, (list, tuple)): f = item[0] tmpl = template_mapping.get(f) if tmpl: s.append(tmpl % item[1]) s = [] for item in files: if isinstance(item, List): for f in item: static_map(s, f) else: static_map(s, item) self.write(''.join(s), escape=False)
def include_files(self, extensions=None): """ Includes files (usually in the head). Can minify and cache local files By default, caches in ram for 5 minutes. To change, response.cache_includes = (cache_method, time_expire). Example: (cache.disk, 60) # caches to disk for 1 minute. """ files = [] ext_files = [] has_js = has_css = False for item in self.files: if isinstance(item, (list, tuple)): ext_files.append(item) continue if extensions and not item.rpartition('.')[2] in extensions: continue if item in files: continue if item.endswith('.js'): has_js = True if item.endswith('.css'): has_css = True files.append(item) if have_minify and ((self.optimize_css and has_css) or (self.optimize_js and has_js)): # cache for 5 minutes by default key = hashlib_md5(repr(files)).hexdigest() cache = self.cache_includes or (current.cache.ram, 60 * 5) def call_minify(files=files): return minify.minify(files, URL('static', 'temp'), current.request.folder, self.optimize_css, self.optimize_js) if cache: cache_model, time_expire = cache files = cache_model('response.files.minified/' + key, call_minify, time_expire) else: files = call_minify() files.extend(ext_files) s = [] for item in files: if isinstance(item, str): f = item.lower().split('?')[0] ext = f.rpartition('.')[2] # if static_version we need also to check for # static_version_urls. In that case, the _.x.x.x # bit would have already been added by the URL() # function if self.static_version and not self.static_version_urls: item = item.replace( '/static/', '/static/_%s/' % self.static_version, 1) tmpl = template_mapping.get(ext) if tmpl: s.append(tmpl % item) elif isinstance(item, (list, tuple)): f = item[0] tmpl = template_mapping.get(f) if tmpl: s.append(tmpl % item[1]) self.write(''.join(s), escape=False)
def wrapped_f(): if current.request.env.request_method != 'GET': return func() if quick: session_ = True if 'S' in quick else False vars_ = True if 'V' in quick else False lang_ = True if 'L' in quick else False user_agent_ = True if 'U' in quick else False public_ = True if 'P' in quick else False else: (session_, vars_, lang_, user_agent_, public_) = \ (session, vars, lang, user_agent, public) expires = 'Fri, 01 Jan 1990 00:00:00 GMT' if time_expire: cache_control = 'max-age=%(time_expire)s, s-maxage=%(time_expire)s' % dict(time_expire=time_expire) expires = (current.request.utcnow + datetime.timedelta(seconds=time_expire)).strftime( '%a, %d %b %Y %H:%M:%S GMT') else: cache_control = 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0' cache_control += ', public' if not session_ and public_ else ', private' if cache_model: # figure out the correct cache key cache_key = [current.request.env.path_info, current.response.view] if session_: cache_key.append(current.response.session_id) elif user_agent_: if user_agent_ is True: cache_key.append("%(is_mobile)s_%(is_tablet)s" % current.request.user_agent()) else: cache_key.append(str(list(user_agent_.items()))) if vars_: cache_key.append(current.request.env.query_string) if lang_: cache_key.append(current.T.accepted_language) cache_key = hashlib_md5('__'.join(cache_key)).hexdigest() if prefix: cache_key = prefix + cache_key try: # action returns something rtn = cache_model(cache_key, lambda: func(), time_expire=time_expire) http, status = None, current.response.status except HTTP as e: # action raises HTTP (can still be valid) rtn = cache_model(cache_key, lambda: e.body, time_expire=time_expire) http, status = HTTP(e.status, rtn, **e.headers), e.status else: # action raised a generic exception http = None else: # no server-cache side involved try: # action returns something rtn = func() http, status = None, current.response.status except HTTP as e: # action raises HTTP (can still be valid) status = e.status http = HTTP(e.status, e.body, **e.headers) else: # action raised a generic exception http = None send_headers = False if http and isinstance(valid_statuses, list): if status in valid_statuses: send_headers = True elif valid_statuses is None: if str(status)[0] in '123': send_headers = True if send_headers: headers = {'Pragma': None, 'Expires': expires, 'Cache-Control': cache_control} current.response.headers.update(headers) if cache_model and not send_headers: # we cached already the value, but the status is not valid # so we need to delete the cached value cache_model(cache_key, None) if http: if send_headers: http.headers.update(current.response.headers) raise http return rtn
def wrapped_f(): if current.request.env.request_method != 'GET': return func() if quick: session_ = True if 'S' in quick else False vars_ = True if 'V' in quick else False lang_ = True if 'L' in quick else False user_agent_ = True if 'U' in quick else False public_ = True if 'P' in quick else False else: (session_, vars_, lang_, user_agent_, public_) = \ (session, vars, lang, user_agent, public) expires = 'Fri, 01 Jan 1990 00:00:00 GMT' if time_expire: cache_control = 'max-age=%(time_expire)s, s-maxage=%(time_expire)s' % dict( time_expire=time_expire) expires = (current.request.utcnow + datetime.timedelta(seconds=time_expire) ).strftime('%a, %d %b %Y %H:%M:%S GMT') else: cache_control = 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0' cache_control += ', public' if not session_ and public_ else ', private' if cache_model: # figure out the correct cache key cache_key = [ current.request.env.path_info, current.response.view ] if session_: cache_key.append(current.response.session_id) elif user_agent_: if user_agent_ is True: cache_key.append("%(is_mobile)s_%(is_tablet)s" % current.request.user_agent()) else: cache_key.append(str(list(user_agent_.items()))) if vars_: cache_key.append(current.request.env.query_string) if lang_: cache_key.append(current.T.accepted_language) cache_key = hashlib_md5('__'.join(cache_key)).hexdigest() if prefix: cache_key = prefix + cache_key try: # action returns something rtn = cache_model(cache_key, lambda: func(), time_expire=time_expire) http, status = None, current.response.status except HTTP as e: # action raises HTTP (can still be valid) rtn = cache_model(cache_key, lambda: e.body, time_expire=time_expire) http, status = HTTP(e.status, rtn, **e.headers), e.status else: # action raised a generic exception http = None else: # no server-cache side involved try: # action returns something rtn = func() http, status = None, current.response.status except HTTP as e: # action raises HTTP (can still be valid) status = e.status http = HTTP(e.status, e.body, **e.headers) else: # action raised a generic exception http = None send_headers = False if http and isinstance(valid_statuses, list): if status in valid_statuses: send_headers = True elif valid_statuses is None: if str(status)[0] in '123': send_headers = True if send_headers: headers = { 'Pragma': None, 'Expires': expires, 'Cache-Control': cache_control } current.response.headers.update(headers) if cache_model and not send_headers: # we cached already the value, but the status is not valid # so we need to delete the cached value cache_model(cache_key, None) if http: if send_headers: http.headers.update(current.response.headers) raise http return rtn