<commit_before>import cherrypy
import os

import tangelo
import tangelo.server


# A function to run as a before_handler hook that examines a request path and
# "normalizes" it, either by appending a slash or "index.html", etc.
def treat_url():
    reqpath = cherrypy.request.path_info
    webroot = cherrypy.config.get("webroot")

    # Clear the thread storage.
    cherrypy.thread_data.target = None
    cherrypy.thread_data.do_auth = True

    # If the request path is blank, redirect to /.
    if reqpath == "":
        raise cherrypy.HTTPRedirect("/")

    # Compute "parallel" path component lists based on the web root and the
    # disk root.
    if reqpath == "/":
        reqpathcomp = []
        pathcomp = [webroot]
    else:
        # Split the request path into path components, omitting the leading
        # slash.
        reqpathcomp = reqpath[1:].split("/")

        # Compute the disk path the URL corresponds to.
        #
        # First check to see whether the path is absolute (i.e. rooted at
        # webroot) or in a user home directory.
        if reqpathcomp[0][0] == "~" and len(reqpathcomp[0]) > 1:
            # Only treat this component as a home directory if there is
            # actually text following the tilde (rather than making the server
            # serve files from the home directory of whatever user account it
            # is using to run).
            pathcomp = [os.path.expanduser(reqpathcomp[0]) +
                        os.path.sep +
                        "tangelo_html"] + reqpathcomp[1:]
        else:
            pathcomp = [webroot] + reqpathcomp

    # Save the request path and disk path components in the thread storage,
    # slightly modifying the request path if it refers to an absolute path
    # (indicated by being one element shorter than the disk path).
    if len(reqpathcomp) == len(pathcomp) - 1:
        reqpathcomp_save = [""] + reqpathcomp
    elif len(reqpathcomp) == len(pathcomp):
        reqpathcomp_save = ["/" + reqpathcomp[0]] + reqpathcomp[1:]
    else:
        raise RuntimeError("reqpathcomp and pathcomp lengths are wonky")

    # If the path represents a directory and has a trailing slash, remove it
    # (this will make the auth update step easier).
    if (len(reqpathcomp_save) > 1 and
            reqpathcomp_save[-1] == "" or
            pathcomp[-1] == ""):
        assert reqpathcomp_save[-1] == "" and pathcomp[-1] == ""
        reqpathcomp_save = reqpathcomp_save[:-1]
        pathcomp_save = pathcomp[:-1]
    else:
        pathcomp_save = pathcomp

    cherrypy.thread_data.reqpathcomp = reqpathcomp_save
    cherrypy.thread_data.pathcomp = pathcomp_save

    # If pathcomp has more than one element, fuse the first two together.  This
    # makes the search for a possible service below much simpler.
    if len(pathcomp) > 1:
        pathcomp = [pathcomp[0] + os.path.sep + pathcomp[1]] + pathcomp[2:]

    # Form an actual path string.
    path = os.path.sep.join(pathcomp)

    # If the path is a directory, check for a trailing slash.  If missing,
    # perform a redirect to the path WITH the trailing slash.  Otherwise, check
    # for an index.html file in that directory; if found, perform an internal
    # redirect to that file.  Otherwise, leave the path alone - it now
    # represents a request for a directory listing.
    #
    # If instead the path isn't a directory, check to see if it's a regular
    # file.  If it is, save the path in thread local storage - this will let
    # the handler very quickly serve the file.
    #
    # If it is not a regular file, then check to see if it is a python service.
    #
    # Finally, if it is none of the above, then indicate a 404 error.
    if os.path.isdir(path):
        if reqpath[-1] != "/":
            raise cherrypy.HTTPRedirect(reqpath + "/")
        elif os.path.exists(path + os.path.sep + "index.html"):
            raise cherrypy.InternalRedirect(reqpath + "index.html")
        else:
            cherrypy.thread_data.target = {"type": "dir",
                                           "path": path}
    elif os.path.exists(path):
        # Don't serve Python files (if someone really wants to serve the program
        # text, they can create a symlink with a different file extension and
        # that will be served just fine).
        if len(path) > 3 and path[-3:] == ".py":
            cherrypy.thread_data.target = {"type": "restricted",
                                           "path": path}
        else:
            # Also do not serve config files that match up to Python files.
            if (len(path) > 5 and
                    path[-5:] == ".json" and
                    os.path.exists(path[:-5] + ".py")):
                cherrypy.thread_data.target = {"type": "restricted",
                                               "path": path}
            else:
                cherrypy.thread_data.target = {"type": "file",
                                               "path": path}
    else:
        service_path = None
        pargs = None
        # for i, comp in enumerate(pathcomp):
        for i in range(len(pathcomp)):
            service_path = os.path.sep.join(pathcomp[:(i + 1)]) + ".py"
            if os.path.exists(service_path):
                pargs = pathcomp[(i + 1):]
                break

        if pargs is None:
            cherrypy.thread_data.target = {"type": "404",
                                           "path": path}
            cherrypy.thread_data.do_auth = False
        else:
            cherrypy.thread_data.target = {"type": "service",
                                           "path": service_path,
                                           "pargs": pargs}


