Пример #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. If 0 or other boolean
        False, no 'expires' param will be set, and the cookie will be a
        "session cookie" which expires when the browser is closed.
    
    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).
    
    """
    cookie = cherrypy.serving.response.cookie
    cookie[name] = cherrypy.serving.session.id
    cookie[name]['path'] = path or cherrypy.serving.request.headers.get(path_header) or '/'
    if timeout:
        e = time.time() + timeout * 60
        cookie[name]['expires'] = httputil.HTTPDate(e)
    if domain is not None:
        cookie[name]['domain'] = domain
    if secure:
        cookie[name]['secure'] = 1
Пример #2
0
 def a_gif(self):
     cherrypy.response.headers['Last-Modified'] = httputil.HTTPDate(
     )
     return gif_bytes
Пример #3
0
def serve_file(path, content_type=None, disposition=None, name=None,
               debug=False):
    """Set status, headers, and body in order to serve the given path.

    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.serving.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):
        msg = "'%s' is not an absolute path." % path
        if debug:
            cherrypy.log(msg, 'TOOLS.STATICFILE')
        raise ValueError(msg)

    try:
        st = os.stat(path)
    except (OSError, TypeError, ValueError):
        # OSError when file fails to stat
        # TypeError on Python 2 when there's a null byte
        # ValueError on Python 3 when there's a null byte
        if debug:
            cherrypy.log('os.stat(%r) failed' % path, 'TOOLS.STATIC')
        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.
        if debug:
            cherrypy.log('%r is a directory' % path, 'TOOLS.STATIC')
        raise cherrypy.NotFound()

    # Set the Last-Modified response header, so that
    # modified-since validation code can work.
    response.headers['Last-Modified'] = httputil.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, None)
    if content_type is not None:
        response.headers['Content-Type'] = content_type
    if debug:
        cherrypy.log('Content-Type: %r' % content_type, 'TOOLS.STATIC')

    cd = None
    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
    if debug:
        cherrypy.log('Content-Disposition: %r' % cd, 'TOOLS.STATIC')

    # Set Content-Length and use an iterable (file object)
    #   this way CP won't load the whole file in memory
    content_length = st.st_size
    fileobj = open(path, 'rb')
    return _serve_fileobj(fileobj, content_type, content_length, debug=debug)
Пример #4
0
def expire():
    """Expire the current session cookie."""
    name = cherrypy.serving.request.config.get('tools.sessions.name', 'session_id')
    one_year = 31536000
    e = time.time() - one_year
    cherrypy.serving.response.cookie[name]['expires'] = httputil.HTTPDate(e)
Пример #5
0
    def serve_raw_file(self,
                       file,
                       content_type=None,
                       disposition=None,
                       name=None):
        # Adapted from CherryPy's serve_file(), modified to work with file-like
        # objects

        response = cherrypy.response
        st = None

        if isinstance(file, str):

            path = file

            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()

            if stat.S_ISDIR(st.st_mode):
                raise cherrypy.NotFound()

            response.headers['Last-Modified'] = httputil.HTTPDate(st.st_mtime)
            cptools.validate_since()
            file = open(path, "rb")
        else:
            path = getattr(file, "name", None)
            if path:
                try:
                    st = os.stat(path)
                except OSError:
                    pass
            else:
                if not hasattr(file, "read"):
                    raise ValueError(
                        "Expected a file-like object, got %r instead "
                        "(object has no read() method)" % file)
                if not hasattr(file, "seek"):
                    raise ValueError("Can't serve file-like object %r "
                                     "(object has no seek() method)" % file)
                if not hasattr(file, "tell"):
                    raise ValueError("Can't serve file-like object %r "
                                     "(object has no tell() method)" % file)

        # Set the content type
        if content_type is None:

            if path:
                content_type = mimetypes.guess_type(path)[0]

            if not content_type:
                content_type = "text/plain"

        response.headers["Content-Type"] = content_type

        # Set the content disposition
        if disposition is not None:
            cd = disposition
            if not name and path:
                name = os.path.basename(path)
            if name:
                cd = rfc6266.build_header(name, cd)
            response.headers["Content-Disposition"] = cd

        if self.use_xsendfile and path:
            response.headers["X-Sendfile"] = path
            return ""

        # Find the size of the file
        if st is None:
            start = file.tell()
            file.seek(0, 2)  # Move to the end of the file
            c_len = file.tell() - start
            file.seek(start)
        else:
            c_len = st.st_size

        # 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 = httputil.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
                    file.seek(start)
                    response.body = file_generator_limited(file, 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 "Content-Length" in response.headers:
                        # 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))
                            file.seek(start)
                            for chunk in file_generator_limited(
                                    file, stop - start):
                                yield chunk
                            yield "\r\n"
                        # Final boundary
                        yield "--" + boundary + "--"

                        # Apache compatibility:
                        yield "\r\n"

                    response.body = file_ranges()
            else:
                response.headers['Content-Length'] = c_len
                response.body = file
        else:
            response.headers['Content-Length'] = c_len
            response.body = file

        return response.body
Пример #6
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.

"""
    req = cherrypy.request
    response = cherrypy.response
    
    user = req.login
    reponame = req.path_info.split("/")[1]
    if reponame not in ["info", "build", "buildlog"]:
        if reponame not in astrid.repos.sections():
                raise cherrypy.HTTPError(404)
            
        if user not in astrid.repos.get(reponame, "users"):
            raise cherrypy.HTTPError(401)


    match = indexlistermatch

    # 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

    # 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.parse.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("'{}' is not an absolute path.".format(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'] = httputil.HTTPDate(st.st_mtime)
        cptools.validate_since()
        response.body = indexlister( section=section, dir=dir, path=path,
                                     **kwargs ).encode()
        response.headers['Content-Type'] = 'text/html'
        req.is_index = True
        return True

    return False