"""
http binding interface
"""
from twisted.python import components
from twisted.web import server, resource
from twisted.internet import defer, task
from twisted.python import log
from zope.interface import Interface, implements
try:
from twisted.words.xish import domish
except ImportError:
from twisted.xish import domish
import hashlib, time
import error
from session import make_session
import punjab
from punjab.xmpp import ns
NS_BIND = 'http://jabber.org/protocol/httpbind'
NS_FEATURES = 'http://etherx.jabber.org/streams'
NS_XMPP = 'urn:xmpp:xbosh'
class DummyElement:
"""
dummy element for a quicker parse
"""
# currently not used
def __init__(self, *args, **kwargs):
self.children = []
class HttpbElementStream(domish.ExpatElementStream):
"""
add rawXml to the elements
"""
def __init__(self, prefixes=None):
domish.ExpatElementStream.__init__(self)
self.prefixes = {}
if prefixes:
self.prefixes.update(prefixes)
self.prefixes.update(domish.G_PREFIXES)
self.prefixStack = [domish.G_PREFIXES.values()]
self.prefixCounter = 0
def getPrefix(self, uri):
if not self.prefixes.has_key(uri):
self.prefixes[uri] = "xn%d" % (self.prefixCounter)
self.prefixCounter = self.prefixCounter + 1
return self.prefixes[uri]
def prefixInScope(self, prefix):
stack = self.prefixStack
for i in range(-1, (len(self.prefixStack)+1) * -1, -1):
if prefix in stack[i]:
return True
return False
def _onStartElement(self, name, attrs):
# Generate a qname tuple from the provided name
attr_str = ''
defaultUri = None
uri = None
qname = name.split(" ")
if len(qname) == 1:
qname = ('', name)
currentUri = None
else:
currentUri = qname[0]
if self.currElem:
defaultUri = self.currElem.defaultUri
uri = self.currElem.uri
if not defaultUri and currentUri in self.defaultNsStack:
defaultUri = self.defaultNsStack[1]
if defaultUri and currentUri != defaultUri:
raw_xml = u"""<%s xmlns='%s'%s""" % (qname[1], qname[0], '%s')
else:
raw_xml = u"""<%s%s""" % (qname[1], '%s')
# Process attributes
for k, v in attrs.items():
if k.find(" ") != -1:
aqname = k.split(" ")
attrs[(aqname[0], aqname[1])] = v
attr_prefix = self.getPrefix(aqname[0])
if not self.prefixInScope(attr_prefix):
attr_str = attr_str + " xmlns:%s='%s'" % (attr_prefix,
aqname[0])
self.prefixStack[-1].append(attr_prefix)
attr_str = attr_str + " %s:%s='%s'" % (attr_prefix,
aqname[1],
domish.escapeToXml(v,
True))
del attrs[k]
else:
v = domish.escapeToXml(v, True)
attr_str = attr_str + " " + k + "='" + v + "'"
raw_xml = raw_xml % (attr_str,)
# Construct the new element
e = domish.Element(qname, self.defaultNsStack[-1], attrs, self.localPrefixes)
self.localPrefixes = {}
# Document already started
if self.documentStarted == 1:
if self.currElem != None:
if len(self.currElem.children)==0 or isinstance(self.currElem.children[-1], domish.Element):
if self.currRawElem[-1] != ">":
self.currRawElem = self.currRawElem +">"
self.currElem.children.append(e)
e.parent = self.currElem
self.currRawElem = self.currRawElem + raw_xml
self.currElem = e
# New document
else:
self.currRawElem = u''
self.documentStarted = 1
self.DocumentStartEvent(e)
def _onEndElement(self, _):
# Check for null current elem; end of doc
if self.currElem is None:
self.DocumentEndEvent()
# Check for parent that is None; that's
# the top of the stack
elif self.currElem.parent is None:
if len(self.currElem.children)>0:
self.currRawElem = self.currRawElem + "</"+ self.currElem.name+">"
else:
self.currRawElem = self.currRawElem + "/>"
self.ElementEvent(self.currElem, self.currRawElem)
self.currElem = None
self.currRawElem = u''
# Anything else is just some element in the current
# packet wrapping up
else:
if len(self.currElem.children)==0:
self.currRawElem = self.currRawElem + "/>"
else:
self.currRawElem = self.currRawElem + "</"+ self.currElem.name+">"
self.currElem = self.currElem.parent
def _onCdata(self, data):
if self.currElem != None:
if len(self.currElem.children)==0:
self.currRawElem = self.currRawElem + ">" + domish.escapeToXml(data)
#self.currRawElem = self.currRawElem + ">" + data
else:
self.currRawElem = self.currRawElem + domish.escapeToXml(data)
#self.currRawElem = self.currRawElem + data
self.currElem.addContent(data)
def _onStartNamespace(self, prefix, uri):
# If this is the default namespace, put
# it on the stack
if prefix is None:
self.defaultNsStack.append(uri)
else:
self.localPrefixes[prefix] = uri
def _onEndNamespace(self, prefix):
# Remove last element on the stack
if prefix is None:
self.defaultNsStack.pop()
def elementStream():
""" Preferred method to construct an ElementStream
Uses Expat-based stream if available, and falls back to Sux if necessary.
"""
try:
es = HttpbElementStream()
return es
except ImportError:
if domish.SuxElementStream is None:
raise Exception("No parsers available :(")
es = domish.SuxElementStream()
return es
# make httpb body class, similar to xmlrpclib
#
class HttpbParse:
"""
An xml parser for parsing the body elements.
"""
def __init__(self, use_t=False):
"""
Call reset to initialize object
"""
self.use_t = use_t # use domish element stream
self._reset()
def parse(self, buf):
"""
Parse incoming xml and return the body and its children in a list
"""
self.stream.parse(buf)
# return the doc element and its children in a list
return self.body, self.xmpp_elements
def serialize(self, obj):
"""
Turn object into a string type
"""
if isinstance(obj, domish.Element):
obj = obj.toXml()
return obj
def onDocumentStart(self, rootelem):
"""
The body document has started.
This should be a body.
"""
if rootelem.name == 'body':
self.body = rootelem
def onElement(self, element, raw_element = None):
"""
A child element has been found.
"""
if isinstance(element, domish.Element):
if raw_element:
self.xmpp_elements.append(raw_element)
else:
self.xmpp_elements.append(element)
else:
pass
def _reset(self):
"""
Setup the parser
"""
if not self.use_t:
self.stream = elementStream()
else:
self.stream = domish.elementStream()
self.stream.DocumentStartEvent = self.onDocumentStart
self.stream.ElementEvent = self.onElement
self.stream.DocumentEndEvent = self.onDocumentEnd
self.body = ""
self.xmpp_elements = []
def onDocumentEnd(self):
"""
Body End
"""
pass
class IHttpbService(Interface):
"""
Interface for http binding class
"""
def __init__(self, verbose):
""" """
def startSession(self, body):
""" Start a punjab jabber session """
def endSession(self, session):
""" end a punjab jabber session """
def onExpire(self, session_id):
""" preform actions based on when the jabber connection expires """
def parseBody(self, body):
""" parse a body element """
def error(self, error):
""" send a body error element """
def inSession(self, body):
""" """
def getXmppElements(self, body, session):
""" """
class IHttpbFactory(Interface):
"""
Factory class for generating binding sessions.
"""
def startSession(self):
""" Start a punjab jabber session """
def endSession(self, session):
""" end a punjab jabber session """
def parseBody(self, body):
""" parse an body element """
def buildProtocol(self, addr):
"""Return a protocol """
class Httpb(resource.Resource):
"""
Http resource to handle BOSH requests.
"""
isLeaf = True
def __init__(self, service, v = 0):
"""Initialize.
"""
resource.Resource.__init__(self)
self.service = service
self.hp = None
self.children = {}
self.client = 0
self.verbose = v
self.polling = self.service.polling or 15
def render_OPTIONS(self, request):
request.setHeader('Access-Control-Allow-Origin', '*')
request.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
request.setHeader('Access-Control-Allow-Headers', 'Content-Type')
request.setHeader('Access-Control-Max-Age', '86400')
return ""
Loading ...