Example #1
0
def handle_return(req, return_contents):
    """
    Perform the "return" part of the response.
    This function returns the file or directory listing contained in
    req.path. Sets the HTTP response code in req, writes additional headers,
    and writes the HTTP response, if any.

    If return_contents is True, and the path is a non-directory, returns the
    contents of the file verbatim. If False, returns a directory listing
    with a single file, ".", and info about the file.

    If the path is a directory, return_contents is ignored.
    """

    path = studpath.to_home_path(req.path)

    # FIXME: What to do about req.path == ""?
    # Currently goes to 403 Forbidden.
    if path is None:
        req.status = req.HTTP_FORBIDDEN
        req.headers_out["X-IVLE-Return-Error"] = "Forbidden"
        req.write("Forbidden")
        return

    # If this is a repository-revision request, it needs to be treated
    # differently than if it were a regular file request.
    # Note: If there IS a revision requested but the file doesn't exist in
    # that revision, this will terminate.
    revision = _get_revision_or_die(req, svnclient, path)

    if revision is None:
        if not os.access(path, os.R_OK):
            req.status = req.HTTP_NOT_FOUND
            req.headers_out["X-IVLE-Return-Error"] = "File not found"
            req.write("File not found")
            return
        is_dir = os.path.isdir(path)
    else:
        is_dir = ivle.svn.revision_is_dir(svnclient, path, revision)

    if is_dir:
        # It's a directory. Return the directory listing.
        req.content_type = mime_dirlisting
        req.headers_out["X-IVLE-Return"] = "Dir"
        # TODO: Fix this dirty, dirty hack
        newjson = get_dirlisting(req, svnclient, path, revision)
        if "X-IVLE-Action-Error" in req.headers_out:
            newjson["Error"] = req.headers_out["X-IVLE-Action-Error"]
        req.write(json.dumps(newjson))
    elif return_contents:
        # It's a file. Return the file contents.
        # First get the mime type of this file
        (type, _) = mimetypes.guess_type(path)
        if type is None:
            type = ivle.mimetypes.DEFAULT_MIMETYPE
        req.content_type = type
        req.headers_out["X-IVLE-Return"] = "File"

        send_file(req, svnclient, path, revision)
    else:
        # It's a file. Return a "fake directory listing" with just this file.
        req.content_type = mime_dirlisting
        req.headers_out["X-IVLE-Return"] = "File"
        req.write(json.dumps(get_dirlisting(req, svnclient, path, revision)))
Example #2
0
def cgi_environ(req, script_path, user, overrides=None):
    """Gets CGI variables from apache and makes a few changes for security and 
    correctness.

    Does not modify req, only reads it.

    overrides: A dict mapping env var names to strings, to override arbitrary
        environment variables in the resulting CGI environent.
    """
    env = {}
    # Comments here are on the heavy side, explained carefully for security
    # reasons. Please read carefully before making changes.
    
    # This automatically asks mod_python to load up the CGI variables into the
    # environment (which is a good first approximation)
    for (k,v) in req.get_cgi_environ().items():
        env[k] = v

    # Remove DOCUMENT_ROOT and SCRIPT_FILENAME. Not part of CGI spec and
    # exposes unnecessary details about server.
    try:
        del env['DOCUMENT_ROOT']
    except: pass
    try:
        del env['SCRIPT_FILENAME']
    except: pass

    # Remove PATH. The PATH here is the path on the server machine; not useful
    # inside the jail. It may be a good idea to add another path, reflecting
    # the inside of the jail, but not done at this stage.
    try:
        del env['PATH']
    except: pass

    # CGI specifies that REMOTE_HOST SHOULD be set, and MAY just be set to
    # REMOTE_ADDR. Since Apache does not appear to set this, set it to
    # REMOTE_ADDR.
    if 'REMOTE_HOST' not in env and 'REMOTE_ADDR' in env:
        env['REMOTE_HOST'] = env['REMOTE_ADDR']

    env['PATH_INFO'] = ''
    del env['PATH_TRANSLATED']

    normuri = os.path.normpath(req.uri)
    env['SCRIPT_NAME'] = normuri

    # SCRIPT_NAME is the path to the script WITHOUT PATH_INFO.
    # We don't care about these if the script is null (ie. noop).
    # XXX: We check for /home because we don't want to interfere with
    # CGIRequest, which fileservice still uses.
    if script_path and script_path.startswith('/home'):
        normscript = os.path.normpath(script_path)

        uri_into_jail = studpath.to_home_path(os.path.normpath(req.path))

        # PATH_INFO is wrong because the script doesn't physically exist.
        env['PATH_INFO'] = uri_into_jail[len(normscript):]
        if len(env['PATH_INFO']) > 0:
            env['SCRIPT_NAME'] = normuri[:-len(env['PATH_INFO'])]

    # SERVER_SOFTWARE is actually not Apache but IVLE, since we are
    # custom-making the CGI request.
    env['SERVER_SOFTWARE'] = "IVLE/" + ivle.__version__

    # Additional environment variables
    username = user.login
    env['HOME'] = os.path.join('/home', username)

    if overrides is not None:
        env.update(overrides)
    return env