Example #1
0
class Element(Node):

    preserveCase = 0
    caseInsensitive = 1
    nsprefixes = None

    def __init__(self,
                 tagName,
                 attributes=None,
                 parentNode=None,
                 filename=None,
                 markpos=None,
                 caseInsensitive=1,
                 preserveCase=0,
                 namespace=None):
        Node.__init__(self, parentNode)
        self.preserveCase = preserveCase or not caseInsensitive
        self.caseInsensitive = caseInsensitive
        if not preserveCase:
            tagName = tagName.lower()
        if attributes is None:
            self.attributes = {}
        else:
            self.attributes = attributes
            for k, v in self.attributes.items():
                self.attributes[k] = unescape(v)

        if caseInsensitive:
            self.attributes = InsensitiveDict(self.attributes,
                                              preserve=preserveCase)

        self.endTagName = self.nodeName = self.tagName = tagName
        self._filename = filename
        self._markpos = markpos
        self.namespace = namespace

    def addPrefixes(self, pfxs):
        if self.nsprefixes is None:
            self.nsprefixes = pfxs
        else:
            self.nsprefixes.update(pfxs)

    def endTag(self, endTagName):
        if not self.preserveCase:
            endTagName = endTagName.lower()
        self.endTagName = endTagName

    def isEqualToElement(self, n):
        if self.caseInsensitive:
            return ((self.attributes == n.attributes)
                    and (self.nodeName.lower() == n.nodeName.lower()))
        return (self.attributes == n.attributes) and (self.nodeName
                                                      == n.nodeName)

    def isEqualToNode(self, other):
        """
        Compare this element to C{other}.  If the C{nodeName}, C{namespace},
        C{attributes}, and C{childNodes} are all the same, return C{True},
        otherwise return C{False}.
        """
        return (self.nodeName.lower() == other.nodeName.lower()
                and self.namespace == other.namespace
                and self.attributes == other.attributes
                and Node.isEqualToNode(self, other))

    def cloneNode(self, deep=0, parent=None):
        clone = Element(self.tagName,
                        parentNode=parent,
                        namespace=self.namespace,
                        preserveCase=self.preserveCase,
                        caseInsensitive=self.caseInsensitive)
        clone.attributes.update(self.attributes)
        if deep:
            clone.childNodes = [
                child.cloneNode(1, clone) for child in self.childNodes
            ]
        else:
            clone.childNodes = []
        return clone

    def getElementsByTagName(self, name):
        if self.caseInsensitive:
            return getElementsByTagNameNoCase(self, name)
        return getElementsByTagName(self, name)

    def hasAttributes(self):
        return 1

    def getAttribute(self, name, default=None):
        return self.attributes.get(name, default)

    def getAttributeNS(self, ns, name, default=None):
        nsk = (ns, name)
        if self.attributes.has_key(nsk):
            return self.attributes[nsk]
        if ns == self.namespace:
            return self.attributes.get(name, default)
        return default

    def getAttributeNode(self, name):
        return _Attr(self.getAttribute(name), self)

    def setAttribute(self, name, attr):
        self.attributes[name] = attr

    def removeAttribute(self, name):
        if name in self.attributes:
            del self.attributes[name]

    def hasAttribute(self, name):
        return name in self.attributes

    def writexml(self,
                 stream,
                 indent='',
                 addindent='',
                 newl='',
                 strip=0,
                 nsprefixes={},
                 namespace=''):
        # write beginning
        ALLOWSINGLETON = ('img', 'br', 'hr', 'base', 'meta', 'link', 'param',
                          'area', 'input', 'col', 'basefont', 'isindex',
                          'frame')
        BLOCKELEMENTS = ('html', 'head', 'body', 'noscript', 'ins', 'del',
                         'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'script', 'ul',
                         'ol', 'dl', 'pre', 'hr', 'blockquote', 'address', 'p',
                         'div', 'fieldset', 'table', 'tr', 'form', 'object',
                         'fieldset', 'applet', 'map')
        FORMATNICELY = ('tr', 'ul', 'ol', 'head')

        # this should never be necessary unless people start
        # changing .tagName on the fly(?)
        if not self.preserveCase:
            self.endTagName = self.tagName
        w = stream.write
        if self.nsprefixes:
            newprefixes = self.nsprefixes.copy()
            for ns in nsprefixes.keys():
                if ns in newprefixes:
                    del newprefixes[ns]
        else:
            newprefixes = {}

        begin = ['<']
        if self.tagName in BLOCKELEMENTS:
            begin = [newl, indent] + begin
        bext = begin.extend
        writeattr = lambda _atr, _val: bext(
            (' ', _atr, '="', escape(_val), '"'))
        if namespace != self.namespace and self.namespace is not None:
            if nsprefixes.has_key(self.namespace):
                prefix = nsprefixes[self.namespace]
                bext(prefix + ':' + self.tagName)
            else:
                bext(self.tagName)
                writeattr("xmlns", self.namespace)
        else:
            bext(self.tagName)
        j = ''.join
        for attr, val in self.attributes.iteritems():
            if isinstance(attr, tuple):
                ns, key = attr
                if nsprefixes.has_key(ns):
                    prefix = nsprefixes[ns]
                else:
                    prefix = genprefix()
                    newprefixes[ns] = prefix
                assert val is not None
                writeattr(prefix + ':' + key, val)
            else:
                assert val is not None
                writeattr(attr, val)
        if newprefixes:
            for ns, prefix in newprefixes.iteritems():
                if prefix:
                    writeattr('xmlns:' + prefix, ns)
            newprefixes.update(nsprefixes)
            downprefixes = newprefixes
        else:
            downprefixes = nsprefixes
        w(j(begin))
        if self.childNodes:
            w(">")
            newindent = indent + addindent
            for child in self.childNodes:
                if self.tagName in BLOCKELEMENTS and \
                   self.tagName in FORMATNICELY:
                    w(j((newl, newindent)))
                child.writexml(stream, newindent, addindent, newl, strip,
                               downprefixes, self.namespace)
            if self.tagName in BLOCKELEMENTS:
                w(j((newl, indent)))
            w(j(("</", self.endTagName, '>')))

        elif self.tagName.lower() not in ALLOWSINGLETON:
            w(j(('></', self.endTagName, '>')))
        else:
            w(" />")

    def __repr__(self):
        rep = "Element(%s" % repr(self.nodeName)
        if self.attributes:
            rep += ", attributes=%r" % (self.attributes, )
        if self._filename:
            rep += ", filename=%r" % (self._filename, )
        if self._markpos:
            rep += ", markpos=%r" % (self._markpos, )
        return rep + ')'

    def __str__(self):
        rep = "<" + self.nodeName
        if self._filename or self._markpos:
            rep += " ("
        if self._filename:
            rep += repr(self._filename)
        if self._markpos:
            rep += " line %s column %s" % self._markpos
        if self._filename or self._markpos:
            rep += ")"
        for item in self.attributes.items():
            rep += " %s=%r" % item
        if self.hasChildNodes():
            rep += " >...</%s>" % self.nodeName
        else:
            rep += " />"
        return rep
Example #2
0
class Element(Node):

    preserveCase = 0
    caseInsensitive = 1
    nsprefixes = None
    namespace = ''

    def __init__(self, tagName, attributes=None, parentNode=None,
                        filename=None, markpos=None,
                        caseInsensitive=1, preserveCase=0,
                 namespace=''):
        Node.__init__(self, parentNode)
        self.preserveCase = preserveCase or not caseInsensitive
        self.caseInsensitive = caseInsensitive
        if not preserveCase:
            tagName = tagName.lower()
        if attributes is None:
            self.attributes = {}
        else:
            self.attributes = attributes
            for k, v in self.attributes.items():
                self.attributes[k] = unescape(v)

        if caseInsensitive:
            self.attributes = InsensitiveDict(self.attributes, 
                                              preserve=preserveCase)

        self.endTagName = self.nodeName = self.tagName = tagName
        self._filename = filename
        self._markpos = markpos
        self.namespace = namespace

    def addPrefixes(self, pfxs):
        if self.nsprefixes is None:
            self.nsprefixes = pfxs
        else:
            self.nsprefixes.update(pfxs)

    def endTag(self, endTagName):
        if not self.preserveCase:
            endTagName = endTagName.lower()
        self.endTagName = endTagName

    def isEqualToElement(self, n):
        if self.caseInsensitive:
            return (self.attributes == n.attributes) and (self.nodeName.lower() == n.nodeName.lower())
        return (self.attributes == n.attributes) and (self.nodeName == n.nodeName)

    def cloneNode(self, deep=0, parent=None):
        clone = Element(
            self.tagName, parentNode=parent, namespace=self.namespace,
            preserveCase=self.preserveCase, caseInsensitive=self.caseInsensitive)
        clone.attributes.update(self.attributes)
        if deep:
            clone.childNodes = [child.cloneNode(1, clone) for child in self.childNodes]
        else:
            clone.childNodes = []
        return clone

    def getElementsByTagName(self, name):
        if self.caseInsensitive:
            return getElementsByTagNameNoCase(self, name)
        return getElementsByTagName(self, name)

    def hasAttributes(self):
        return 1

    def getAttribute(self, name, default=None):
        return self.attributes.get(name, default)

    def getAttributeNS(self, ns, name, default=None):
        nsk = (ns, name)
        if self.attributes.has_key(nsk):
            return self.attributes[nsk]
        if ns == self.namespace:
            return self.attributes.get(name, default)
        return default

    def getAttributeNode(self, name):
        return _Attr(self.getAttribute(name), self)

    def setAttribute(self, name, attr):
        self.attributes[name] = attr

    def removeAttribute(self, name):
        if name in self.attributes:
            del self.attributes[name]

    def removeAttribute_has_key(self, name):
        if self.attributes.has_key(name):
            del self.attributes[name]

    def hasAttribute(self, name):
        return name in self.attributes

    def hasAttribute_has_key(self, name):
        return self.attributes.has_key(name)

    if dictsAreNotSequences:
        hasAttribute = hasAttribute_has_key
        removeAttribute = removeAttribute_has_key

    def writexml(self, stream, indent='', addindent='', newl='', strip=0, nsprefixes={}, namespace=''):
        # write beginning
        ALLOWSINGLETON = ('img', 'br', 'hr', 'base', 'meta', 'link', 'param',
                          'area', 'input', 'col', 'basefont', 'isindex',
                          'frame')
        BLOCKELEMENTS = ('html', 'head', 'body', 'noscript', 'ins', 'del',
                         'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'script',
                         'ul', 'ol', 'dl', 'pre', 'hr', 'blockquote',
                         'address', 'p', 'div', 'fieldset', 'table', 'tr',
                         'form', 'object', 'fieldset', 'applet', 'map')
        FORMATNICELY = ('tr', 'ul', 'ol', 'head')

        # this should never be necessary unless people start
        # changing .tagName on the fly(?)
        if not self.preserveCase:
            self.endTagName = self.tagName
        w = stream.write
        if self.nsprefixes:
            newprefixes = self.nsprefixes.copy()
            for ns in nsprefixes.keys():
                del newprefixes[ns]
        else:
             newprefixes = {}

        begin = ['<']
        if self.tagName in BLOCKELEMENTS:
            begin = [newl, indent] + begin
        bext = begin.extend
        writeattr = lambda _atr, _val: bext((' ', _atr, '="', escape(_val), '"'))
        if namespace != self.namespace and self.namespace:
            if nsprefixes.has_key(self.namespace):
                prefix = nsprefixes[self.namespace]
                bext(prefix+':'+self.tagName)
            else:
                bext(self.tagName)
                writeattr("xmlns", self.namespace)
        else:
            bext(self.tagName)
        j = ''.join
        for attr, val in self.attributes.iteritems():
            if isinstance(attr, tuple):
                ns, key = attr
                if nsprefixes.has_key(ns):
                    prefix = nsprefixes[ns]
                else:
                    prefix = genprefix()
                    newprefixes[ns] = prefix
                assert val is not None
                writeattr(prefix+':'+key,val)
            else:
                assert val is not None
                writeattr(attr, val)
        if newprefixes:
            for ns, prefix in newprefixes.iteritems():
                if prefix:
                    writeattr('xmlns:'+prefix, ns)
            newprefixes.update(nsprefixes)
            downprefixes = newprefixes
        else:
            downprefixes = nsprefixes
        w(j(begin))
        if self.childNodes:
            w(">")
            newindent = indent + addindent
            for child in self.childNodes:
                if self.tagName in BLOCKELEMENTS and \
                   self.tagName in FORMATNICELY:
                    w(j((newl, newindent)))
                child.writexml(stream, newindent, addindent, newl, strip, downprefixes, self.namespace)
            if self.tagName in BLOCKELEMENTS:
                w(j((newl, indent)))
            w(j(("</", self.endTagName, '>')))
            
        elif self.tagName.lower() not in ALLOWSINGLETON:
            w(j(('></', self.endTagName, '>')))
        else:
            w(" />")

    def __repr__(self):
        rep = "Element(%s" % repr(self.nodeName)
        if self.attributes:
            rep += ", attributes=%r" % (self.attributes,)
        if self._filename:
            rep += ", filename=%r" % (self._filename,)
        if self._markpos:
            rep += ", markpos=%r" % (self._markpos,)
        return rep + ')'

    def __str__(self):
        rep = "<" + self.nodeName
        if self._filename or self._markpos:
            rep += " ("
        if self._filename:
            rep += repr(self._filename)
        if self._markpos:
            rep += " line %s column %s" % self._markpos
        if self._filename or self._markpos:
            rep += ")"
        for item in self.attributes.items():
            rep += " %s=%r" % item
        if self.hasChildNodes():
            rep += " >...</%s>" % self.nodeName
        else:
            rep += " />"
        return rep
class Element(Node):

    preserveCase = 0
    caseInsensitive = 1
    nsprefixes = None

    def __init__(self, tagName, attributes=None, parentNode=None,
                 filename=None, markpos=None,
                 caseInsensitive=1, preserveCase=0,
                 namespace=None):
        Node.__init__(self, parentNode)
        self.preserveCase = preserveCase or not caseInsensitive
        self.caseInsensitive = caseInsensitive
        if not preserveCase:
            tagName = tagName.lower()
        if attributes is None:
            self.attributes = {}
        else:
            self.attributes = attributes
            for k, v in self.attributes.items():
                self.attributes[k] = unescape(v)

        if caseInsensitive:
            self.attributes = InsensitiveDict(self.attributes,
                                              preserve=preserveCase)

        self.endTagName = self.nodeName = self.tagName = tagName
        self._filename = filename
        self._markpos = markpos
        self.namespace = namespace

    def addPrefixes(self, pfxs):
        if self.nsprefixes is None:
            self.nsprefixes = pfxs
        else:
            self.nsprefixes.update(pfxs)

    def endTag(self, endTagName):
        if not self.preserveCase:
            endTagName = endTagName.lower()
        self.endTagName = endTagName

    def isEqualToElement(self, n):
        if self.caseInsensitive:
            return ((self.attributes == n.attributes)
                    and (self.nodeName.lower() == n.nodeName.lower()))
        return (self.attributes == n.attributes) and (self.nodeName == n.nodeName)


    def isEqualToNode(self, other):
        """
        Compare this element to C{other}.  If the C{nodeName}, C{namespace},
        C{attributes}, and C{childNodes} are all the same, return C{True},
        otherwise return C{False}.
        """
        return (
            self.nodeName.lower() == other.nodeName.lower() and
            self.namespace == other.namespace and
            self.attributes == other.attributes and
            Node.isEqualToNode(self, other))


    def cloneNode(self, deep=0, parent=None):
        clone = Element(
            self.tagName, parentNode=parent, namespace=self.namespace,
            preserveCase=self.preserveCase, caseInsensitive=self.caseInsensitive)
        clone.attributes.update(self.attributes)
        if deep:
            clone.childNodes = [child.cloneNode(1, clone) for child in self.childNodes]
        else:
            clone.childNodes = []
        return clone

    def getElementsByTagName(self, name):
        if self.caseInsensitive:
            return getElementsByTagNameNoCase(self, name)
        return getElementsByTagName(self, name)

    def hasAttributes(self):
        return 1

    def getAttribute(self, name, default=None):
        return self.attributes.get(name, default)

    def getAttributeNS(self, ns, name, default=None):
        nsk = (ns, name)
        if self.attributes.has_key(nsk):
            return self.attributes[nsk]
        if ns == self.namespace:
            return self.attributes.get(name, default)
        return default

    def getAttributeNode(self, name):
        return _Attr(self.getAttribute(name), self)

    def setAttribute(self, name, attr):
        self.attributes[name] = attr

    def removeAttribute(self, name):
        if name in self.attributes:
            del self.attributes[name]

    def hasAttribute(self, name):
        return name in self.attributes


    def writexml(self, stream, indent='', addindent='', newl='', strip=0,
                 nsprefixes={}, namespace=''):
        """
        Serialize this L{Element} to the given stream.

        @param stream: A file-like object to which this L{Element} will be
            written.

        @param nsprefixes: A C{dict} mapping namespace URIs as C{str} to
            prefixes as C{str}.  This defines the prefixes which are already in
            scope in the document at the point at which this L{Element} exists.
            This is essentially an implementation detail for namespace support.
            Applications should not try to use it.

        @param namespace: The namespace URI as a C{str} which is the default at
            the point in the document at which this L{Element} exists.  This is
            essentially an implementation detail for namespace support.
            Applications should not try to use it.
        """
        # write beginning
        ALLOWSINGLETON = ('img', 'br', 'hr', 'base', 'meta', 'link', 'param',
                          'area', 'input', 'col', 'basefont', 'isindex',
                          'frame')
        BLOCKELEMENTS = ('html', 'head', 'body', 'noscript', 'ins', 'del',
                         'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'script',
                         'ul', 'ol', 'dl', 'pre', 'hr', 'blockquote',
                         'address', 'p', 'div', 'fieldset', 'table', 'tr',
                         'form', 'object', 'fieldset', 'applet', 'map')
        FORMATNICELY = ('tr', 'ul', 'ol', 'head')

        # this should never be necessary unless people start
        # changing .tagName on the fly(?)
        if not self.preserveCase:
            self.endTagName = self.tagName
        w = stream.write
        if self.nsprefixes:
            newprefixes = self.nsprefixes.copy()
            for ns in nsprefixes.keys():
                if ns in newprefixes:
                    del newprefixes[ns]
        else:
             newprefixes = {}

        begin = ['<']
        if self.tagName in BLOCKELEMENTS:
            begin = [newl, indent] + begin
        bext = begin.extend
        writeattr = lambda _atr, _val: bext((' ', _atr, '="', escape(_val), '"'))

        # Make a local for tracking what end tag will be used.  If namespace
        # prefixes are involved, this will be changed to account for that
        # before it's actually used.
        endTagName = self.endTagName

        if namespace != self.namespace and self.namespace is not None:
            # If the current default namespace is not the namespace of this tag
            # (and this tag has a namespace at all) then we'll write out
            # something related to namespaces.
            if self.namespace in nsprefixes:
                # This tag's namespace already has a prefix bound to it.  Use
                # that prefix.
                prefix = nsprefixes[self.namespace]
                bext(prefix + ':' + self.tagName)
                # Also make sure we use it for the end tag.
                endTagName = prefix + ':' + self.endTagName
            else:
                # This tag's namespace has no prefix bound to it.  Change the
                # default namespace to this tag's namespace so we don't need
                # prefixes.  Alternatively, we could add a new prefix binding.
                # I'm not sure why the code was written one way rather than the
                # other. -exarkun
                bext(self.tagName)
                writeattr("xmlns", self.namespace)
                # The default namespace just changed.  Make sure any children
                # know about this.
                namespace = self.namespace
        else:
            # This tag has no namespace or its namespace is already the default
            # namespace.  Nothing extra to do here.
            bext(self.tagName)

        j = ''.join
        for attr, val in self.attributes.iteritems():
            if isinstance(attr, tuple):
                ns, key = attr
                if nsprefixes.has_key(ns):
                    prefix = nsprefixes[ns]
                else:
                    prefix = genprefix()
                    newprefixes[ns] = prefix
                assert val is not None
                writeattr(prefix+':'+key,val)
            else:
                assert val is not None
                writeattr(attr, val)
        if newprefixes:
            for ns, prefix in newprefixes.iteritems():
                if prefix:
                    writeattr('xmlns:'+prefix, ns)
            newprefixes.update(nsprefixes)
            downprefixes = newprefixes
        else:
            downprefixes = nsprefixes
        w(j(begin))
        if self.childNodes:
            w(">")
            newindent = indent + addindent
            for child in self.childNodes:
                if self.tagName in BLOCKELEMENTS and \
                   self.tagName in FORMATNICELY:
                    w(j((newl, newindent)))
                child.writexml(stream, newindent, addindent, newl, strip,
                               downprefixes, namespace)
            if self.tagName in BLOCKELEMENTS:
                w(j((newl, indent)))
            w(j(('</', endTagName, '>')))
        elif self.tagName.lower() not in ALLOWSINGLETON:
            w(j(('></', endTagName, '>')))
        else:
            w(" />")


    def __repr__(self):
        rep = "Element(%s" % repr(self.nodeName)
        if self.attributes:
            rep += ", attributes=%r" % (self.attributes,)
        if self._filename:
            rep += ", filename=%r" % (self._filename,)
        if self._markpos:
            rep += ", markpos=%r" % (self._markpos,)
        return rep + ')'

    def __str__(self):
        rep = "<" + self.nodeName
        if self._filename or self._markpos:
            rep += " ("
        if self._filename:
            rep += repr(self._filename)
        if self._markpos:
            rep += " line %s column %s" % self._markpos
        if self._filename or self._markpos:
            rep += ")"
        for item in self.attributes.items():
            rep += " %s=%r" % item
        if self.hasChildNodes():
            rep += " >...</%s>" % self.nodeName
        else:
            rep += " />"
        return rep
