⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dibbler.py

📁 用python实现的邮件过滤器
💻 PY
📖 第 1 页 / 共 3 页
字号:
           (or a `socketMap` argument for pure asyncore listeners).  The           incoming socket will be prepended to this list, and passed as the           first argument.  See `HTTPServer` for an example.         o socketMap: Optional.  The asyncore socket map to use.  If you're           using a `Dibbler.Context`, pass context._map.        See `HTTPServer` for an example `Listener` - it's a good deal smaller        than this description!"""        asyncore.dispatcher.__init__(self, map=socketMap)        self.socketMap = socketMap        self.factory = factory        self.factoryArgs = factoryArgs        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)        s.setblocking(False)        self.set_socket(s, self.socketMap)        self.set_reuse_addr()        if type(port) != type(()):            port = ('', port)        self.bind(port)        self.listen(5)    def handle_accept(self):        """Asyncore override."""        # If an incoming connection is instantly reset, eg. by following a        # link in the web interface then instantly following another one or        # hitting stop, handle_accept() will be triggered but accept() will        # return None.        result = self.accept()        if result:            clientSocket, clientAddress = result            args = [clientSocket] + list(self.factoryArgs)            self.factory(*args)class HTTPServer(Listener):    """A web server with which you can register `HTTPPlugin`s to serve up    your content - see `HTTPPlugin` for detailed documentation and examples.    `port` specifies the TCP/IP (address, port) on which to run, defaulting    to ('', 80).    `context` optionally specifies a `Dibbler.Context` for the server.    """    NO_AUTHENTICATION     = "None"    BASIC_AUTHENTICATION  = "Basic"    DIGEST_AUTHENTICATION = "Digest"    def __init__(self, port=('', 80), context=_defaultContext):        """Create an `HTTPServer` for the given port."""        Listener.__init__(self, port, _HTTPHandler,                          (self, context), context._map)        self._plugins = []        try:            context._HTTPPort = port[1]        except TypeError:            context._HTTPPort = port    def register(self, *plugins):        """Registers one or more `HTTPPlugin`-derived objects with the        server."""        for plugin in plugins:            self._plugins.append(plugin)    def requestAuthenticationMode(self):        """Override: HTTP Authentication. It should return a value among        NO_AUTHENTICATION, BASIC_AUTHENTICATION and DIGEST_AUTHENTICATION.        The two last values will force HTTP authentication respectively        through Base64 and MD5 encodings."""        return self.NO_AUTHENTICATION    def isValidUser(self, name, password):        """Override: Return True for authorized logins."""        return True    def getPasswordForUser(self, name):        """Override: Return the password associated to the specified user        name."""        return ''    def getRealm(self):        """Override: Specify the HTTP authentication realm."""        return "Dibbler application server"    def getCancelMessage(self):        """Override: Specify the cancel message for an HTTP Authentication."""        return "You must log in."class _HTTPHandler(BrighterAsyncChat):    """This is a helper for the HTTP server class - one of these is created    for each incoming request, and does the job of decoding the HTTP traffic    and driving the plugins."""    # RE to extract option="value" fields from    # digest auth login field    _login_splitter = re.compile('([a-zA-Z]+)=(".*?"|.*?),?')    def __init__(self, clientSocket, server, context):        # Grumble: asynchat.__init__ doesn't take a 'map' argument,        # hence the two-stage construction.        BrighterAsyncChat.__init__(self, map=context._map)        BrighterAsyncChat.set_socket(self, clientSocket, context._map)        self._context = context        self._server = server        self._request = ''        self.set_terminator('\r\n\r\n')        # Because a methlet is likely to call `writeOKHeaders` before doing        # anything else, an unexpected exception won't send back a 500, which        # is poor.  So we buffer any sent headers until either a plain `write`        # happens or the methlet returns.        self._bufferedHeaders = []        self._headersWritten = False        # Tell the plugins about the connection, letting them veto it.        for plugin in self._server._plugins:            if not plugin.onIncomingConnection(clientSocket):                self.close()    def collect_incoming_data(self, data):        """Asynchat override."""        self._request = self._request + data    def found_terminator(self):        """Asynchat override."""        # Parse the HTTP request.        requestLine, headers = (self._request+'\r\n').split('\r\n', 1)        try:            method, url, version = requestLine.strip().split()        except ValueError:            self.writeError(400, "Malformed request: '%s'" % requestLine)            self.close_when_done()            return        # Parse the URL, and deal with POST vs. GET requests.        method = method.upper()        unused, unused, path, unused, query, unused = urlparse.urlparse(url)        cgiParams = cgi.parse_qs(query, keep_blank_values=True)        if self.get_terminator() == '\r\n\r\n' and method == 'POST':            # We need to read the body - set a numeric async_chat terminator            # equal to the Content-Length.            match = re.search(r'(?i)content-length:\s*(\d+)', headers)            contentLength = int(match.group(1))            if contentLength > 0:                self.set_terminator(contentLength)                self._request = self._request + '\r\n\r\n'                return        # Have we just read the body of a POSTed request?  Decode the body,        # which will contain parameters and possibly uploaded files.        if type(self.get_terminator()) is type(1):            self.set_terminator('\r\n\r\n')            body = self._request.split('\r\n\r\n', 1)[1]            match = re.search(r'(?i)content-type:\s*([^\r\n]+)', headers)            contentTypeHeader = match.group(1)            contentType, pdict = cgi.parse_header(contentTypeHeader)            if contentType == 'multipart/form-data':                # multipart/form-data - probably a file upload.                bodyFile = StringIO.StringIO(body)                cgiParams.update(cgi.parse_multipart(bodyFile, pdict))            else:                # A normal x-www-form-urlencoded.                cgiParams.update(cgi.parse_qs(body, keep_blank_values=True))        # Convert the cgi params into a simple dictionary.        params = {}        for name, value in cgiParams.iteritems():            params[name] = value[0]        # Parse the headers.        headersRegex = re.compile('([^:]*):\s*(.*)')        headersDict = dict([headersRegex.match(line).groups(2)                           for line in headers.split('\r\n')                           if headersRegex.match(line)])        # HTTP Basic/Digest Authentication support.        serverAuthMode = self._server.requestAuthenticationMode()        if serverAuthMode != HTTPServer.NO_AUTHENTICATION:            # The server wants us to authenticate the user.            authResult = False            authHeader = headersDict.get('Authorization')            if authHeader:                authMatch = re.search('(\w+)\s+(.*)', authHeader)                authenticationMode, login = authMatch.groups()                if authenticationMode == HTTPServer.BASIC_AUTHENTICATION:                    authResult = self._basicAuthentication(login)                elif authenticationMode == HTTPServer.DIGEST_AUTHENTICATION:                    authResult = self._digestAuthentication(login, method)                else:                    print >>sys.stdout, "Unknown mode: %s" % authenticationMode            if not authResult:                self.writeUnauthorizedAccess(serverAuthMode)        # Find and call the methlet.  '/eggs.gif' becomes 'onEggsGif'.        if path == '/':            path = '/Home'        pieces = path[1:].split('.')        name = 'on' + ''.join([piece.capitalize() for piece in pieces])        for plugin in self._server._plugins:            if hasattr(plugin, name):                # The plugin's APIs (`write`, etc) reflect back to us via                # `plugin._handler`.                plugin._handler = self                try:                    # Call the methlet.                    getattr(plugin, name)(**params)                    if self._bufferedHeaders:                        # The methlet returned without writing anything other                        # than headers.  This isn't unreasonable - it might                        # have written a 302 or something.  Flush the buffered                        # headers                        self.write(None)                except:                    # The methlet raised an exception - send the traceback to                    # the browser, unless it's SystemExit in which case we let                    # it go.                    eType, eValue, eTrace = sys.exc_info()                    if eType == SystemExit:                        # Close all the listeners so that no further incoming                        # connections appear.                        contextMap = self._context._map                        for dispatcher in contextMap.values():                            if isinstance(dispatcher, Listener):                                dispatcher.close()                        # Let any existing connections close down first.  This                        # has happened when all we have left are _HTTPHandlers                        # (this one plus any others that are using keep-alive;                        # none of the others can be actually doing any work                        # because *we're* the one doing the work).                        def isProtected(dispatcher):                            return not isinstance(dispatcher, _HTTPHandler)                        while len(filter(isProtected, contextMap.values())) > 0:                            asyncore.poll(timeout=1, map=contextMap)                        raise SystemExit                    message = """<h3>500 Server error</h3><pre>%s</pre>"""                    details = traceback.format_exception(eType, eValue, eTrace)                    details = '\n'.join(details)                    self.writeError(500, message % cgi.escape(details))                plugin._handler = None                break        else:            self.onUnknown(path, params)        # `close_when_done` and `Connection: close` ensure that we don't        # support keep-alives or pipelining.  There are problems with some        # browsers, for instance with extra characters being appended after        # the body of a POSTed request.        self.close_when_done()    def onUnknown(self, path, params):        """Handler for unknown URLs.  Returns a 404 page."""        self.writeError(404, "Not found: '%s'" % path)    def writeOKHeaders(self, contentType, extraHeaders={}):        """Reflected from `HTTPPlugin`s."""        # Buffer the headers until there's a `write`, in case an error occurs.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -