<commit_before># Module:   dispatcher
# Date:     13th September 2007
# Author:   <NAME>, prologic at shortcircuit dot net dot au

"""Dispatchers

This module implements URL dispatchers.
"""

import os
import warnings
import xmlrpclib
from urlparse import urljoin as _urljoin

try:
    import json
    HAS_JSON = 2
except ImportError:
    try:
        import simplejson as json
        HAS_JSON = 1
    except ImportError:
        HAS_JSON = 0
        warnings.warn("No json support available.")

from circuits import handler, Event, Component

from core import Controller
from errors import HTTPError
from cgifs import FieldStorage
from tools import expires, serve_file
from utils import parseQueryString, dictform

class RPC(Event): pass


class Static(Component):

    channel = "web"

    def __init__(self, path=None, docroot=None, defaults=("index.html",)):
        super(Static, self).__init__()

        self.path = path
        self.docroot = docroot or os.getcwd()
        self.defaults = defaults

    @handler("request", filter=True, priority=0.9)
    def request(self, event, request, response):
        if self.path is not None and not request.path.startswith(self.path):
            return

        req = event
        path = request.path

        if self.path is not None:
            path = path[len(self.path):]
        path = path.strip("/")

        filename = None

        if path:
            filename = os.path.abspath(os.path.join(self.docroot, path))
        else:
            for default in self.defaults:
                filename = os.path.abspath(os.path.join(self.docroot, default))
                if os.path.exists(filename):
                    break

        if filename and os.path.exists(filename):
            expires(request, response, 3600*24*30)
            return serve_file(request, response, filename)

class Dispatcher(Component):

    channel = "web"

    def __init__(self, **kwargs):
        super(Dispatcher, self).__init__(**kwargs)

        self.paths = []

    def _parseBody(self, request, response, params):
        body = request.body
        headers = request.headers

        if "Content-Type" not in headers:
            headers["Content-Type"] = ""

        try:
            form = FieldStorage(fp=body,
                headers=headers,
                environ={"REQUEST_METHOD": "POST"},
                keep_blank_values=True)
        except Exception, e:
            if e.__class__.__name__ == 'MaxSizeExceeded':
                # Post data is too big
                return HTTPError(request, response, 413)
            else:
                raise

        if form.file:
            request.body = form.file
        else:
            params.update(dictform(form))

        return True

    def _getChannel(self, request):
        """_getChannel(request) -> channel

        Find and return an appropriate channel for the given request.

        The channel is found by traversing the system's event channels,
        and matching path components to successive channels in the system.

        If a channel cannot be found for a given path, but there is
        a default channel, then this will be used.
        """

        path = request.path

        method = request.method.upper()
        request.index = request.path.endswith("/")

        names = [x for x in path.strip("/").split("/") if x]

        if not names:
            for default in ("index", method, "default"):
                k = ("/", default)
                if k in self.channels:
                    return default, "/", []
            return None, None, []

        i = 0
        matches = [""]
        candidates = []
        while i <= len(names):
            x = "/".join(matches) or "/"
            if x in self.paths:
                candidates.append([i, x])
                if i < len(names):
                    matches.append(names[i])
            else:
                break
            i += 1

        if not candidates:
            return None, None, []

        vpath = []
        channel = None
        for i, candidate in reversed(candidates):
            if i < len(names):
                channels = [names[i], "index", method, "default"]
            else:
                channels = ["index", method, "default"]

            found = False
            for channel in channels:
                if (candidate, channel) in self.channels:
                    if i < len(names) and channel == names[i]:
                        i += 1
                    found = True
                    break

            if found:
                if channel == "index" and not request.index:
                    continue
                else:
                    break

        if channel is not None:
            if i < len(names):
                vpath = [x.replace("%2F", "/") for x in names[i:]]
            else:
                vpath = []

        if not (candidate, channel) in self.channels:
            return None, None, []
        else:
            handler = self.channels[(candidate, channel)][0]
            if vpath and not (handler.args or handler.varargs or handler.varkw):
                return None, None, []
            else:
                return channel, candidate, vpath

    @handler("registered", target="*")
    def registered(self, c, m):
        if isinstance(c, Controller) and c not in self.components:
            self.paths.append(c.channel)
            c.unregister()
            self += c

    @handler("unregistered", target="*")
    def unregistered(self, c, m):
        if isinstance(c, Controller) and c in self.components and m == self:
            self.paths.remove(c.channel)

    @handler("request", filter=True, priority=0.1)
    def request(self, event, request, response):
        req = event

        channel, target, vpath = self._getChannel(request)

        if channel and target:
            req.kwargs = parseQueryString(request.qs)
            v = self._parseBody(request, response, req.kwargs)
            if not v:
                return v # MaxSizeExceeded (return the HTTPError)

            if vpath:
                req.args += tuple(vpath)<commit_msg>circutis.web.dispatchers: By using a set for the set of possible paths (targets) and adding a default of '/' ensures that all possible paths can be traversed and matching channels found. (Fixes issue #7)<commit_after># Module:   dispatcher
# Date:     13th September 2007
# Author:   <NAME>, prologic at shortcircuit dot net dot au

"""Dispatchers

This module implements URL dispatchers.
"""

import os
import warnings
import xmlrpclib
from urlparse import urljoin as _urljoin

try:
    import json
    HAS_JSON = 2
except ImportError:
    try:
        import simplejson as json
        HAS_JSON = 1
    except ImportError:
        HAS_JSON = 0
        warnings.warn("No json support available.")

from circuits import handler, Event, Component

from core import Controller
from errors import HTTPError
from cgifs import FieldStorage
from tools import expires, serve_file
from utils import parseQueryString, dictform

class RPC(Event): pass


class Static(Component):

    channel = "web"

    def __init__(self, path=None, docroot=None, defaults=("index.html",)):
        super(Static, self).__init__()

        self.path = path
        self.docroot = docroot or os.getcwd()
        self.defaults = defaults

    @handler("request", filter=True, priority=0.9)
    def request(self, event, request, response):
        if self.path is not None and not request.path.startswith(self.path):
            return

        req = event
        path = request.path

        if self.path is not None:
            path = path[len(self.path):]
        path = path.strip("/")

        filename = None

        if path:
            filename = os.path.abspath(os.path.join(self.docroot, path))
        else:
            for default in self.defaults:
                filename = os.path.abspath(os.path.join(self.docroot, default))
                if os.path.exists(filename):
                    break

        if filename and os.path.exists(filename):
            expires(request, response, 3600*24*30)
            return serve_file(request, response, filename)

class Dispatcher(Component):

    channel = "web"

    def __init__(self, **kwargs):
        super(Dispatcher, self).__init__(**kwargs)

        self.paths = set(["/"])

    def _parseBody(self, request, response, params):
        body = request.body
        headers = request.headers

        if "Content-Type" not in headers:
            headers["Content-Type"] = ""

        try:
            form = FieldStorage(fp=body,
                headers=headers,
                environ={"REQUEST_METHOD": "POST"},
                keep_blank_values=True)
        except Exception, e:
            if e.__class__.__name__ == 'MaxSizeExceeded':
                # Post data is too big
                return HTTPError(request, response, 413)
            else:
                raise

        if form.file:
            request.body = form.file
        else:
            params.update(dictform(form))

        return True

    def _getChannel(self, request):
        """_getChannel(request) -> channel

        Find and return an appropriate channel for the given request.

        The channel is found by traversing the system's event channels,
        and matching path components to successive channels in the system.

        If a channel cannot be found for a given path, but there is
        a default channel, then this will be used.
        """

        path = request.path

        method = request.method.upper()
        request.index = request.path.endswith("/")

        names = [x for x in path.strip("/").split("/") if x]

        if not names:
            for default in ("index", method, "default"):
                k = ("/", default)
                if k in self.channels:
                    return default, "/", []
            return None, None, []

        i = 0
        matches = [""]
        candidates = []
        while i <= len(names):
            x = "/".join(matches) or "/"
            if x in self.paths:
                candidates.append([i, x])
                if i < len(names):
                    matches.append(names[i])
            else:
                break
            i += 1

        if not candidates:
            return None, None, []

        vpath = []
        channel = None
        for i, candidate in reversed(candidates):
            if i < len(names):
                channels = [names[i], "index", method, "default"]
            else:
                channels = ["index", method, "default"]

            found = False
            for channel in channels:
                if (candidate, channel) in self.channels:
                    if i < len(names) and channel == names[i]:
                        i += 1
                    found = True
                    break

            if found:
                if channel == "index" and not request.index:
                    continue
                else:
                    break

        if channel is not None:
            if i < len(names):
                vpath = [x.replace("%2F", "/") for x in names[i:]]
            else:
                vpath = []

        if not (candidate, channel) in self.channels:
            return None, None, []
        else:
            handler = self.channels[(candidate, channel)][0]
            if vpath and not (handler.args or handler.varargs or handler.varkw):
                return None, None, []
            else:
                return channel, candidate, vpath

    @handler("registered", target="*")
    def registered(self, c, m):
        if isinstance(c, Controller) and c not in self.components:
            self.paths.add(c.channel)
            c.unregister()
            self += c

    @handler("unregistered", target="*")
    def unregistered(self, c, m):
        if isinstance(c, Controller) and c in self.components and m == self:
            self.paths.remove(c.channel)

    @handler("request", filter=True, priority=0.1)
    def request(self, event, request, response):
        req = event

        channel, target, vpath = self._getChannel(request)

        if channel and target:
            req.kwargs = parseQueryString(request.qs)
            v = self._parseBody(request, response, req.kwargs)
            if not v:
                return v # MaxSizeExceeded (return the HTTPError)

            if vpath:
                req.args += tuple(vpath)
{'fraction_non_alphanumeric': 0.09829367940398942, 'fraction_numerical': 0.004726427942001121, 'mean_word_length': 1.717457553330431, 'pattern_counts': {'":': 2, '<': 15, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2822032', 'n_tokens_mistral': 3411, 'n_tokens_neox': 3216, 'n_words': 1061}