Example #4
0
    def __send_http_response(self, inh, request, response_msg):
        """
        When we've know what message to send back to the HTTP client
        which has connected to the HTTP server, we issue this message back.

        @param inh: an inhabinant who will receive the response
        @type inh: AbstractInhabitant

        @param request: web server request.
        @type request: Request

        @param response_msg: response message to send.
        @type response_msg: AbstractMessage
        """
        if not self.connection_alive:
            logger.debug(
                'Connection died inside %r while trying '
                'to reply with %r', self, response_msg)
            # That's very very bad! We should put the message back to queue.
            self.tr_manager.post_message(response_msg)
        else:
            logger.debug('Sending response %r to %r', response_msg,
                         request.requestHeaders)

            response_msg.in_transfer = True

            # Add the default server-specific headers,
            # then the message-specific headers.
            _headers = InsensitiveDict(
                dict(request.responseHeaders.getAllRawHeaders()))
            _pragma = ','.join(
                ifilter(None, [response_msg.get_pragma(),
                               self.extra_pragma()]))
            HTTPTransport.update_headers(_headers, {'Pragma': [_pragma]})
            HTTPTransport.update_headers(_headers, response_msg.get_headers())
            for k, v_list in _headers.iteritems():
                request.responseHeaders.setRawHeaders(k, v_list)

            logger.debug('New headers for %r are: %r', response_msg,
                         request.responseHeaders)

            @contract_epydoc
            def produce_body_in_main(body, msg):
                """
                @type body: col.Iterable
                @type msg: AbstractMessage
                """
                assert in_main_thread()

                try:
                    producer = LazyPullProducer(request, body)
                    producer.completed.addBoth(self._ready_to_finish.callback)
                except Exception:
                    logger.exception('Error during writing back the request:')
                    # We haven't succeeded to send the message to the client.
                    # Put it back to the queue.
                    callInThread(self.tr_manager.post_message, msg)

            assert not in_main_thread()  # get_body() may take long
            _body = response_msg.get_body()
            logger.debug('Writing body: %r', response_msg)

            callFromThread(produce_body_in_main, _body, response_msg)
