Exemple #1
0
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
Exemple #2
0
    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)
Exemple #3
0
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
Exemple #6
0
 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()
Exemple #7
0
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
Exemple #8
0
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
Exemple #10
0
 def a_gif(self):
     cherrypy.response.headers['Last-Modified'] = http.HTTPDate()
     return gif_bytes
Exemple #11
0
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
Exemple #12
0
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
Exemple #13
0
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