class AuthUpdate(cherrypy.Tool):
    # A list of acceptable authentication types.
    allowed_auth_types = ["digest"]

    def __init__(self, point="before_handler", priority=50):
        # cherrypy.Tool attributes.
        self._name = None
        self._point = point
        self._priority = priority

        # A record of installed auth tools.<commit_msg>Separated "treat_url()" tool into a pure functional operation, combined with an "action" phase<commit_after>import cherrypy
import os

import tangelo
import tangelo.server


def analyze_url(reqpath, webroot):
    tangelo.log(reqpath)
    tangelo.log(webroot)

    target = None
    save_data = {"target": None,
                 "do_auth": True}

    # If the request path is blank, redirect to /.
    if reqpath == "":
        return {"action": "HTTPRedirect",
                "argument": "/",
                "save_data": save_data,
                "target": target}

    # Compute "parallel" path component lists based on the web root and the
    # disk root.
    if reqpath == "/":
        reqpathcomp = []
        pathcomp = [webroot]
    else:
        # Split the request path into path components, omitting the leading
        # slash.
        reqpathcomp = reqpath[1:].split("/")

        # Compute the disk path the URL corresponds to.
        #
        # First check to see whether the path is absolute (i.e. rooted at
        # webroot) or in a user home directory.
        if reqpathcomp[0][0] == "~" and len(reqpathcomp[0]) > 1:
            # Only treat this component as a home directory if there is
            # actually text following the tilde (rather than making the server
            # serve files from the home directory of whatever user account it
            # is using to run).
            pathcomp = [os.path.expanduser(reqpathcomp[0]) +
                        os.path.sep +
                        "tangelo_html"] + reqpathcomp[1:]
        else:
            pathcomp = [webroot] + reqpathcomp

    # Save the request path and disk path components in the thread storage,
    # slightly modifying the request path if it refers to an absolute path
    # (indicated by being one element shorter than the disk path).
    if len(reqpathcomp) == len(pathcomp) - 1:
        reqpathcomp_save = [""] + reqpathcomp
    elif len(reqpathcomp) == len(pathcomp):
        reqpathcomp_save = ["/" + reqpathcomp[0]] + reqpathcomp[1:]
    else:
        return {"action": "RuntimeError",
                "message": "reqpathcomp and pathcomp lengths are wonky",
                "save_data": save_data,
                "target": target}

    # If the path represents a directory and has a trailing slash, remove it
    # (this will make the auth update step easier).
    if (len(reqpathcomp_save) > 1 and
            reqpathcomp_save[-1] == "" or
            pathcomp[-1] == ""):
        assert reqpathcomp_save[-1] == "" and pathcomp[-1] == ""
        reqpathcomp_save = reqpathcomp_save[:-1]
        pathcomp_save = pathcomp[:-1]
    else:
        pathcomp_save = pathcomp

    save_data["reqpathcomp"] = reqpathcomp_save
    save_data["pathcomp"] = pathcomp_save

    # If pathcomp has more than one element, fuse the first two together.  This
    # makes the search for a possible service below much simpler.
    if len(pathcomp) > 1:
        pathcomp = [pathcomp[0] + os.path.sep + pathcomp[1]] + pathcomp[2:]

    # Form an actual path string.
    path = os.path.sep.join(pathcomp)

    # If the path is a directory, check for a trailing slash.  If missing,
    # perform a redirect to the path WITH the trailing slash.  Otherwise, check
    # for an index.html file in that directory; if found, perform an internal
    # redirect to that file.  Otherwise, leave the path alone - it now
    # represents a request for a directory listing.
    #
    # If instead the path isn't a directory, check to see if it's a regular
    # file.  If it is, save the path in thread local storage - this will let
    # the handler very quickly serve the file.
    #
    # If it is not a regular file, then check to see if it is a python service.
    #
    # Finally, if it is none of the above, then indicate a 404 error.
    if os.path.isdir(path):
        if reqpath[-1] != "/":
            return {"action": "HTTPRedirect",
                    "argument": reqpath + "/",
                    "save_data": save_data,
                    "target": target}
        elif os.path.exists(path + os.path.sep + "index.html"):
            return {"action": "InternalRedirect",
                    "argument": reqpath + "index.html",
                    "save_data": save_data,
                    "target": target}
        else:
            target = {"type": "dir",
                      "path": path}
    elif os.path.exists(path):
        # Don't serve Python files (if someone really wants to serve the program
        # text, they can create a symlink with a different file extension and
        # that will be served just fine).
        if len(path) > 3 and path[-3:] == ".py":
            target = {"type": "restricted",
                      "path": path}
        else:
            # Also do not serve config files that match up to Python files.
            if (len(path) > 5 and
                    path[-5:] == ".json" and
                    os.path.exists(path[:-5] + ".py")):
                target = {"type": "restricted",
                          "path": path}
            else:
                target = {"type": "file",
                          "path": path}
    else:
        service_path = None
        pargs = None
        # for i, comp in enumerate(pathcomp):
        for i in range(len(pathcomp)):
            service_path = os.path.sep.join(pathcomp[:(i + 1)]) + ".py"
            if os.path.exists(service_path):
                pargs = pathcomp[(i + 1):]
                break

        if pargs is None:
            target = {"type": "404",
                      "path": path}
            save_data["do_auth"] = False
        else:
            target = {"type": "service",
                      "path": service_path,
                      "pargs": pargs}

    return {"save_data": save_data,
            "target": target}


def treat_url():
    directive = analyze_url(cherrypy.request.path_info, cherrypy.config.get("webroot"))

    tangelo.log(str(directive))

    cherrypy.thread_data.target = directive["target"]
    cherrypy.thread_data.do_auth = directive["save_data"]["do_auth"]
    cherrypy.thread_data.reqpathcomp = directive["save_data"]["reqpathcomp"]
    cherrypy.thread_data.pathcomp = directive["save_data"]["pathcomp"]

    if "action" in directive:
        if directive["action"] == "HTTPRedirect":
            raise cherrypy.HTTPRedirect(directive["argument"])
        elif directive["action"] == "InternalRedirect":
            raise cherrypy.InternalRedirect(directive["argument"])
        else:
            raise RuntimeError("illegal action directive: '%s'" % (directive["action"]))


class AuthUpdate(cherrypy.Tool):
    # A list of acceptable authentication types.
    allowed_auth_types = ["digest"]

    def __init__(self, point="before_handler", priority=50):
        # cherrypy.Tool attributes.
        self._name = None
        self._point = point
        self._priority = priority

        # A record of installed auth tools.
{'fraction_non_alphanumeric': 0.10161166538756715, 'fraction_numerical': 0.0056792018419033, 'mean_word_length': 1.9963209933318005, 'pattern_counts': {'":': 56, '<': 3, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6151679', 'n_tokens_mistral': 3696, 'n_tokens_neox': 3526, 'n_words': 1230}