Example #5
0
    def _render(self, request, avatar):
        """Node-specific request processing.

        @param request: Web server request.
        @type request: Request

        @type avatar: Host

        @returns: nothing (not a C{Deferred} object!).
            But, due to C{inlineCallbacks}, yields the intermediate
            C{Deferred}s.

        @todo: Proper error handling.

        @todo: Properly handle the situation when the passthrough is
               restricted: generate the reply which contains the Error 404.

        @todo: This should be streamlined using super() as soon
               as C{twisted.web.resource.Resource} becomes a new-style class
        """
        assert not in_main_thread()
        # Kind-of-calling the parent, but the parent in this case should
        # return a Deferred as well,... let's not bother with it.
        # DeferredProcessingResource._render(self, request, avatar)

        logger.debug('')
        logger.debug('')
        logger.debug('Avatar %r;'
                     '\tincoming headers %r;'
                     '\tfrom %r', avatar, request.requestHeaders,
                     request.client)

        # We setup the default headers for response even before
        # we start analyzing the incoming message,
        # so that if analyzing fails for some reason, we have the headers
        # and can create a more-or-less proper error reply.
        _requestHeaders = InsensitiveDict(
            dict(request.requestHeaders.getAllRawHeaders()))

        _responseHeaders = InsensitiveDict()
        self.initialize_headers(_responseHeaders)

        message = self.create_message_from_headers(headers=_requestHeaders,
                                                   auth_peer=avatar)

        message.body_receiver = RequestBodyReceiver(message=message,
                                                    request=request)

        # Make sure the body is received, before going further
        dummy_received_data = yield message.body_receiver.on_finish

        assert not in_main_thread()

        if message.direct:
            # If this is the message directed to ourselves,
            # process it and send the response
            logger.debug('')
            logger.debug('> Der Mitteilung Nahert: %r von %s', message,
                         message.src)

            # Process the incoming message
            try:
                self.tr_manager.handle_incoming_message(message)
            except TransactionProcessingException as e:
                # The incoming transaction cannot be processed.

                # TODO: handle error properly, send a error reply maybe
                logger.error('Error (%r) during incoming msg processing: %s',
                             e, e)

            logger.debug('Will send response to %r from %r %s', message,
                         message.src, hash(message.src))
            for k, v_list in _responseHeaders.iteritems():
                request.responseHeaders.setRawHeaders(k, v_list)
            logger.debug('Done with response headers')
        elif self._accept_passthrough_message(message):
            # Non-direct message, and passthrough allowed:
            # wait for the body, then put in the queue.

            logger.debug('Passthrough message %r: body already available',
                         message)
            self.tr_manager.post_message(message)

        else:
            # Passthrough is restricted for this message!
            raise NotImplementedError(u'Failed message {!r}:\n'
                                      u'from: {!r}\n'
                                      u'  to: {!r}'.format(
                                          message, message.src, message.dst))

        # How to check if we still need a message?
        still_need_checker = lambda: self.connection_alive

        # No matter if we are processing the message or passing it through,
        # we must send a response somehow.

        # If this is the message to us, we'd prefer a response to reply it;
        # but if this is a passthrough message, it will go to a different peer.
        prefer_msg_uuid = message.uuid if message.direct else None
        try:
            # Let's (asynchronously) wait for the response message here.
            resp_msg = self.__response_msg \
                     = yield self.tr_manager.wait_for_message_for_peer(
                                 inh=message.src,
                                 prefer_msg_uuid=prefer_msg_uuid,
                                 still_wait_checker=still_need_checker)
        except internet_error.ConnectionClosed as e:
            logger.warning('Stopped to wait for a message due to %r', e)
            self._handle_connection_close(Failure(e))
        except Exception as e:
            logger.exception('Stopped to wait for a message due to %r', e)
            self._handle_connection_close(Failure(e))
        else:
            # Since now and till the end of transfer we store the message
            # in self.__response_msg.

            assert not in_main_thread()

            if resp_msg is None:
                # The connection died already, while waiting for the message.
                assert not self.connection_alive

            else:
                # Got the message, send it back
                assert isinstance(resp_msg, AbstractMessage), repr(resp_msg)
                self.__send_http_response(message.src, request, resp_msg)
Example #6
0
    def __send_http_response(self, inh, request, response_msg):
        """
        When we've know what message to send back to the HTTP client
        which has connected to the HTTP server, we issue this message back.

        @param inh: an inhabinant who will receive the response
        @type inh: AbstractInhabitant

        @param request: web server request.
        @type request: Request

        @param response_msg: response message to send.
        @type response_msg: AbstractMessage
        """
        if not self.connection_alive:
            logger.debug('Connection died inside %r while trying '
                             'to reply with %r',
                         self, response_msg)
            # That's very very bad! We should put the message back to queue.
            self.tr_manager.post_message(response_msg)
        else:
            logger.debug('Sending response %r to %r',
                         response_msg, request.requestHeaders)

            response_msg.in_transfer = True

            # Add the default server-specific headers,
            # then the message-specific headers.
            _headers = InsensitiveDict(dict(request.responseHeaders
                                                   .getAllRawHeaders()))
            _pragma = ','.join(ifilter(None, [response_msg.get_pragma(),
                                              self.extra_pragma()]))
            HTTPTransport.update_headers(_headers, {'Pragma': [_pragma]})
            HTTPTransport.update_headers(_headers, response_msg.get_headers())
            for k, v_list in _headers.iteritems():
                request.responseHeaders.setRawHeaders(k, v_list)

            logger.debug('New headers for %r are: %r',
                         response_msg, request.responseHeaders)


            @contract_epydoc
            def produce_body_in_main(body, msg):
                """
                @type body: col.Iterable
                @type msg: AbstractMessage
                """
                assert in_main_thread()

                try:
                    producer = LazyPullProducer(request, body)
                    producer.completed.addBoth(self._ready_to_finish.callback)
                except Exception:
                    logger.exception('Error during writing back the request:')
                    # We haven't succeeded to send the message to the client.
                    # Put it back to the queue.
                    callInThread(self.tr_manager.post_message, msg)


            assert not in_main_thread()  # get_body() may take long
            _body = response_msg.get_body()
            logger.debug('Writing body: %r', response_msg)

            callFromThread(produce_body_in_main, _body, response_msg)
