def set_response_cookie(path=None, path_header=None, name='session_id', timeout=60, domain=None, secure=False): """Set a response cookie for the client. path: the 'path' value to stick in the response cookie metadata. path_header: if 'path' is None (the default), then the response cookie 'path' will be pulled from request.headers[path_header]. name: the name of the cookie. timeout: the expiration timeout for the cookie. domain: the cookie domain. secure: if False (the default) the cookie 'secure' value will not be set. If True, the cookie 'secure' value will be set (to 1). """ # Set response cookie cookie = cherrypy.response.cookie cookie[name] = cherrypy.serving.session.id cookie[name]['path'] = (path or cherrypy.request.headers.get(path_header) or '/') # We'd like to use the "max-age" param as indicated in # http://www.faqs.org/rfcs/rfc2109.html but IE doesn't # save it to disk and the session is lost if people close # the browser. So we have to use the old "expires" ... sigh ... ## cookie[name]['max-age'] = timeout * 60 if timeout: cookie[name]['expires'] = http.HTTPDate(time.time() + (timeout * 60)) if domain is not None: cookie[name]['domain'] = domain if secure: cookie[name]['secure'] = 1
def default(self, *args, **kwd): if args: if args[0] == 'filter_forms_javascript.js': if config.caching_filter_form_javascript: if cherrypy.session.get( 'filter_forms_javascript') is not None: since = cherrypy.request.headers.get( 'If-Unmodified-Since') since2 = cherrypy.request.headers.get( 'If-Modified-Since') if since or since2: raise cherrypy.HTTPRedirect("", 304) cherrypy.response.headers['Last-Modified'] = http.HTTPDate( time.time()) result = filterforms.get_filter_forms_javascript( cherrypy.session['filterforms']) cherrypy.session['filter_forms_javascript'] = result return result elif args[0] == 'set_history': new_history = simplejson.loads(kwd.get('history', 'false')) cherrypy.session['history'] = new_history utils.get_corba_session().setHistory(new_history) debug('History set to %s' % new_history) return json_response(new_history) elif args[0] == 'service_actions.js': result = filterforms.get_service_actions_javascript( cherrypy.session.get("Logger")) return result return super(ADIF, self).default(*args, **kwd)
def use_future_expires(): """ Convenience method for setting cherrypy future expires headers. Will only enable futures expires headers if use_future_expires config is True. For full details see: http://www.mnot.net/cache_docs/ """ if cherrypy.config.get('use_future_expires', False): cherrypy.response.headers["Expires"] = http.HTTPDate(cherrypy.response.time + 31536000 ) # set expires 1 year ahead cherrypy.response.headers["cache-control"] = 'public, max-age=31536000' # 1 year
def expires(secs=0, force=False): """Tool for influencing cache mechanisms using the 'Expires' header. 'secs' must be either an int or a datetime.timedelta, and indicates the number of seconds between response.time and when the response should expire. The 'Expires' header will be set to (response.time + secs). If 'secs' is zero, the 'Expires' header is set one year in the past, and the following "cache prevention" headers are also set: 'Pragma': 'no-cache' 'Cache-Control': 'no-cache, must-revalidate' If 'force' is False (the default), the following headers are checked: 'Etag', 'Last-Modified', 'Age', 'Expires'. If any are already present, none of the above response headers are set. """ response = cherrypy.response headers = response.headers cacheable = False if not force: # some header names that indicate that the response can be cached for indicator in ('Etag', 'Last-Modified', 'Age', 'Expires'): if indicator in headers: cacheable = True break if not cacheable: if isinstance(secs, datetime.timedelta): secs = (86400 * secs.days) + secs.seconds if secs == 0: if force or "Pragma" not in headers: headers["Pragma"] = "no-cache" if cherrypy.request.protocol >= (1, 1): if force or "Cache-Control" not in headers: headers["Cache-Control"] = "no-cache, must-revalidate" # Set an explicit Expires date in the past. expiry = http.HTTPDate(1169942400.0) else: expiry = http.HTTPDate(response.time + secs) if force or "Expires" not in headers: headers["Expires"] = expiry
def run(self, method, path, query_string, protocol, headers, rfile): cherrypy.response.status = "204 No Content" cherrypy.response.header_list = [ ("Content-Type", 'text/html'), ("Server", "Null CherryPy"), ("Date", http.HTTPDate()), ("Content-Length", "0"), ] cherrypy.response.body = [""] return cherrypy.response
def __init__(self): self.status = None self.header_list = None self._body = [] self.time = time.time() self.headers = http.HeaderMap() # Since we know all our keys are titled strings, we can # bypass HeaderMap.update and get a big speed boost. dict.update(self.headers, { "Content-Type": 'text/html', "Server": "CherryPy/" + cherrypy.__version__, "Date": http.HTTPDate(self.time), }) self.cookie = Cookie.SimpleCookie()
def set_cache_level(cache_level, response): ''' Sets the HTTP caching headers to a preset configuration. Returns either the original response or None. cache_level 'never': explicit defeat of client-side caching 'etag': applies an ETag header by MD5 hashing the body 'always': sets max caching Returns either the given response or None. Returns None if the cache_level is set to 'etag' and a hash of the given response matches the If-None-Match header in the request. Herein lies another fantastic IE quirk, this time relating to the following combination: SSL webserver, IE client, HTTP request from Flash/ActionScript. The 'Cache-Control' header *must* begin with 'no-store', otherwise Flash will error out with the ever helpful, "IO Error #2032". One is free to append any other header one wishes after the 'no-store'. Usage: return util.set_cache_level('etag', response) ''' if cache_level == 'never': cherrypy.response.headers['Cache-Control'] = 'no-store, max-age=0, no-cache, must-revalidate' cherrypy.response.headers['Expires'] = 'Thu, 26 Oct 1978 00:00:00 GMT' elif cache_level == 'etag': # ie6 requires max-age=0 to ensure etag validation is performed otherwise it will not make a request if is_ie(): cherrypy.response.headers['Cache-Control'] = 'max-age=0, must-revalidate, no-cache' # immediately return 304 with empty body if etag matches if apply_etag(response): return None elif cache_level == 'always': # set 1 year ahead cherrypy.response.headers['Cache-Control'] = 'max-age=31536000' cherrypy.response.headers['Expires'] = http.HTTPDate(cherrypy.response.time + 31536000) else: raise ValueError, 'Unrecognized cache level: %s' % cache_level return response
def set_response_cookie(path=None, path_header=None, name='session_id', timeout=60, domain=None, secure=False, httponly=False): """Set a response cookie for the client. path: the 'path' value to stick in the response cookie metadata. path_header: if 'path' is None (the default), then the response cookie 'path' will be pulled from request.headers[path_header]. name: the name of the cookie. timeout: the expiration timeout for the cookie. domain: the cookie domain. secure: if False (the default) the cookie 'secure' value will not be set. If True, the cookie 'secure' value will be set (to 1). httponly: If False (the default) the cookie 'httponly' value will not be set. If True, the cookie 'httponly' value will be set (to 1). """ # Set response cookie cookie = cherrypy.response.cookie cookie[name] = cherrypy.serving.session.id cookie[name]['path'] = (path or cherrypy.request.headers.get(path_header) or '/') # We'd like to use the "max-age" param as indicated in # http://www.faqs.org/rfcs/rfc2109.html but IE doesn't # save it to disk and the session is lost if people close # the browser. So we have to use the old "expires" ... sigh ... ## cookie[name]['max-age'] = timeout * 60 if timeout: #cookie[name]['expires'] = http.HTTPDate(time.time() + (timeout * 60)) # Replace Cherrypy's version of this so that cookies alwasy last for # 24 hours by default - Setting them to 1 hour causes problems for IE # users who's clocks are off from the server timeout = timeout * 60 # convert to seconds if timeout < 86400: timeout = 86400 # Cookies last at least 24 hours cookie[name]['expires'] = http.HTTPDate(time.time() + timeout) if domain is not None: cookie[name]['domain'] = domain if secure: cookie[name]['secure'] = 1 if httponly: cookie[name]['httponly'] = 1
path = os.path.join(config['vault'], str(flFile.id)) response = cherrypy.response try: st = os.stat(path) except OSError, ose: cherrypy.log.error("OSError while trying to serve file: %s" % str(ose)) raise cherrypy.NotFound() # Check if path is a directory. if stat.S_ISDIR(st.st_mode): # Let the caller deal with it as they like. raise cherrypy.NotFound() # Set the Last-Modified response header, so that # modified-since validation code can work. response.headers['Last-Modified'] = http.HTTPDate(st.st_mtime) #cptools.validate_since() if content_type is None: # Set content-type based on filename extension ext = "" i = flFile.name.rfind('.') if i != -1: ext = flFile.name[i:].lower() content_type = mimetypes.types_map.get(ext, "text/plain") response.headers['Content-Type'] = content_type if disposition is not None: cd = '%s; filename="%s"' % (disposition, flFile.name) response.headers["Content-Disposition"] = cd # Set Content-Length and use an iterable (file object) # this way CP won't load the whole file in memory
def a_gif(self): cherrypy.response.headers['Last-Modified'] = http.HTTPDate() return gif_bytes
def serve_file(path, content_type=None, disposition=None, name=None): """Set status, headers, and body in order to serve the given file. The Content-Type header will be set to the content_type arg, if provided. If not provided, the Content-Type will be guessed by the file extension of the 'path' argument. If disposition is not None, the Content-Disposition header will be set to "<disposition>; filename=<name>". If name is None, it will be set to the basename of path. If disposition is None, no Content-Disposition header will be written. """ response = cherrypy.response # If path is relative, users should fix it by making path absolute. # That is, CherryPy should not guess where the application root is. # It certainly should *not* use cwd (since CP may be invoked from a # variety of paths). If using tools.staticdir, you can make your relative # paths become absolute by supplying a value for "tools.staticdir.root". if not os.path.isabs(path): raise ValueError("'%s' is not an absolute path." % path) try: st = os.stat(path) except OSError: raise cherrypy.NotFound() # Check if path is a directory. if stat.S_ISDIR(st.st_mode): # Let the caller deal with it as they like. raise cherrypy.NotFound() # Set the Last-Modified response header, so that # modified-since validation code can work. response.headers['Last-Modified'] = http.HTTPDate(st.st_mtime) cptools.validate_since() if content_type is None: # Set content-type based on filename extension ext = "" i = path.rfind('.') if i != -1: ext = path[i:].lower() content_type = mimetypes.types_map.get(ext, "text/plain") response.headers['Content-Type'] = content_type if disposition is not None: if name is None: name = os.path.basename(path) cd = '%s; filename="%s"' % (disposition, name) response.headers["Content-Disposition"] = cd # Set Content-Length and use an iterable (file object) # this way CP won't load the whole file in memory c_len = st.st_size bodyfile = open(path, 'rb') # HTTP/1.0 didn't have Range/Accept-Ranges headers, or the 206 code if cherrypy.request.protocol >= (1, 1): response.headers["Accept-Ranges"] = "bytes" r = http.get_ranges(cherrypy.request.headers.get('Range'), c_len) if r == []: response.headers['Content-Range'] = "bytes */%s" % c_len message = "Invalid Range (first-byte-pos greater than Content-Length)" raise cherrypy.HTTPError(416, message) if r: if len(r) == 1: # Return a single-part response. start, stop = r[0] if stop > c_len: stop = c_len r_len = stop - start response.status = "206 Partial Content" response.headers['Content-Range'] = ("bytes %s-%s/%s" % (start, stop - 1, c_len)) response.headers['Content-Length'] = r_len bodyfile.seek(start) response.body = file_generator_limited(bodyfile, r_len) else: # Return a multipart/byteranges response. response.status = "206 Partial Content" import mimetools boundary = mimetools.choose_boundary() ct = "multipart/byteranges; boundary=%s" % boundary response.headers['Content-Type'] = ct if response.headers.has_key("Content-Length"): # Delete Content-Length header so finalize() recalcs it. del response.headers["Content-Length"] def file_ranges(): # Apache compatibility: yield "\r\n" for start, stop in r: yield "--" + boundary yield "\r\nContent-type: %s" % content_type yield ("\r\nContent-range: bytes %s-%s/%s\r\n\r\n" % (start, stop - 1, c_len)) bodyfile.seek(start) for chunk in file_generator_limited( bodyfile, stop - start): yield chunk yield "\r\n" # Final boundary yield "--" + boundary + "--" # Apache compatibility: yield "\r\n" response.body = file_ranges() return response.body response.headers['Content-Length'] = c_len response.body = bodyfile return response.body
def init(storage_type='ram', path=None, path_header=None, name='session_id', timeout=60, domain=None, secure=False, clean_freq=5, **kwargs): """Initialize session object (using cookies). storage_type: one of 'ram', 'file', 'postgresql'. This will be used to look up the corresponding class in cherrypy.lib.sessions globals. For example, 'file' will use the FileSession class. path: the 'path' value to stick in the response cookie metadata. path_header: if 'path' is None (the default), then the response cookie 'path' will be pulled from request.headers[path_header]. name: the name of the cookie. timeout: the expiration timeout for the cookie. domain: the cookie domain. secure: if False (the default) the cookie 'secure' value will not be set. If True, the cookie 'secure' value will be set (to 1). clean_freq (minutes): the poll rate for expired session cleanup. Any additional kwargs will be bound to the new Session instance, and may be specific to the storage type. See the subclass of Session you're using for more information. """ request = cherrypy.request # Guard against running twice if hasattr(request, "_session_init_flag"): return request._session_init_flag = True # Check if request came with a session ID id = None if name in request.cookie: id = request.cookie[name].value # Create and attach a new Session instance to cherrypy._serving. # It will possess a reference to (and lock, and lazily load) # the requested session data. storage_class = storage_type.title() + 'Session' kwargs['timeout'] = timeout kwargs['clean_freq'] = clean_freq cherrypy._serving.session = sess = globals()[storage_class](id, **kwargs) if not hasattr(cherrypy, "session"): cherrypy.session = cherrypy._ThreadLocalProxy('session') if hasattr(sess, "setup"): sess.setup() # Set response cookie cookie = cherrypy.response.cookie cookie[name] = sess.id cookie[name]['path'] = path or request.headers.get(path_header) or '/' # We'd like to use the "max-age" param as indicated in # http://www.faqs.org/rfcs/rfc2109.html but IE doesn't # save it to disk and the session is lost if people close # the browser. So we have to use the old "expires" ... sigh ... ## cookie[name]['max-age'] = timeout * 60 if timeout: cookie[name]['expires'] = http.HTTPDate(time.time() + (timeout * 60)) if domain is not None: cookie[name]['domain'] = domain if secure: cookie[name]['secure'] = 1
def staticdirindex(section, dir, root="", match="", content_types=None, index="", indexlistermatch="", indexlister=None, **kwargs): """Serve a directory index listing for a dir. Compatibility alert: staticdirindex is built on and is dependent on staticdir and its configurations. staticdirindex only works effectively in locations where staticdir is also configured. staticdirindex is coded to allow easy integration with staticdir, if demand warrants. indexlister must be configured, or no function is performed. indexlister should be a callable that accepts the following parameters: section: same as for staticdir (and implicitly calculated for it) dir: same as for staticdir, but already combined with root path: combination of section and dir Other parameters that are configured for staticdirindex will be passed on to indexlister. Should use priorty > than that of staticdir, so that only directories not served by staticdir, call staticdirindex. """ # first call old staticdir, and see if it does anything sdret = staticdir(section, dir, root, match, content_types, index) if sdret: return True # if not, then see if we are configured to do anything if indexlister is None: return False req = cherrypy.request response = cherrypy.response match = indexlistermatch # N.B. filename ending in a slash or not does not imply a directory # the following block of code directly copied from static.py staticdir if match and not re.search(match, cherrypy.request.path_info): return False # Allow the use of '~' to refer to a user's home directory. dir = os.path.expanduser(dir) # If dir is relative, make absolute using "root". if not os.path.isabs(dir): if not root: msg = "Static dir requires an absolute dir (or root)." raise ValueError(msg) dir = os.path.join(root, dir) # Determine where we are in the object tree relative to 'section' # (where the static tool was defined). if section == 'global': section = "/" section = section.rstrip(r"\/") branch = cherrypy.request.path_info[len(section) + 1:] branch = urllib.unquote(branch.lstrip(r"\/")) # If branch is "", filename will end in a slash filename = os.path.join(dir, branch) # There's a chance that the branch pulled from the URL might # have ".." or similar uplevel attacks in it. Check that the final # filename is a child of dir. if not os.path.normpath(filename).startswith(os.path.normpath(dir)): raise cherrypy.HTTPError(403) # Forbidden # the above block of code directly copied from static.py staticdir # N.B. filename ending in a slash or not does not imply a directory # Check if path is a directory. path = filename # The following block of code copied from static.py serve_file # If path is relative, users should fix it by making path absolute. # That is, CherryPy should not guess where the application root is. # It certainly should *not* use cwd (since CP may be invoked from a # variety of paths). If using tools.static, you can make your relative # paths become absolute by supplying a value for "tools.static.root". if not os.path.isabs(path): raise ValueError("'%s' is not an absolute path." % path) try: st = os.stat(path) except OSError: # The above block of code copied from static.py serve_file return False if stat.S_ISDIR(st.st_mode): # Set the Last-Modified response header, so that # modified-since validation code can work. response.headers['Last-Modified'] = http.HTTPDate(st.st_mtime) cptools.validate_since() response.body = indexlister(section=section, dir=dir, path=path, **kwargs) response.headers['Content-Type'] = 'text/html' req.is_index = True return True return False