Example #7
0
    def _render(self, request, avatar):
        """Node-specific request processing.

        @param request: Web server request.
        @type request: Request

        @type avatar: Host

        @returns: nothing (not a C{Deferred} object!).
            But, due to C{inlineCallbacks}, yields the intermediate
            C{Deferred}s.

        @todo: Proper error handling.

        @todo: Properly handle the situation when the passthrough is
               restricted: generate the reply which contains the Error 404.

        @todo: This should be streamlined using super() as soon
               as C{twisted.web.resource.Resource} becomes a new-style class
        """
        assert not in_main_thread()
        # Kind-of-calling the parent, but the parent in this case should
        # return a Deferred as well,... let's not bother with it.
        # DeferredProcessingResource._render(self, request, avatar)

        logger.debug('')
        logger.debug('')
        logger.debug('Avatar %r;'
                         '\tincoming headers %r;'
                         '\tfrom %r',
                     avatar, request.requestHeaders, request.client)

        # We setup the default headers for response even before
        # we start analyzing the incoming message,
        # so that if analyzing fails for some reason, we have the headers
        # and can create a more-or-less proper error reply.
        _requestHeaders = InsensitiveDict(dict(request.requestHeaders
                                                      .getAllRawHeaders()))

        _responseHeaders = InsensitiveDict()
        self.initialize_headers(_responseHeaders)

        message = self.create_message_from_headers(headers=_requestHeaders,
                                                   auth_peer=avatar)

        message.body_receiver = RequestBodyReceiver(message=message,
                                                    request=request)

        # Make sure the body is received, before going further
        dummy_received_data = yield message.body_receiver.on_finish

        assert not in_main_thread()

        if message.direct:
            # If this is the message directed to ourselves,
            # process it and send the response
            logger.debug('')
            logger.debug('> Der Mitteilung Nahert: %r von %s',
                         message, message.src)

            # Process the incoming message
            try:
                self.tr_manager.handle_incoming_message(message)
            except TransactionProcessingException as e:
                # The incoming transaction cannot be processed.

                # TODO: handle error properly, send a error reply maybe
                logger.error('Error (%r) during incoming msg processing: %s',
                             e, e)

            logger.debug('Will send response to %r from %r %s',
                         message, message.src, hash(message.src))
            for k, v_list in _responseHeaders.iteritems():
                request.responseHeaders.setRawHeaders(k, v_list)
            logger.debug('Done with response headers')
        elif self._accept_passthrough_message(message):
            # Non-direct message, and passthrough allowed:
            # wait for the body, then put in the queue.

            logger.debug('Passthrough message %r: body already available',
                         message)
            self.tr_manager.post_message(message)

        else:
            # Passthrough is restricted for this message!
            raise NotImplementedError(u'Failed message {!r}:\n'
                                           u'from: {!r}\n'
                                           u'  to: {!r}'.format(message,
                                                                message.src,
                                                                message.dst))

        # How to check if we still need a message?
        still_need_checker = lambda: self.connection_alive

        # No matter if we are processing the message or passing it through,
        # we must send a response somehow.

        # If this is the message to us, we'd prefer a response to reply it;
        # but if this is a passthrough message, it will go to a different peer.
        prefer_msg_uuid = message.uuid if message.direct else None
        try:
            # Let's (asynchronously) wait for the response message here.
            resp_msg = self.__response_msg \
                     = yield self.tr_manager.wait_for_message_for_peer(
                                 inh=message.src,
                                 prefer_msg_uuid=prefer_msg_uuid,
                                 still_wait_checker=still_need_checker)
        except internet_error.ConnectionClosed as e:
            logger.warning('Stopped to wait for a message due to %r', e)
            self._handle_connection_close(Failure(e))
        except Exception as e:
            logger.exception('Stopped to wait for a message due to %r', e)
            self._handle_connection_close(Failure(e))
        else:
            # Since now and till the end of transfer we store the message
            # in self.__response_msg.

            assert not in_main_thread()

            if resp_msg is None:
                # The connection died already, while waiting for the message.
                assert not self.connection_alive

            else:
                # Got the message, send it back
                assert isinstance(resp_msg, AbstractMessage), repr(resp_msg)
                self.__send_http_response(message.src, request, resp_msg)