diff options
author | maruel@google.com <maruel@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-10-21 23:00:58 +0000 |
---|---|---|
committer | maruel@google.com <maruel@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-10-21 23:00:58 +0000 |
commit | fb1234375c142c49d28ddbf1fdac5ee9a0f444bc (patch) | |
tree | c52c0dabf0320ffa513f115b3dc3a3537b87a5f3 /tools/buildbot/pylibs/twisted/web | |
parent | 090b98d8ea1c8c5099a6ff010d39ccf6088e9ed1 (diff) | |
download | chromium_src-fb1234375c142c49d28ddbf1fdac5ee9a0f444bc.zip chromium_src-fb1234375c142c49d28ddbf1fdac5ee9a0f444bc.tar.gz chromium_src-fb1234375c142c49d28ddbf1fdac5ee9a0f444bc.tar.bz2 |
Move the buildbot code to trunk/tools/buildbot so it is not included in a default source checkout.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@3698 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'tools/buildbot/pylibs/twisted/web')
68 files changed, 0 insertions, 18829 deletions
diff --git a/tools/buildbot/pylibs/twisted/web/__init__.py b/tools/buildbot/pylibs/twisted/web/__init__.py deleted file mode 100644 index 976b2db..0000000 --- a/tools/buildbot/pylibs/twisted/web/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" - -Twisted Web: a Twisted Web Server. - -""" - -from twisted.web._version import version -__version__ = version.short() - diff --git a/tools/buildbot/pylibs/twisted/web/_version.py b/tools/buildbot/pylibs/twisted/web/_version.py deleted file mode 100644 index 9c9f80a..0000000 --- a/tools/buildbot/pylibs/twisted/web/_version.py +++ /dev/null @@ -1,3 +0,0 @@ -# This is an auto-generated file. Do not edit it. -from twisted.python import versions -version = versions.Version('twisted.web', 8, 1, 0) diff --git a/tools/buildbot/pylibs/twisted/web/client.py b/tools/buildbot/pylibs/twisted/web/client.py deleted file mode 100644 index bdc50b7..0000000 --- a/tools/buildbot/pylibs/twisted/web/client.py +++ /dev/null @@ -1,434 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_webclient -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -HTTP client. -""" - -import os, types -from urlparse import urlunparse - -from twisted.web import http -from twisted.internet import defer, protocol, reactor -from twisted.python import failure -from twisted.python.util import InsensitiveDict -from twisted.web import error - - -class PartialDownloadError(error.Error): - """Page was only partially downloaded, we got disconnected in middle. - - The bit that was downloaded is in the response attribute. - """ - - -class HTTPPageGetter(http.HTTPClient): - - quietLoss = 0 - followRedirect = 1 - failed = 0 - - def connectionMade(self): - method = getattr(self.factory, 'method', 'GET') - self.sendCommand(method, self.factory.path) - self.sendHeader('Host', self.factory.headers.get("host", self.factory.host)) - self.sendHeader('User-Agent', self.factory.agent) - if self.factory.cookies: - l=[] - for cookie, cookval in self.factory.cookies.items(): - l.append('%s=%s' % (cookie, cookval)) - self.sendHeader('Cookie', '; '.join(l)) - data = getattr(self.factory, 'postdata', None) - if data is not None: - self.sendHeader("Content-Length", str(len(data))) - for (key, value) in self.factory.headers.items(): - if key.lower() != "content-length": - # we calculated it on our own - self.sendHeader(key, value) - self.endHeaders() - self.headers = {} - - if data is not None: - self.transport.write(data) - - def handleHeader(self, key, value): - key = key.lower() - l = self.headers[key] = self.headers.get(key, []) - l.append(value) - - def handleStatus(self, version, status, message): - self.version, self.status, self.message = version, status, message - self.factory.gotStatus(version, status, message) - - def handleEndHeaders(self): - self.factory.gotHeaders(self.headers) - m = getattr(self, 'handleStatus_'+self.status, self.handleStatusDefault) - m() - - def handleStatus_200(self): - pass - - handleStatus_201 = lambda self: self.handleStatus_200() - handleStatus_202 = lambda self: self.handleStatus_200() - - def handleStatusDefault(self): - self.failed = 1 - - def handleStatus_301(self): - l = self.headers.get('location') - if not l: - self.handleStatusDefault() - return - url = l[0] - if self.followRedirect: - scheme, host, port, path = \ - _parse(url, defaultPort=self.transport.getPeer().port) - self.factory.setURL(url) - - if self.factory.scheme == 'https': - from twisted.internet import ssl - contextFactory = ssl.ClientContextFactory() - reactor.connectSSL(self.factory.host, self.factory.port, - self.factory, contextFactory) - else: - reactor.connectTCP(self.factory.host, self.factory.port, - self.factory) - else: - self.handleStatusDefault() - self.factory.noPage( - failure.Failure( - error.PageRedirect( - self.status, self.message, location = url))) - self.quietLoss = 1 - self.transport.loseConnection() - - handleStatus_302 = lambda self: self.handleStatus_301() - - def handleStatus_303(self): - self.factory.method = 'GET' - self.handleStatus_301() - - def connectionLost(self, reason): - if not self.quietLoss: - http.HTTPClient.connectionLost(self, reason) - self.factory.noPage(reason) - - def handleResponse(self, response): - if self.quietLoss: - return - if self.failed: - self.factory.noPage( - failure.Failure( - error.Error( - self.status, self.message, response))) - if self.factory.method.upper() == 'HEAD': - # Callback with empty string, since there is never a response - # body for HEAD requests. - self.factory.page('') - elif self.length != None and self.length != 0: - self.factory.noPage(failure.Failure( - PartialDownloadError(self.status, self.message, response))) - else: - self.factory.page(response) - # server might be stupid and not close connection. admittedly - # the fact we do only one request per connection is also - # stupid... - self.transport.loseConnection() - - def timeout(self): - self.quietLoss = True - self.transport.loseConnection() - self.factory.noPage(defer.TimeoutError("Getting %s took longer than %s seconds." % (self.factory.url, self.factory.timeout))) - - -class HTTPPageDownloader(HTTPPageGetter): - - transmittingPage = 0 - - def handleStatus_200(self, partialContent=0): - HTTPPageGetter.handleStatus_200(self) - self.transmittingPage = 1 - self.factory.pageStart(partialContent) - - def handleStatus_206(self): - self.handleStatus_200(partialContent=1) - - def handleResponsePart(self, data): - if self.transmittingPage: - self.factory.pagePart(data) - - def handleResponseEnd(self): - if self.transmittingPage: - self.factory.pageEnd() - self.transmittingPage = 0 - if self.failed: - self.factory.noPage( - failure.Failure( - error.Error( - self.status, self.message, None))) - self.transport.loseConnection() - - -class HTTPClientFactory(protocol.ClientFactory): - """Download a given URL. - - @type deferred: Deferred - @ivar deferred: A Deferred that will fire when the content has - been retrieved. Once this is fired, the ivars `status', `version', - and `message' will be set. - - @type status: str - @ivar status: The status of the response. - - @type version: str - @ivar version: The version of the response. - - @type message: str - @ivar message: The text message returned with the status. - - @type response_headers: dict - @ivar response_headers: The headers that were specified in the - response from the server. - """ - - protocol = HTTPPageGetter - - url = None - scheme = None - host = '' - port = None - path = None - - def __init__(self, url, method='GET', postdata=None, headers=None, - agent="Twisted PageGetter", timeout=0, cookies=None, - followRedirect=1): - self.protocol.followRedirect = followRedirect - self.timeout = timeout - self.agent = agent - - if cookies is None: - cookies = {} - self.cookies = cookies - if headers is not None: - self.headers = InsensitiveDict(headers) - else: - self.headers = InsensitiveDict() - if postdata is not None: - self.headers.setdefault('Content-Length', len(postdata)) - # just in case a broken http/1.1 decides to keep connection alive - self.headers.setdefault("connection", "close") - self.postdata = postdata - self.method = method - - self.setURL(url) - - self.waiting = 1 - self.deferred = defer.Deferred() - self.response_headers = None - - def __repr__(self): - return "<%s: %s>" % (self.__class__.__name__, self.url) - - def setURL(self, url): - self.url = url - scheme, host, port, path = _parse(url) - if scheme and host: - self.scheme = scheme - self.host = host - self.port = port - self.path = path - - def buildProtocol(self, addr): - p = protocol.ClientFactory.buildProtocol(self, addr) - if self.timeout: - timeoutCall = reactor.callLater(self.timeout, p.timeout) - self.deferred.addBoth(self._cancelTimeout, timeoutCall) - return p - - def _cancelTimeout(self, result, timeoutCall): - if timeoutCall.active(): - timeoutCall.cancel() - return result - - def gotHeaders(self, headers): - self.response_headers = headers - if headers.has_key('set-cookie'): - for cookie in headers['set-cookie']: - cookparts = cookie.split(';') - cook = cookparts[0] - cook.lstrip() - k, v = cook.split('=', 1) - self.cookies[k.lstrip()] = v.lstrip() - - def gotStatus(self, version, status, message): - self.version, self.status, self.message = version, status, message - - def page(self, page): - if self.waiting: - self.waiting = 0 - self.deferred.callback(page) - - def noPage(self, reason): - if self.waiting: - self.waiting = 0 - self.deferred.errback(reason) - - def clientConnectionFailed(self, _, reason): - if self.waiting: - self.waiting = 0 - self.deferred.errback(reason) - - -class HTTPDownloader(HTTPClientFactory): - """Download to a file.""" - - protocol = HTTPPageDownloader - value = None - - def __init__(self, url, fileOrName, - method='GET', postdata=None, headers=None, - agent="Twisted client", supportPartial=0): - self.requestedPartial = 0 - if isinstance(fileOrName, types.StringTypes): - self.fileName = fileOrName - self.file = None - if supportPartial and os.path.exists(self.fileName): - fileLength = os.path.getsize(self.fileName) - if fileLength: - self.requestedPartial = fileLength - if headers == None: - headers = {} - headers["range"] = "bytes=%d-" % fileLength - else: - self.file = fileOrName - HTTPClientFactory.__init__(self, url, method=method, postdata=postdata, headers=headers, agent=agent) - self.deferred = defer.Deferred() - self.waiting = 1 - - def gotHeaders(self, headers): - if self.requestedPartial: - contentRange = headers.get("content-range", None) - if not contentRange: - # server doesn't support partial requests, oh well - self.requestedPartial = 0 - return - start, end, realLength = http.parseContentRange(contentRange[0]) - if start != self.requestedPartial: - # server is acting wierdly - self.requestedPartial = 0 - - def openFile(self, partialContent): - if partialContent: - file = open(self.fileName, 'rb+') - file.seek(0, 2) - else: - file = open(self.fileName, 'wb') - return file - - def pageStart(self, partialContent): - """Called on page download start. - - @param partialContent: tells us if the download is partial download we requested. - """ - if partialContent and not self.requestedPartial: - raise ValueError, "we shouldn't get partial content response if we didn't want it!" - if self.waiting: - self.waiting = 0 - try: - if not self.file: - self.file = self.openFile(partialContent) - except IOError: - #raise - self.deferred.errback(failure.Failure()) - - def pagePart(self, data): - if not self.file: - return - try: - self.file.write(data) - except IOError: - #raise - self.file = None - self.deferred.errback(failure.Failure()) - - def pageEnd(self): - if not self.file: - return - try: - self.file.close() - except IOError: - self.deferred.errback(failure.Failure()) - return - self.deferred.callback(self.value) - - -def _parse(url, defaultPort=None): - """ - Split the given URL into the scheme, host, port, and path. - - @type url: C{str} - @param url: An URL to parse. - - @type defaultPort: C{int} or C{None} - @param defaultPort: An alternate value to use as the port if the URL does - not include one. - - @return: A four-tuple of the scheme, host, port, and path of the URL. All - of these are C{str} instances except for port, which is an C{int}. - """ - url = url.strip() - parsed = http.urlparse(url) - scheme = parsed[0] - path = urlunparse(('','')+parsed[2:]) - if defaultPort is None: - if scheme == 'https': - defaultPort = 443 - else: - defaultPort = 80 - host, port = parsed[1], defaultPort - if ':' in host: - host, port = host.split(':') - port = int(port) - if path == "": - path = "/" - return scheme, host, port, path - - -def getPage(url, contextFactory=None, *args, **kwargs): - """Download a web page as a string. - - Download a page. Return a deferred, which will callback with a - page (as a string) or errback with a description of the error. - - See HTTPClientFactory to see what extra args can be passed. - """ - scheme, host, port, path = _parse(url) - factory = HTTPClientFactory(url, *args, **kwargs) - if scheme == 'https': - from twisted.internet import ssl - if contextFactory is None: - contextFactory = ssl.ClientContextFactory() - reactor.connectSSL(host, port, factory, contextFactory) - else: - reactor.connectTCP(host, port, factory) - return factory.deferred - - -def downloadPage(url, file, contextFactory=None, *args, **kwargs): - """Download a web page to a file. - - @param file: path to file on filesystem, or file-like object. - - See HTTPDownloader to see what extra args can be passed. - """ - scheme, host, port, path = _parse(url) - factory = HTTPDownloader(url, file, *args, **kwargs) - if scheme == 'https': - from twisted.internet import ssl - if contextFactory is None: - contextFactory = ssl.ClientContextFactory() - reactor.connectSSL(host, port, factory, contextFactory) - else: - reactor.connectTCP(host, port, factory) - return factory.deferred diff --git a/tools/buildbot/pylibs/twisted/web/demo.py b/tools/buildbot/pylibs/twisted/web/demo.py deleted file mode 100644 index 57df240..0000000 --- a/tools/buildbot/pylibs/twisted/web/demo.py +++ /dev/null @@ -1,29 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""I am a simple test resource. -""" - -from twisted.python import log -from twisted.web import static - -class Test(static.Data): - isLeaf = True - def __init__(self): - static.Data.__init__( - self, - """ - <html> - <head><title>Temporary Test</title><head> - <body> - - Hello! This is a temporary test until a more sophisticated form - demo can be put back in using more up-to-date Twisted APIs. - - </body> - </html> - """, - "text/html") - diff --git a/tools/buildbot/pylibs/twisted/web/distrib.py b/tools/buildbot/pylibs/twisted/web/distrib.py deleted file mode 100644 index df2141b..0000000 --- a/tools/buildbot/pylibs/twisted/web/distrib.py +++ /dev/null @@ -1,303 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_web -*- - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Distributed web servers. - -This is going to have to be refactored so that argument parsing is done -by each subprocess and not by the main web server (i.e. GET, POST etc.). -""" - -# System Imports -import types, os, copy, string, cStringIO -if (os.sys.platform != 'win32') and (os.name != 'java'): - import pwd - -# Twisted Imports -from twisted.spread import pb -from twisted.web import http -from twisted.python import log -from twisted.persisted import styles -from twisted.web.woven import page -from twisted.internet import address, reactor - -# Sibling Imports -import resource -import server -import error -import html -import static -from server import NOT_DONE_YET - -class _ReferenceableProducerWrapper(pb.Referenceable): - def __init__(self, producer): - self.producer = producer - - def remote_resumeProducing(self): - self.producer.resumeProducing() - - def remote_pauseProducing(self): - self.producer.pauseProducing() - - def remote_stopProducing(self): - self.producer.stopProducing() - - -class Request(pb.RemoteCopy, server.Request): - def setCopyableState(self, state): - for k in 'host', 'client': - tup = state[k] - addrdesc = {'INET': 'TCP', 'UNIX': 'UNIX'}[tup[0]] - addr = {'TCP': lambda: address.IPv4Address(addrdesc, - tup[1], tup[2], - _bwHack='INET'), - 'UNIX': lambda: address.UNIXAddress(tup[1])}[addrdesc]() - state[k] = addr - pb.RemoteCopy.setCopyableState(self, state) - # Emulate the local request interface -- - self.content = cStringIO.StringIO(self.content_data) - self.write = self.remote.remoteMethod('write') - self.finish = self.remote.remoteMethod('finish') - self.setHeader = self.remote.remoteMethod('setHeader') - self.addCookie = self.remote.remoteMethod('addCookie') - self.setETag = self.remote.remoteMethod('setETag') - self.setResponseCode = self.remote.remoteMethod('setResponseCode') - self.setLastModified = self.remote.remoteMethod('setLastModified') - - def registerProducer(self, producer, streaming): - self.remote.callRemote("registerProducer", - _ReferenceableProducerWrapper(producer), - streaming).addErrback(self.fail) - - def unregisterProducer(self): - self.remote.callRemote("unregisterProducer").addErrback(self.fail) - - def fail(self, failure): - log.err(failure) - - -pb.setCopierForClass(server.Request, Request) - -class Issue: - def __init__(self, request): - self.request = request - - def finished(self, result): - if result != NOT_DONE_YET: - assert isinstance(result, types.StringType),\ - "return value not a string" - self.request.write(result) - self.request.finish() - - def failed(self, failure): - #XXX: Argh. FIXME. - failure = str(failure) - self.request.write( - error.ErrorPage(http.INTERNAL_SERVER_ERROR, - "Server Connection Lost", - "Connection to distributed server lost:" + - html.PRE(failure)). - render(self.request)) - self.request.finish() - log.msg(failure) - - -class ResourceSubscription(resource.Resource): - isLeaf = 1 - waiting = 0 - def __init__(self, host, port): - resource.Resource.__init__(self) - self.host = host - self.port = port - self.pending = [] - self.publisher = None - - def __getstate__(self): - """Get persistent state for this ResourceSubscription. - """ - # When I unserialize, - state = copy.copy(self.__dict__) - # Publisher won't be connected... - state['publisher'] = None - # I won't be making a connection - state['waiting'] = 0 - # There will be no pending requests. - state['pending'] = [] - return state - - def connected(self, publisher): - """I've connected to a publisher; I'll now send all my requests. - """ - log.msg('connected to publisher') - publisher.broker.notifyOnDisconnect(self.booted) - self.publisher = publisher - self.waiting = 0 - for request in self.pending: - self.render(request) - self.pending = [] - - def notConnected(self, msg): - """I can't connect to a publisher; I'll now reply to all pending - requests. - """ - log.msg("could not connect to distributed web service: %s" % msg) - self.waiting = 0 - self.publisher = None - for request in self.pending: - request.write("Unable to connect to distributed server.") - request.finish() - self.pending = [] - - def booted(self): - self.notConnected("connection dropped") - - def render(self, request): - """Render this request, from my server. - - This will always be asynchronous, and therefore return NOT_DONE_YET. - It spins off a request to the pb client, and either adds it to the list - of pending issues or requests it immediately, depending on if the - client is already connected. - """ - if not self.publisher: - self.pending.append(request) - if not self.waiting: - self.waiting = 1 - bf = pb.PBClientFactory() - timeout = 10 - if self.host == "unix": - reactor.connectUNIX(self.port, bf, timeout) - else: - reactor.connectTCP(self.host, self.port, bf, timeout) - d = bf.getRootObject() - d.addCallbacks(self.connected, self.notConnected) - - else: - i = Issue(request) - self.publisher.callRemote('request', request).addCallbacks(i.finished, i.failed) - return NOT_DONE_YET - -class ResourcePublisher(pb.Root, styles.Versioned): - def __init__(self, site): - self.site = site - - persistenceVersion = 2 - - def upgradeToVersion2(self): - self.application.authorizer.removeIdentity("web") - del self.application.services[self.serviceName] - del self.serviceName - del self.application - del self.perspectiveName - - def getPerspectiveNamed(self, name): - return self - - def remote_request(self, request): - res = self.site.getResourceFor(request) - log.msg( request ) - return res.render(request) - -class UserDirectory(page.Page): - userDirName = 'public_html' - userSocketName = '.twistd-web-pb' - - template = """ -<html> - <head> - <title>twisted.web.distrib.UserDirectory</title> - <style> - - a - { - font-family: Lucida, Verdana, Helvetica, Arial, sans-serif; - color: #369; - text-decoration: none; - } - - th - { - font-family: Lucida, Verdana, Helvetica, Arial, sans-serif; - font-weight: bold; - text-decoration: none; - text-align: left; - } - - pre, code - { - font-family: "Courier New", Courier, monospace; - } - - p, body, td, ol, ul, menu, blockquote, div - { - font-family: Lucida, Verdana, Helvetica, Arial, sans-serif; - color: #000; - } - - </style> - <base view="Attributes" model="base" /> - </head> - - <body> - <h1>twisted.web.distrib.UserDirectory</h1> - - <ul view="List" model="directory"> - <li pattern="listItem"><a view="Link" /> </li> - </ul> -</body> -</html> - """ - - def wmfactory_base(self, request): - return {'href':request.prePathURL()} - - def wmfactory_directory(self, request): - m = [] - for user in pwd.getpwall(): - pw_name, pw_passwd, pw_uid, pw_gid, pw_gecos, pw_dir, pw_shell \ - = user - realname = string.split(pw_gecos,',')[0] - if not realname: - realname = pw_name - if os.path.exists(os.path.join(pw_dir, self.userDirName)): - m.append({ - 'href':'%s/'%pw_name, - 'text':'%s (file)'%realname - }) - twistdsock = os.path.join(pw_dir, self.userSocketName) - if os.path.exists(twistdsock): - linknm = '%s.twistd' % pw_name - m.append({ - 'href':'%s/'%linknm, - 'text':'%s (twistd)'%realname}) - return m - - def getChild(self, name, request): - if name == '': - return self - - td = '.twistd' - - if name[-len(td):] == td: - username = name[:-len(td)] - sub = 1 - else: - username = name - sub = 0 - try: - pw_name, pw_passwd, pw_uid, pw_gid, pw_gecos, pw_dir, pw_shell \ - = pwd.getpwnam(username) - except KeyError: - return error.NoResource() - if sub: - twistdsock = os.path.join(pw_dir, self.userSocketName) - rs = ResourceSubscription('unix',twistdsock) - self.putChild(name, rs) - return rs - else: - path = os.path.join(pw_dir, self.userDirName) - if not os.path.exists(path): - return error.NoResource() - return static.File(path) diff --git a/tools/buildbot/pylibs/twisted/web/domhelpers.py b/tools/buildbot/pylibs/twisted/web/domhelpers.py deleted file mode 100644 index e1322c4..0000000 --- a/tools/buildbot/pylibs/twisted/web/domhelpers.py +++ /dev/null @@ -1,260 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_woven -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -from __future__ import nested_scopes - -from twisted.web import microdom -from microdom import getElementsByTagName, escape, unescape - -try: - import cStringIO as StringIO -except ImportError: - import StringIO - -class NodeLookupError(Exception): pass - - -def substitute(request, node, subs): - """ - Look through the given node's children for strings, and - attempt to do string substitution with the given parameter. - """ - for child in node.childNodes: - if hasattr(child, 'nodeValue') and child.nodeValue: - child.replaceData(0, len(child.nodeValue), child.nodeValue % subs) - substitute(request, child, subs) - -def _get(node, nodeId, nodeAttrs=('id','class','model','pattern')): - """ - (internal) Get a node with the specified C{nodeId} as any of the C{class}, - C{id} or C{pattern} attributes. - """ - - if hasattr(node, 'hasAttributes') and node.hasAttributes(): - for nodeAttr in nodeAttrs: - if (str (node.getAttribute(nodeAttr)) == nodeId): - return node - if node.hasChildNodes(): - if hasattr(node.childNodes, 'length'): - length = node.childNodes.length - else: - length = len(node.childNodes) - for childNum in range(length): - result = _get(node.childNodes[childNum], nodeId) - if result: return result - -def get(node, nodeId): - """ - Get a node with the specified C{nodeId} as any of the C{class}, - C{id} or C{pattern} attributes. If there is no such node, raise - L{NodeLookupError}. - """ - result = _get(node, nodeId) - if result: return result - raise NodeLookupError, nodeId - -def getIfExists(node, nodeId): - """ - Get a node with the specified C{nodeId} as any of the C{class}, - C{id} or C{pattern} attributes. If there is no such node, return - C{None}. - """ - return _get(node, nodeId) - -def getAndClear(node, nodeId): - """Get a node with the specified C{nodeId} as any of the C{class}, - C{id} or C{pattern} attributes. If there is no such node, raise - L{NodeLookupError}. Remove all child nodes before returning. - """ - result = get(node, nodeId) - if result: - clearNode(result) - return result - -def clearNode(node): - """ - Remove all children from the given node. - """ - node.childNodes[:] = [] - -def locateNodes(nodeList, key, value, noNesting=1): - """ - Find subnodes in the given node where the given attribute - has the given value. - """ - returnList = [] - if not isinstance(nodeList, type([])): - return locateNodes(nodeList.childNodes, key, value, noNesting) - for childNode in nodeList: - if not hasattr(childNode, 'getAttribute'): - continue - if str(childNode.getAttribute(key)) == value: - returnList.append(childNode) - if noNesting: - continue - returnList.extend(locateNodes(childNode, key, value, noNesting)) - return returnList - -def superSetAttribute(node, key, value): - if not hasattr(node, 'setAttribute'): return - node.setAttribute(key, value) - if node.hasChildNodes(): - for child in node.childNodes: - superSetAttribute(child, key, value) - -def superPrependAttribute(node, key, value): - if not hasattr(node, 'setAttribute'): return - old = node.getAttribute(key) - if old: - node.setAttribute(key, value+'/'+old) - else: - node.setAttribute(key, value) - if node.hasChildNodes(): - for child in node.childNodes: - superPrependAttribute(child, key, value) - -def superAppendAttribute(node, key, value): - if not hasattr(node, 'setAttribute'): return - old = node.getAttribute(key) - if old: - node.setAttribute(key, old + '/' + value) - else: - node.setAttribute(key, value) - if node.hasChildNodes(): - for child in node.childNodes: - superAppendAttribute(child, key, value) - -def gatherTextNodes(iNode, dounescape=0, joinWith=""): - """Visit each child node and collect its text data, if any, into a string. -For example:: - >>> doc=microdom.parseString('<a>1<b>2<c>3</c>4</b></a>') - >>> gatherTextNodes(doc.documentElement) - '1234' -With dounescape=1, also convert entities back into normal characters. -@return: the gathered nodes as a single string -@rtype: str -""" - gathered=[] - gathered_append=gathered.append - slice=[iNode] - while len(slice)>0: - c=slice.pop(0) - if hasattr(c, 'nodeValue') and c.nodeValue is not None: - if dounescape: - val=unescape(c.nodeValue) - else: - val=c.nodeValue - gathered_append(val) - slice[:0]=c.childNodes - return joinWith.join(gathered) - -class RawText(microdom.Text): - """This is an evil and horrible speed hack. Basically, if you have a big - chunk of XML that you want to insert into the DOM, but you don't want to - incur the cost of parsing it, you can construct one of these and insert it - into the DOM. This will most certainly only work with microdom as the API - for converting nodes to xml is different in every DOM implementation. - - This could be improved by making this class a Lazy parser, so if you - inserted this into the DOM and then later actually tried to mutate this - node, it would be parsed then. - """ - - def writexml(self, writer, indent="", addindent="", newl="", strip=0, nsprefixes=None, namespace=None): - writer.write("%s%s%s" % (indent, self.data, newl)) - -def findNodes(parent, matcher, accum=None): - if accum is None: - accum = [] - if not parent.hasChildNodes(): - return accum - for child in parent.childNodes: - # print child, child.nodeType, child.nodeName - if matcher(child): - accum.append(child) - findNodes(child, matcher, accum) - return accum - - -def findNodesShallowOnMatch(parent, matcher, recurseMatcher, accum=None): - if accum is None: - accum = [] - if not parent.hasChildNodes(): - return accum - for child in parent.childNodes: - # print child, child.nodeType, child.nodeName - if matcher(child): - accum.append(child) - if recurseMatcher(child): - findNodesShallowOnMatch(child, matcher, recurseMatcher, accum) - return accum - -def findNodesShallow(parent, matcher, accum=None): - if accum is None: - accum = [] - if not parent.hasChildNodes(): - return accum - for child in parent.childNodes: - if matcher(child): - accum.append(child) - else: - findNodes(child, matcher, accum) - return accum - - -def findElementsWithAttributeShallow(parent, attribute): - return findNodesShallow(parent, - lambda n: isinstance(n, microdom.Element) and - n.hasAttribute(attribute)) - - -def findElements(parent, matcher): - return findNodes( - parent, - lambda n, matcher=matcher: isinstance(n, microdom.Element) and - matcher(n)) - -def findElementsWithAttribute(parent, attribute, value=None): - if value: - return findElements( - parent, - lambda n, attribute=attribute, value=value: - n.hasAttribute(attribute) and n.getAttribute(attribute) == value) - else: - return findElements( - parent, - lambda n, attribute=attribute: n.hasAttribute(attribute)) - - -def findNodesNamed(parent, name): - return findNodes(parent, lambda n, name=name: n.nodeName == name) - - -def writeNodeData(node, oldio): - for subnode in node.childNodes: - if hasattr(subnode, 'data'): - oldio.write(str(subnode.data)) - else: - writeNodeData(subnode, oldio) - - -def getNodeText(node): - oldio = StringIO.StringIO() - writeNodeData(node, oldio) - return oldio.getvalue() - -def getParents(node): - l = [] - while node: - l.append(node) - node = node.parentNode - return l - -def namedChildren(parent, nodeName): - """namedChildren(parent, nodeName) -> children (not descendants) of parent - that have tagName == nodeName - """ - return [n for n in parent.childNodes if getattr(n, 'tagName', '')==nodeName] diff --git a/tools/buildbot/pylibs/twisted/web/error.py b/tools/buildbot/pylibs/twisted/web/error.py deleted file mode 100644 index 737f1f5..0000000 --- a/tools/buildbot/pylibs/twisted/web/error.py +++ /dev/null @@ -1,61 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""I am the Twisted.Web error resources and exceptions.""" - -#t.w imports -import resource - -from twisted.web import http - -class Error(Exception): - def __init__(self, code, message = None, response = None): - message = message or http.responses.get(code) - Exception.__init__(self, code, message, response) - self.status = code - self.response = response - - def __str__(self): - return '%s %s' % (self[0], self[1]) - -class PageRedirect(Error): - """A request that resulted in a http redirect """ - def __init__(self, code, message = None, response = None, location = None): - message = message or ("%s to %s" % (http.responses.get(code), location)) - Error.__init__(self, code, message, response) - self.location = location - -class ErrorPage(resource.Resource): - def __init__(self, status, brief, detail): - resource.Resource.__init__(self) - self.code = status - self.brief = brief - self.detail = detail - - def render(self, request): - request.setResponseCode(self.code) - request.setHeader("content-type", "text/html") - return ("""<html> - <head><title>%s - %s</title></head> - <body><h1>%s</h1> - <p>%s</p> - </body></html>\n\n""" % - (self.code, self.brief, self.brief, self.detail)) - - def getChild(self, chnam, request): - return self - - -class NoResource(ErrorPage): - def __init__(self, message="Sorry. No luck finding that resource."): - ErrorPage.__init__(self, http.NOT_FOUND, - "No Such Resource", - message) - -class ForbiddenResource(ErrorPage): - def __init__(self, message="Sorry, resource is forbidden."): - ErrorPage.__init__(self, http.FORBIDDEN, - "Forbidden Resource", - message) diff --git a/tools/buildbot/pylibs/twisted/web/google.py b/tools/buildbot/pylibs/twisted/web/google.py deleted file mode 100644 index a0b8e8f..0000000 --- a/tools/buildbot/pylibs/twisted/web/google.py +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -"""\"I'm Feeling Lucky\" with U{Google<http://google.com>}. -""" -import urllib -from twisted.internet import protocol, reactor, defer -from twisted.web import http - -class GoogleChecker(http.HTTPClient): - - def connectionMade(self): - self.sendCommand('GET', self.factory.url) - self.sendHeader('Host', self.factory.host) - self.sendHeader('User-Agent', self.factory.agent) - self.endHeaders() - - def handleHeader(self, key, value): - key = key.lower() - if key == 'location': - self.factory.gotLocation(value) - - def handleStatus(self, version, status, message): - if status != '302': - self.factory.noLocation(ValueError("bad status")) - - def handleEndHeaders(self): - self.factory.noLocation(ValueError("no location")) - - def handleResponsePart(self, part): - pass - - def handleResponseEnd(self): - pass - - def connectionLost(self, reason): - self.factory.noLocation(reason) - - -class GoogleCheckerFactory(protocol.ClientFactory): - - protocol = GoogleChecker - - def __init__(self, words): - self.url = ('/search?q=%s&btnI=%s' % - (urllib.quote_plus(' '.join(words)), - urllib.quote_plus("I'm Feeling Lucky"))) - self.agent="Twisted/GoogleChecker" - self.host = "www.google.com" - self.deferred = defer.Deferred() - - def clientConnectionFailed(self, _, reason): - self.noLocation(reason) - - def gotLocation(self, location): - if self.deferred: - self.deferred.callback(location) - self.deferred = None - - def noLocation(self, error): - if self.deferred: - self.deferred.errback(error) - self.deferred = None - - -def checkGoogle(words): - """Check google for a match. - - @returns: a Deferred which will callback with a URL or errback with a - Failure. - """ - factory = GoogleCheckerFactory(words) - reactor.connectTCP('www.google.com', 80, factory) - return factory.deferred diff --git a/tools/buildbot/pylibs/twisted/web/guard.py b/tools/buildbot/pylibs/twisted/web/guard.py deleted file mode 100644 index 9b5cd3c..0000000 --- a/tools/buildbot/pylibs/twisted/web/guard.py +++ /dev/null @@ -1,217 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""DEPRECATED. - -You probably should be using twisted.web.woven.guard instead. -""" - -# System Imports -import string, traceback -from cStringIO import StringIO - -from twisted.python import log - -# Sibling Imports -import error -import html -import resource -import widgets -from server import NOT_DONE_YET - -import warnings -warnings.warn("Please use twisted.web.woven.guard", DeprecationWarning, 2) - - -class _Detacher: - """Detach a web session from an attached perspective. - - This will happen when the session expires. - """ - - def __init__(self, session, identity, perspective): - self.session = session - self.identity = identity - self.perspective = perspective - session.notifyOnExpire(self.detach) - - def detach(self): - self.perspective.detached(self.session, self.identity) - del self.session - del self.identity - del self.perspective - - -class AuthForm(widgets.Form): - formFields = [ - ['string','Identity','username',''], - ['password','Password','password',''], - ['string','Perspective','perspective',''] - ] - - formAcceptExtraArgs = 1 - - def __init__(self, reqauth, sessionIdentity=None, sessionPerspective=None): - """Initialize, specifying various options. - - @param reqauth: a web.resource.Resource instance, indicating which - resource a user will be logging into with this form; this must - specify a serviceName attribute which indicates the name of the - service from which perspectives will be requested. - - @param sessionIdentity: if specified, the name of the attribute on - the user's session to set for the identity they get from logging - in to this form. - - @param sessionPerspective: if specified, the name of the attribute on - the user's session to set for the perspective they get from - logging in to this form. - """ - self.reqauth = reqauth - self.sessionPerspective = sessionPerspective - self.sessionIdentity = sessionIdentity - - def gotPerspective(self, perspective, request, ident): - # TODO: fix this... - resKey = string.join(['AUTH',self.reqauth.service.serviceName], '_') - sess = request.getSession() - setattr(sess, resKey, perspective) - if self.sessionPerspective: - setattr(sess, self.sessionPerspective, perspective) - if self.sessionIdentity: - setattr(sess, self.sessionIdentity, ident) - p = perspective.attached(sess, ident) - _Detacher(sess, ident, p) - return self.reqauth.reallyRender(request) - - def didntGetPerspective(self, error, request): - log.msg('Password not verified! Error: %s' % error) - io = StringIO() - io.write(self.formatError("Login incorrect.")) - self.format(self.getFormFields(request), io.write, request) - return [io.getvalue()] - - def gotIdentity(self, ident, password, request, perspectiveName): - pwrq = ident.verifyPlainPassword(password) - pwrq.addCallback(self.passwordIsOk, ident, password, - request, perspectiveName) - pwrq.addErrback(self.didntGetPerspective, request) - pwrq.needsHeader = 1 - return [pwrq] - - def passwordIsOk(self, msg, ident, password, request, perspectiveName): - ret = ident.requestPerspectiveForKey(self.reqauth.service.serviceName, - perspectiveName).addCallbacks( - self.gotPerspective, self.didntGetPerspective, - callbackArgs=(request,ident), - errbackArgs=(request,)) - ret.needsHeader = 1 - return [ret] - - def didntGetIdentity(self, unauth, request): - io = StringIO() - io.write(self.formatError("Login incorrect.")) - self.format(self.getFormFields(request), io.write, request) - return io.getvalue() - - def process(self, write, request, submit, username, password, perspective): - """Process the form results. - """ - # must be done before page is displayed so cookie can get set! - request.getSession() - # this site must be tagged with an application. - idrq = self.reqauth.service.authorizer.getIdentityRequest(username) - idrq.needsHeader = 1 - idrq.addCallbacks(self.gotIdentity, self.didntGetIdentity, - callbackArgs=(password,request,perspective or username), - errbackArgs=(request,)) - return [idrq] - -class AuthPage(widgets.Page): - template = ''' - <html><head><title>Authorization Required</title></head> - <body> - <center> - %%%%authForm%%%% - </center> - </body> - </html> - ''' - authForm = None - def __init__(self, reqauth, sessionIdentity=None, sessionPerspective=None): - widgets.Page.__init__(self) - self.authForm = AuthForm(reqauth, sessionPerspective, sessionIdentity) - - -class WidgetGuard(widgets.Widget): - - def __init__(self, wid, service, - sessionIdentity=None, - sessionPerspective=None): - self.wid = wid - self.service = service - self.sessionPerspective = sessionPerspective - self.sessionIdentity = sessionIdentity - - def reallyRender(self, request): - return widgets.possiblyDeferWidget(self.wid, request) - - def display(self, request): - session = request.getSession() - resKey = string.join(['AUTH',self.service.serviceName], '_') - if hasattr(session, resKey): - return self.wid.display(request) - else: - return AuthForm(self).display(request) - - - -# TODO hiding forms behind a ResourceGuard sucks, because if -# ResourceGuard needs to authenticate the user, it will 1) complain -# about the form submitted, 2) throw the data away. This happens if -# you use "foo?a=b" -style URLs and the user hasn't authenticated yet, -# or with session expiry. - -class ResourceGuard(resource.Resource): - - isLeaf = 1 - - def __init__(self, res, service, sessionIdentity=None, sessionPerspective=None): - resource.Resource.__init__(self) - self.res = res - self.service = service - self.sessionPerspective = sessionPerspective - self.sessionIdentity = sessionIdentity - - def __getattr__(self, k): - if not self.__dict__.has_key("res"): - raise AttributeError, k - return getattr(self.res, k) - - def __getstate__(self): - return self.__dict__.copy() - - def listNames(self): - return self.res.listNames() - - def reallyRender(self, request): - # it's authenticated already... - res = resource.getChildForRequest(self.res, request) - val = res.render(request) - if val != NOT_DONE_YET: - request.write(val) - request.finish() - return widgets.FORGET_IT - - def render(self, request): - session = request.getSession() - resKey = string.join(['AUTH',self.service.serviceName], '_') - if hasattr(session, resKey): - self.reallyRender(request) - return NOT_DONE_YET - else: - return AuthPage(self, - self.sessionPerspective, - self.sessionIdentity).render(request) - diff --git a/tools/buildbot/pylibs/twisted/web/html.py b/tools/buildbot/pylibs/twisted/web/html.py deleted file mode 100644 index fd3ff5f..0000000 --- a/tools/buildbot/pylibs/twisted/web/html.py +++ /dev/null @@ -1,49 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""I hold HTML generation helpers. -""" - -from twisted.python import log -#t.w imports -from twisted.web import resource - -import traceback, string - -from cStringIO import StringIO -from microdom import escape - -def PRE(text): - "Wrap <pre> tags around some text and HTML-escape it." - return "<pre>"+escape(text)+"</pre>" - -def UL(lst): - io = StringIO() - io.write("<ul>\n") - for el in lst: - io.write("<li> %s</li>\n" % el) - io.write("</ul>") - return io.getvalue() - -def linkList(lst): - io = StringIO() - io.write("<ul>\n") - for hr, el in lst: - io.write('<li> <a href="%s">%s</a></li>\n' % (hr, el)) - io.write("</ul>") - return io.getvalue() - -def output(func, *args, **kw): - """output(func, *args, **kw) -> html string - Either return the result of a function (which presumably returns an - HTML-legal string) or a sparse HTMLized error message and a message - in the server log. - """ - try: - return func(*args, **kw) - except: - log.msg("Error calling %r:" % (func,)) - log.err() - return PRE("An error occurred.") diff --git a/tools/buildbot/pylibs/twisted/web/http.py b/tools/buildbot/pylibs/twisted/web/http.py deleted file mode 100644 index 1a68250..0000000 --- a/tools/buildbot/pylibs/twisted/web/http.py +++ /dev/null @@ -1,1244 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_http -*- - -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -HyperText Transfer Protocol implementation. - -This is used by twisted.web. - -Future Plans: - - HTTP client support will at some point be refactored to support HTTP/1.1. - - Accept chunked data from clients in server. - - Other missing HTTP features from the RFC. - -Maintainer: U{Itamar Shtull-Trauring<mailto:twisted@itamarst.org>} -""" - -# system imports -from cStringIO import StringIO -import tempfile -import base64, binascii -import cgi -import socket -import math -import time -import calendar -import warnings -import os -from urlparse import urlparse as _urlparse - -from zope.interface import implements - -# twisted imports -from twisted.internet import interfaces, reactor, protocol, address -from twisted.protocols import policies, basic -from twisted.python import log -try: # try importing the fast, C version - from twisted.protocols._c_urlarg import unquote -except ImportError: - from urllib import unquote - - -protocol_version = "HTTP/1.1" - -_CONTINUE = 100 -SWITCHING = 101 - -OK = 200 -CREATED = 201 -ACCEPTED = 202 -NON_AUTHORITATIVE_INFORMATION = 203 -NO_CONTENT = 204 -RESET_CONTENT = 205 -PARTIAL_CONTENT = 206 -MULTI_STATUS = 207 - -MULTIPLE_CHOICE = 300 -MOVED_PERMANENTLY = 301 -FOUND = 302 -SEE_OTHER = 303 -NOT_MODIFIED = 304 -USE_PROXY = 305 -TEMPORARY_REDIRECT = 307 - -BAD_REQUEST = 400 -UNAUTHORIZED = 401 -PAYMENT_REQUIRED = 402 -FORBIDDEN = 403 -NOT_FOUND = 404 -NOT_ALLOWED = 405 -NOT_ACCEPTABLE = 406 -PROXY_AUTH_REQUIRED = 407 -REQUEST_TIMEOUT = 408 -CONFLICT = 409 -GONE = 410 -LENGTH_REQUIRED = 411 -PRECONDITION_FAILED = 412 -REQUEST_ENTITY_TOO_LARGE = 413 -REQUEST_URI_TOO_LONG = 414 -UNSUPPORTED_MEDIA_TYPE = 415 -REQUESTED_RANGE_NOT_SATISFIABLE = 416 -EXPECTATION_FAILED = 417 - -INTERNAL_SERVER_ERROR = 500 -NOT_IMPLEMENTED = 501 -BAD_GATEWAY = 502 -SERVICE_UNAVAILABLE = 503 -GATEWAY_TIMEOUT = 504 -HTTP_VERSION_NOT_SUPPORTED = 505 -INSUFFICIENT_STORAGE_SPACE = 507 -NOT_EXTENDED = 510 - -RESPONSES = { - # 100 - _CONTINUE: "Continue", - SWITCHING: "Switching Protocols", - - # 200 - OK: "OK", - CREATED: "Created", - ACCEPTED: "Accepted", - NON_AUTHORITATIVE_INFORMATION: "Non-Authoritative Information", - NO_CONTENT: "No Content", - RESET_CONTENT: "Reset Content.", - PARTIAL_CONTENT: "Partial Content", - MULTI_STATUS: "Multi-Status", - - # 300 - MULTIPLE_CHOICE: "Multiple Choices", - MOVED_PERMANENTLY: "Moved Permanently", - FOUND: "Found", - SEE_OTHER: "See Other", - NOT_MODIFIED: "Not Modified", - USE_PROXY: "Use Proxy", - # 306 not defined?? - TEMPORARY_REDIRECT: "Temporary Redirect", - - # 400 - BAD_REQUEST: "Bad Request", - UNAUTHORIZED: "Unauthorized", - PAYMENT_REQUIRED: "Payment Required", - FORBIDDEN: "Forbidden", - NOT_FOUND: "Not Found", - NOT_ALLOWED: "Method Not Allowed", - NOT_ACCEPTABLE: "Not Acceptable", - PROXY_AUTH_REQUIRED: "Proxy Authentication Required", - REQUEST_TIMEOUT: "Request Time-out", - CONFLICT: "Conflict", - GONE: "Gone", - LENGTH_REQUIRED: "Length Required", - PRECONDITION_FAILED: "Precondition Failed", - REQUEST_ENTITY_TOO_LARGE: "Request Entity Too Large", - REQUEST_URI_TOO_LONG: "Request-URI Too Long", - UNSUPPORTED_MEDIA_TYPE: "Unsupported Media Type", - REQUESTED_RANGE_NOT_SATISFIABLE: "Requested Range not satisfiable", - EXPECTATION_FAILED: "Expectation Failed", - - # 500 - INTERNAL_SERVER_ERROR: "Internal Server Error", - NOT_IMPLEMENTED: "Not Implemented", - BAD_GATEWAY: "Bad Gateway", - SERVICE_UNAVAILABLE: "Service Unavailable", - GATEWAY_TIMEOUT: "Gateway Time-out", - HTTP_VERSION_NOT_SUPPORTED: "HTTP Version not supported", - INSUFFICIENT_STORAGE_SPACE: "Insufficient Storage Space", - NOT_EXTENDED: "Not Extended" - } - -CACHED = """Magic constant returned by http.Request methods to set cache -validation headers when the request is conditional and the value fails -the condition.""" - -# backwards compatability -responses = RESPONSES - - -# datetime parsing and formatting -weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] -monthname = [None, - 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', - 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] -weekdayname_lower = [name.lower() for name in weekdayname] -monthname_lower = [name and name.lower() for name in monthname] - -def urlparse(url): - """ - Parse an URL into six components. - - This is similar to L{urlparse.urlparse}, but rejects C{unicode} input - and always produces C{str} output. - - @type url: C{str} - - @raise TypeError: The given url was a C{unicode} string instead of a - C{str}. - - @rtype: six-tuple of str - @return: The scheme, net location, path, params, query string, and fragment - of the URL. - """ - if isinstance(url, unicode): - raise TypeError("url must be str, not unicode") - scheme, netloc, path, params, query, fragment = _urlparse(url) - if isinstance(scheme, unicode): - scheme = scheme.encode('ascii') - netloc = netloc.encode('ascii') - path = path.encode('ascii') - query = query.encode('ascii') - fragment = fragment.encode('ascii') - return scheme, netloc, path, params, query, fragment - - -def parse_qs(qs, keep_blank_values=0, strict_parsing=0, unquote=unquote): - """like cgi.parse_qs, only with custom unquote function""" - d = {} - items = [s2 for s1 in qs.split("&") for s2 in s1.split(";")] - for item in items: - try: - k, v = item.split("=", 1) - except ValueError: - if strict_parsing: - raise - continue - if v or keep_blank_values: - k = unquote(k.replace("+", " ")) - v = unquote(v.replace("+", " ")) - if k in d: - d[k].append(v) - else: - d[k] = [v] - return d - -def datetimeToString(msSinceEpoch=None): - """Convert seconds since epoch to HTTP datetime string.""" - if msSinceEpoch == None: - msSinceEpoch = time.time() - year, month, day, hh, mm, ss, wd, y, z = time.gmtime(msSinceEpoch) - s = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % ( - weekdayname[wd], - day, monthname[month], year, - hh, mm, ss) - return s - -def datetimeToLogString(msSinceEpoch=None): - """Convert seconds since epoch to log datetime string.""" - if msSinceEpoch == None: - msSinceEpoch = time.time() - year, month, day, hh, mm, ss, wd, y, z = time.gmtime(msSinceEpoch) - s = "[%02d/%3s/%4d:%02d:%02d:%02d +0000]" % ( - day, monthname[month], year, - hh, mm, ss) - return s - - -# a hack so we don't need to recalculate log datetime every hit, -# at the price of a small, unimportant, inaccuracy. -_logDateTime = None -_logDateTimeUsers = 0 -_resetLogDateTimeID = None - -def _resetLogDateTime(): - global _logDateTime - global _resetLogDateTime - global _resetLogDateTimeID - _logDateTime = datetimeToLogString() - _resetLogDateTimeID = reactor.callLater(1, _resetLogDateTime) - -def _logDateTimeStart(): - global _logDateTimeUsers - if not _logDateTimeUsers: - _resetLogDateTime() - _logDateTimeUsers += 1 - -def _logDateTimeStop(): - global _logDateTimeUsers - _logDateTimeUsers -= 1; - if (not _logDateTimeUsers and _resetLogDateTimeID - and _resetLogDateTimeID.active()): - _resetLogDateTimeID.cancel() - -def timegm(year, month, day, hour, minute, second): - """Convert time tuple in GMT to seconds since epoch, GMT""" - EPOCH = 1970 - assert year >= EPOCH - assert 1 <= month <= 12 - days = 365*(year-EPOCH) + calendar.leapdays(EPOCH, year) - for i in range(1, month): - days = days + calendar.mdays[i] - if month > 2 and calendar.isleap(year): - days = days + 1 - days = days + day - 1 - hours = days*24 + hour - minutes = hours*60 + minute - seconds = minutes*60 + second - return seconds - -def stringToDatetime(dateString): - """Convert an HTTP date string (one of three formats) to seconds since epoch.""" - parts = dateString.split() - - if not parts[0][0:3].lower() in weekdayname_lower: - # Weekday is stupid. Might have been omitted. - try: - return stringToDatetime("Sun, "+dateString) - except ValueError: - # Guess not. - pass - - partlen = len(parts) - if (partlen == 5 or partlen == 6) and parts[1].isdigit(): - # 1st date format: Sun, 06 Nov 1994 08:49:37 GMT - # (Note: "GMT" is literal, not a variable timezone) - # (also handles without "GMT") - # This is the normal format - day = parts[1] - month = parts[2] - year = parts[3] - time = parts[4] - elif (partlen == 3 or partlen == 4) and parts[1].find('-') != -1: - # 2nd date format: Sunday, 06-Nov-94 08:49:37 GMT - # (Note: "GMT" is literal, not a variable timezone) - # (also handles without without "GMT") - # Two digit year, yucko. - day, month, year = parts[1].split('-') - time = parts[2] - year=int(year) - if year < 69: - year = year + 2000 - elif year < 100: - year = year + 1900 - elif len(parts) == 5: - # 3rd date format: Sun Nov 6 08:49:37 1994 - # ANSI C asctime() format. - day = parts[2] - month = parts[1] - year = parts[4] - time = parts[3] - else: - raise ValueError("Unknown datetime format %r" % dateString) - - day = int(day) - month = int(monthname_lower.index(month.lower())) - year = int(year) - hour, min, sec = map(int, time.split(':')) - return int(timegm(year, month, day, hour, min, sec)) - -def toChunk(data): - """Convert string to a chunk. - - @returns: a tuple of strings representing the chunked encoding of data""" - return ("%x\r\n" % len(data), data, "\r\n") - -def fromChunk(data): - """Convert chunk to string. - - @returns: tuple (result, remaining), may raise ValueError. - """ - prefix, rest = data.split('\r\n', 1) - length = int(prefix, 16) - if length < 0: - raise ValueError("Chunk length must be >= 0, not %d" % (length,)) - if not rest[length:length + 2] == '\r\n': - raise ValueError, "chunk must end with CRLF" - return rest[:length], rest[length + 2:] - - -def parseContentRange(header): - """Parse a content-range header into (start, end, realLength). - - realLength might be None if real length is not known ('*'). - """ - kind, other = header.strip().split() - if kind.lower() != "bytes": - raise ValueError, "a range of type %r is not supported" - startend, realLength = other.split("/") - start, end = map(int, startend.split("-")) - if realLength == "*": - realLength = None - else: - realLength = int(realLength) - return (start, end, realLength) - - -class StringTransport: - """ - I am a StringIO wrapper that conforms for the transport API. I support - the `writeSequence' method. - """ - def __init__(self): - self.s = StringIO() - def writeSequence(self, seq): - self.s.write(''.join(seq)) - def __getattr__(self, attr): - return getattr(self.__dict__['s'], attr) - - -class HTTPClient(basic.LineReceiver): - """A client for HTTP 1.0 - - Notes: - You probably want to send a 'Host' header with the name of - the site you're connecting to, in order to not break name - based virtual hosting. - """ - length = None - firstLine = 1 - __buffer = None - - def sendCommand(self, command, path): - self.transport.write('%s %s HTTP/1.0\r\n' % (command, path)) - - def sendHeader(self, name, value): - self.transport.write('%s: %s\r\n' % (name, value)) - - def endHeaders(self): - self.transport.write('\r\n') - - def lineReceived(self, line): - if self.firstLine: - self.firstLine = 0 - l = line.split(None, 2) - version = l[0] - status = l[1] - try: - message = l[2] - except IndexError: - # sometimes there is no message - message = "" - self.handleStatus(version, status, message) - return - if line: - key, val = line.split(':', 1) - val = val.lstrip() - self.handleHeader(key, val) - if key.lower() == 'content-length': - self.length = int(val) - else: - self.__buffer = StringIO() - self.handleEndHeaders() - self.setRawMode() - - def connectionLost(self, reason): - self.handleResponseEnd() - - def handleResponseEnd(self): - if self.__buffer is not None: - b = self.__buffer.getvalue() - self.__buffer = None - self.handleResponse(b) - - def handleResponsePart(self, data): - self.__buffer.write(data) - - def connectionMade(self): - pass - - handleStatus = handleHeader = handleEndHeaders = lambda *args: None - - def rawDataReceived(self, data): - if self.length is not None: - data, rest = data[:self.length], data[self.length:] - self.length -= len(data) - else: - rest = '' - self.handleResponsePart(data) - if self.length == 0: - self.handleResponseEnd() - self.setLineMode(rest) - - -# response codes that must have empty bodies -NO_BODY_CODES = (204, 304) - -class Request: - """A HTTP request. - - Subclasses should override the process() method to determine how - the request will be processed. - - @ivar method: The HTTP method that was used. - @ivar uri: The full URI that was requested (includes arguments). - @ivar path: The path only (arguments not included). - @ivar args: All of the arguments, including URL and POST arguments. - @type args: A mapping of strings (the argument names) to lists of values. - i.e., ?foo=bar&foo=baz&quux=spam results in - {'foo': ['bar', 'baz'], 'quux': ['spam']}. - @ivar received_headers: All received headers - """ - - implements(interfaces.IConsumer) - - producer = None - finished = 0 - code = OK - code_message = RESPONSES[OK] - method = "(no method yet)" - clientproto = "(no clientproto yet)" - uri = "(no uri yet)" - startedWriting = 0 - chunked = 0 - sentLength = 0 # content-length of response, or total bytes sent via chunking - etag = None - lastModified = None - _forceSSL = 0 - - def __init__(self, channel, queued): - """ - @param channel: the channel we're connected to. - @param queued: are we in the request queue, or can we start writing to - the transport? - """ - self.channel = channel - self.queued = queued - self.received_headers = {} - self.received_cookies = {} - self.headers = {} # outgoing headers - self.cookies = [] # outgoing cookies - - if queued: - self.transport = StringTransport() - else: - self.transport = self.channel.transport - - def _cleanup(self): - """Called when have finished responding and are no longer queued.""" - if self.producer: - log.err(RuntimeError("Producer was not unregistered for %s" % self.uri)) - self.unregisterProducer() - self.channel.requestDone(self) - del self.channel - try: - self.content.close() - except OSError: - # win32 suckiness, no idea why it does this - pass - del self.content - - # methods for channel - end users should not use these - - def noLongerQueued(self): - """Notify the object that it is no longer queued. - - We start writing whatever data we have to the transport, etc. - - This method is not intended for users. - """ - if not self.queued: - raise RuntimeError, "noLongerQueued() got called unnecessarily." - - self.queued = 0 - - # set transport to real one and send any buffer data - data = self.transport.getvalue() - self.transport = self.channel.transport - if data: - self.transport.write(data) - - # if we have producer, register it with transport - if (self.producer is not None) and not self.finished: - self.transport.registerProducer(self.producer, self.streamingProducer) - - # if we're finished, clean up - if self.finished: - self._cleanup() - - def gotLength(self, length): - """Called when HTTP channel got length of content in this request. - - This method is not intended for users. - """ - if length < 100000: - self.content = StringIO() - else: - self.content = tempfile.TemporaryFile() - - def parseCookies(self): - """Parse cookie headers. - - This method is not intended for users.""" - cookietxt = self.getHeader("cookie") - if cookietxt: - for cook in cookietxt.split(';'): - cook = cook.lstrip() - try: - k, v = cook.split('=', 1) - self.received_cookies[k] = v - except ValueError: - pass - - def handleContentChunk(self, data): - """Write a chunk of data. - - This method is not intended for users. - """ - self.content.write(data) - - def requestReceived(self, command, path, version): - """Called by channel when all data has been received. - - This method is not intended for users. - """ - self.content.seek(0,0) - self.args = {} - self.stack = [] - - self.method, self.uri = command, path - self.clientproto = version - x = self.uri.split('?', 1) - - if len(x) == 1: - self.path = self.uri - else: - self.path, argstring = x - self.args = parse_qs(argstring, 1) - - # cache the client and server information, we'll need this later to be - # serialized and sent with the request so CGIs will work remotely - self.client = self.channel.transport.getPeer() - self.host = self.channel.transport.getHost() - - # Argument processing - args = self.args - ctype = self.getHeader('content-type') - if self.method == "POST" and ctype: - mfd = 'multipart/form-data' - key, pdict = cgi.parse_header(ctype) - if key == 'application/x-www-form-urlencoded': - args.update(parse_qs(self.content.read(), 1)) - elif key == mfd: - try: - args.update(cgi.parse_multipart(self.content, pdict)) - except KeyError, e: - if e.args[0] == 'content-disposition': - # Parse_multipart can't cope with missing - # content-dispostion headers in multipart/form-data - # parts, so we catch the exception and tell the client - # it was a bad request. - self.channel.transport.write( - "HTTP/1.1 400 Bad Request\r\n\r\n") - self.channel.transport.loseConnection() - return - raise - - self.process() - - def __repr__(self): - return '<%s %s %s>'% (self.method, self.uri, self.clientproto) - - def process(self): - """Override in subclasses. - - This method is not intended for users. - """ - pass - - - # consumer interface - - def registerProducer(self, producer, streaming): - """Register a producer.""" - if self.producer: - raise ValueError, "registering producer %s before previous one (%s) was unregistered" % (producer, self.producer) - - self.streamingProducer = streaming - self.producer = producer - - if self.queued: - producer.pauseProducing() - else: - self.transport.registerProducer(producer, streaming) - - def unregisterProducer(self): - """Unregister the producer.""" - if not self.queued: - self.transport.unregisterProducer() - self.producer = None - - # private http response methods - - def _sendError(self, code, resp=''): - self.transport.write('%s %s %s\r\n\r\n' % (self.clientproto, code, resp)) - - - # The following is the public interface that people should be - # writing to. - - def getHeader(self, key): - """Get a header that was sent from the network. - """ - return self.received_headers.get(key.lower()) - - def getCookie(self, key): - """Get a cookie that was sent from the network. - """ - return self.received_cookies.get(key) - - def finish(self): - """We are finished writing data.""" - if self.finished: - warnings.warn("Warning! request.finish called twice.", stacklevel=2) - return - - if not self.startedWriting: - # write headers - self.write('') - - if self.chunked: - # write last chunk and closing CRLF - self.transport.write("0\r\n\r\n") - - # log request - if hasattr(self.channel, "factory"): - self.channel.factory.log(self) - - self.finished = 1 - if not self.queued: - self._cleanup() - - def write(self, data): - """ - Write some data as a result of an HTTP request. The first - time this is called, it writes out response data. - """ - if not self.startedWriting: - self.startedWriting = 1 - version = self.clientproto - l = [] - l.append('%s %s %s\r\n' % (version, self.code, - self.code_message)) - # if we don't have a content length, we send data in - # chunked mode, so that we can support pipelining in - # persistent connections. - if ((version == "HTTP/1.1") and - (self.headers.get('content-length', None) is None) and - self.method != "HEAD" and self.code not in NO_BODY_CODES): - l.append("%s: %s\r\n" % ('Transfer-encoding', 'chunked')) - self.chunked = 1 - if self.lastModified is not None: - if self.headers.has_key('last-modified'): - log.msg("Warning: last-modified specified both in" - " header list and lastModified attribute.") - else: - self.setHeader('last-modified', - datetimeToString(self.lastModified)) - if self.etag is not None: - self.setHeader('ETag', self.etag) - for name, value in self.headers.items(): - l.append("%s: %s\r\n" % (name.capitalize(), value)) - for cookie in self.cookies: - l.append('%s: %s\r\n' % ("Set-Cookie", cookie)) - l.append("\r\n") - - self.transport.writeSequence(l) - - # if this is a "HEAD" request, we shouldn't return any data - if self.method == "HEAD": - self.write = lambda data: None - return - - # for certain result codes, we should never return any data - if self.code in NO_BODY_CODES: - self.write = lambda data: None - return - - self.sentLength = self.sentLength + len(data) - if data: - if self.chunked: - self.transport.writeSequence(toChunk(data)) - else: - self.transport.write(data) - - def addCookie(self, k, v, expires=None, domain=None, path=None, max_age=None, comment=None, secure=None): - """Set an outgoing HTTP cookie. - - In general, you should consider using sessions instead of cookies, see - twisted.web.server.Request.getSession and the - twisted.web.server.Session class for details. - """ - cookie = '%s=%s' % (k, v) - if expires is not None: - cookie = cookie +"; Expires=%s" % expires - if domain is not None: - cookie = cookie +"; Domain=%s" % domain - if path is not None: - cookie = cookie +"; Path=%s" % path - if max_age is not None: - cookie = cookie +"; Max-Age=%s" % max_age - if comment is not None: - cookie = cookie +"; Comment=%s" % comment - if secure: - cookie = cookie +"; Secure" - self.cookies.append(cookie) - - def setResponseCode(self, code, message=None): - """Set the HTTP response code. - """ - self.code = code - if message: - self.code_message = message - else: - self.code_message = RESPONSES.get(code, "Unknown Status") - - def setHeader(self, k, v): - """Set an outgoing HTTP header. - """ - self.headers[k.lower()] = v - - def redirect(self, url): - """Utility function that does a redirect. - - The request should have finish() called after this. - """ - self.setResponseCode(FOUND) - self.setHeader("location", url) - - def setLastModified(self, when): - """Set the X{Last-Modified} time for the response to this request. - - If I am called more than once, I ignore attempts to set - Last-Modified earlier, only replacing the Last-Modified time - if it is to a later value. - - If I am a conditional request, I may modify my response code - to L{NOT_MODIFIED} if appropriate for the time given. - - @param when: The last time the resource being returned was - modified, in seconds since the epoch. - @type when: number - @return: If I am a X{If-Modified-Since} conditional request and - the time given is not newer than the condition, I return - L{http.CACHED<CACHED>} to indicate that you should write no - body. Otherwise, I return a false value. - """ - # time.time() may be a float, but the HTTP-date strings are - # only good for whole seconds. - when = long(math.ceil(when)) - if (not self.lastModified) or (self.lastModified < when): - self.lastModified = when - - modified_since = self.getHeader('if-modified-since') - if modified_since: - modified_since = stringToDatetime(modified_since.split(';', 1)[0]) - if modified_since >= when: - self.setResponseCode(NOT_MODIFIED) - return CACHED - return None - - def setETag(self, etag): - """Set an X{entity tag} for the outgoing response. - - That's \"entity tag\" as in the HTTP/1.1 X{ETag} header, \"used - for comparing two or more entities from the same requested - resource.\" - - If I am a conditional request, I may modify my response code - to L{NOT_MODIFIED} or L{PRECONDITION_FAILED}, if appropriate - for the tag given. - - @param etag: The entity tag for the resource being returned. - @type etag: string - @return: If I am a X{If-None-Match} conditional request and - the tag matches one in the request, I return - L{http.CACHED<CACHED>} to indicate that you should write - no body. Otherwise, I return a false value. - """ - if etag: - self.etag = etag - - tags = self.getHeader("if-none-match") - if tags: - tags = tags.split() - if (etag in tags) or ('*' in tags): - self.setResponseCode(((self.method in ("HEAD", "GET")) - and NOT_MODIFIED) - or PRECONDITION_FAILED) - return CACHED - return None - - def getAllHeaders(self): - """Return dictionary of all headers the request received.""" - return self.received_headers - - def getRequestHostname(self): - """ - Get the hostname that the user passed in to the request. - - This will either use the Host: header (if it is available) or the - host we are listening on if the header is unavailable. - - @returns: the requested hostname - @rtype: C{str} - """ - return (self.getHeader('host') or - socket.gethostbyaddr(self.getHost()[1])[0] - ).split(':')[0] - - def getHost(self): - """Get my originally requesting transport's host. - - Don't rely on the 'transport' attribute, since Request objects may be - copied remotely. For information on this method's return value, see - twisted.internet.tcp.Port. - """ - return self.host - - def setHost(self, host, port, ssl=0): - """Change the host and port the request thinks it's using. - - This method is useful for working with reverse HTTP proxies (e.g. - both Squid and Apache's mod_proxy can do this), when the address - the HTTP client is using is different than the one we're listening on. - - For example, Apache may be listening on https://www.example.com, and then - forwarding requests to http://localhost:8080, but we don't want HTML produced - by Twisted to say 'http://localhost:8080', they should say 'https://www.example.com', - so we do:: - - request.setHost('www.example.com', 443, ssl=1) - - This method is experimental. - """ - self._forceSSL = ssl - self.received_headers["host"] = host - self.host = address.IPv4Address("TCP", host, port) - - def getClientIP(self): - """ - Return the IP address of the client who submitted this request. - - @returns: the client IP address - @rtype: C{str} - """ - if isinstance(self.client, address.IPv4Address): - return self.client.host - else: - return None - - def isSecure(self): - """ - Return True if this request is using a secure transport. - - Normally this method returns True if this request's HTTPChannel - instance is using a transport that implements ISSLTransport. - - This will also return True if setHost() has been called - with ssl=True. - - @returns: True if this request is secure - @rtype: C{bool} - """ - if self._forceSSL: - return True - transport = getattr(getattr(self, 'channel', None), 'transport', None) - if interfaces.ISSLTransport(transport, None) is not None: - return True - return False - - def _authorize(self): - # Authorization, (mostly) per the RFC - try: - authh = self.getHeader("Authorization") - if not authh: - self.user = self.password = '' - return - bas, upw = authh.split() - if bas.lower() != "basic": - raise ValueError - upw = base64.decodestring(upw) - self.user, self.password = upw.split(':', 1) - except (binascii.Error, ValueError): - self.user = self.password = "" - except: - log.err() - self.user = self.password = "" - - def getUser(self): - """ - Return the HTTP user sent with this request, if any. - - If no user was supplied, return the empty string. - - @returns: the HTTP user, if any - @rtype: C{str} - """ - try: - return self.user - except: - pass - self._authorize() - return self.user - - def getPassword(self): - """ - Return the HTTP password sent with this request, if any. - - If no password was supplied, return the empty string. - - @returns: the HTTP password, if any - @rtype: C{str} - """ - try: - return self.password - except: - pass - self._authorize() - return self.password - - def getClient(self): - if self.client.type != 'TCP': - return None - host = self.client.host - try: - name, names, addresses = socket.gethostbyaddr(host) - except socket.error: - return host - names.insert(0, name) - for name in names: - if '.' in name: - return name - return names[0] - - def connectionLost(self, reason): - """connection was lost""" - pass - -class HTTPChannel(basic.LineReceiver, policies.TimeoutMixin): - """A receiver for HTTP requests.""" - - maxHeaders = 500 # max number of headers allowed per request - - length = 0 - persistent = 1 - __header = '' - __first_line = 1 - __content = None - - # set in instances or subclasses - requestFactory = Request - - _savedTimeOut = None - - def __init__(self): - # the request queue - self.requests = [] - - def connectionMade(self): - self.setTimeout(self.timeOut) - - def lineReceived(self, line): - self.resetTimeout() - - if self.__first_line: - # if this connection is not persistent, drop any data which - # the client (illegally) sent after the last request. - if not self.persistent: - self.dataReceived = self.lineReceived = lambda *args: None - return - - # IE sends an extraneous empty line (\r\n) after a POST request; - # eat up such a line, but only ONCE - if not line and self.__first_line == 1: - self.__first_line = 2 - return - - # create a new Request object - request = self.requestFactory(self, len(self.requests)) - self.requests.append(request) - - self.__first_line = 0 - parts = line.split() - if len(parts) != 3: - self.transport.write("HTTP/1.1 400 Bad Request\r\n\r\n") - self.transport.loseConnection() - return - command, request, version = parts - self._command = command - self._path = request - self._version = version - elif line == '': - if self.__header: - self.headerReceived(self.__header) - self.__header = '' - self.allHeadersReceived() - if self.length == 0: - self.allContentReceived() - else: - self.setRawMode() - elif line[0] in ' \t': - self.__header = self.__header+'\n'+line - else: - if self.__header: - self.headerReceived(self.__header) - self.__header = line - - def headerReceived(self, line): - """Do pre-processing (for content-length) and store this header away. - """ - header, data = line.split(':', 1) - header = header.lower() - data = data.strip() - if header == 'content-length': - self.length = int(data) - reqHeaders = self.requests[-1].received_headers - reqHeaders[header] = data - if len(reqHeaders) > self.maxHeaders: - self.transport.write("HTTP/1.1 400 Bad Request\r\n\r\n") - self.transport.loseConnection() - - def allContentReceived(self): - command = self._command - path = self._path - version = self._version - - # reset ALL state variables, so we don't interfere with next request - self.length = 0 - self._header = '' - self.__first_line = 1 - del self._command, self._path, self._version - - # Disable the idle timeout, in case this request takes a long - # time to finish generating output. - if self.timeOut: - self._savedTimeOut = self.setTimeout(None) - - req = self.requests[-1] - req.requestReceived(command, path, version) - - def rawDataReceived(self, data): - if len(data) < self.length: - self.requests[-1].handleContentChunk(data) - self.length = self.length - len(data) - else: - self.requests[-1].handleContentChunk(data[:self.length]) - extraneous = data[self.length:] - self.allContentReceived() - self.setLineMode(extraneous) - - def allHeadersReceived(self): - req = self.requests[-1] - req.parseCookies() - self.persistent = self.checkPersistence(req, self._version) - req.gotLength(self.length) - - def checkPersistence(self, request, version): - """Check if the channel should close or not.""" - connection = request.getHeader('connection') - if connection: - tokens = map(str.lower, connection.split(' ')) - else: - tokens = [] - - # HTTP 1.0 persistent connection support is currently disabled, - # since we need a way to disable pipelining. HTTP 1.0 can't do - # pipelining since we can't know in advance if we'll have a - # content-length header, if we don't have the header we need to close the - # connection. In HTTP 1.1 this is not an issue since we use chunked - # encoding if content-length is not available. - - #if version == "HTTP/1.0": - # if 'keep-alive' in tokens: - # request.setHeader('connection', 'Keep-Alive') - # return 1 - # else: - # return 0 - if version == "HTTP/1.1": - if 'close' in tokens: - request.setHeader('connection', 'close') - return 0 - else: - return 1 - else: - return 0 - - def requestDone(self, request): - """Called by first request in queue when it is done.""" - if request != self.requests[0]: raise TypeError - del self.requests[0] - - if self.persistent: - # notify next request it can start writing - if self.requests: - self.requests[0].noLongerQueued() - else: - if self._savedTimeOut: - self.setTimeout(self._savedTimeOut) - else: - self.transport.loseConnection() - - def timeoutConnection(self): - log.msg("Timing out client: %s" % str(self.transport.getPeer())) - policies.TimeoutMixin.timeoutConnection(self) - - def connectionLost(self, reason): - self.setTimeout(None) - for request in self.requests: - request.connectionLost(reason) - - -class HTTPFactory(protocol.ServerFactory): - """Factory for HTTP server.""" - - protocol = HTTPChannel - - logPath = None - - timeOut = 60 * 60 * 12 - - def __init__(self, logPath=None, timeout=60*60*12): - if logPath is not None: - logPath = os.path.abspath(logPath) - self.logPath = logPath - self.timeOut = timeout - - def buildProtocol(self, addr): - p = protocol.ServerFactory.buildProtocol(self, addr) - # timeOut needs to be on the Protocol instance cause - # TimeoutMixin expects it there - p.timeOut = self.timeOut - return p - - def startFactory(self): - _logDateTimeStart() - if self.logPath: - self.logFile = self._openLogFile(self.logPath) - else: - self.logFile = log.logfile - - def stopFactory(self): - if hasattr(self, "logFile"): - if self.logFile != log.logfile: - self.logFile.close() - del self.logFile - _logDateTimeStop() - - def _openLogFile(self, path): - """Override in subclasses, e.g. to use twisted.python.logfile.""" - f = open(path, "a", 1) - return f - - def _escape(self, s): - # pain in the ass. Return a string like python repr, but always - # escaped as if surrounding quotes were "". - r = repr(s) - if r[0] == "'": - return r[1:-1].replace('"', '\\"').replace("\\'", "'") - return r[1:-1] - - def log(self, request): - """Log a request's result to the logfile, by default in combined log format.""" - if hasattr(self, "logFile"): - line = '%s - - %s "%s" %d %s "%s" "%s"\n' % ( - request.getClientIP(), - # request.getUser() or "-", # the remote user is almost never important - _logDateTime, - '%s %s %s' % (self._escape(request.method), - self._escape(request.uri), - self._escape(request.clientproto)), - request.code, - request.sentLength or "-", - self._escape(request.getHeader("referer") or "-"), - self._escape(request.getHeader("user-agent") or "-")) - self.logFile.write(line) diff --git a/tools/buildbot/pylibs/twisted/web/microdom.py b/tools/buildbot/pylibs/twisted/web/microdom.py deleted file mode 100644 index b7b430c..0000000 --- a/tools/buildbot/pylibs/twisted/web/microdom.py +++ /dev/null @@ -1,873 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_xml -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -"""Micro Document Object Model: a partial DOM implementation with SUX. - -This is an implementation of what we consider to be the useful subset of the -DOM. The chief advantage of this library is that, not being burdened with -standards compliance, it can remain very stable between versions. We can also -implement utility 'pythonic' ways to access and mutate the XML tree. - -Since this has not subjected to a serious trial by fire, it is not recommended -to use this outside of Twisted applications. However, it seems to work just -fine for the documentation generator, which parses a fairly representative -sample of XML. - -Microdom mainly focuses on working with HTML and XHTML. -""" - -from __future__ import nested_scopes - -# System Imports -import re -from cStringIO import StringIO - -# Twisted Imports -from twisted.web.sux import XMLParser, ParseError -from twisted.python.util import InsensitiveDict - -# create NodeList class -from types import ListType as NodeList -from types import StringTypes, UnicodeType - -def getElementsByTagName(iNode, name): - matches = [] - matches_append = matches.append # faster lookup. don't do this at home - slice=[iNode] - while len(slice)>0: - c = slice.pop(0) - if c.nodeName == name: - matches_append(c) - slice[:0] = c.childNodes - return matches - -def getElementsByTagNameNoCase(iNode, name): - name = name.lower() - matches = [] - matches_append = matches.append - slice=[iNode] - while len(slice)>0: - c = slice.pop(0) - if c.nodeName.lower() == name: - matches_append(c) - slice[:0] = c.childNodes - return matches - -# order is important -HTML_ESCAPE_CHARS = (('&', '&'), # don't add any entities before this one - ('<', '<'), - ('>', '>'), - ('"', '"')) -REV_HTML_ESCAPE_CHARS = list(HTML_ESCAPE_CHARS) -REV_HTML_ESCAPE_CHARS.reverse() - -XML_ESCAPE_CHARS = HTML_ESCAPE_CHARS + (("'", '''),) -REV_XML_ESCAPE_CHARS = list(XML_ESCAPE_CHARS) -REV_XML_ESCAPE_CHARS.reverse() - -def unescape(text, chars=REV_HTML_ESCAPE_CHARS): - "Perform the exact opposite of 'escape'." - for s, h in chars: - text = text.replace(h, s) - return text - -def escape(text, chars=HTML_ESCAPE_CHARS): - "Escape a few XML special chars with XML entities." - for s, h in chars: - text = text.replace(s, h) - return text - - -class MismatchedTags(Exception): - - def __init__(self, filename, expect, got, endLine, endCol, begLine, begCol): - (self.filename, self.expect, self.got, self.begLine, self.begCol, self.endLine, - self.endCol) = filename, expect, got, begLine, begCol, endLine, endCol - - def __str__(self): - return ("expected </%s>, got </%s> line: %s col: %s, began line: %s col: %s" - % (self.expect, self.got, self.endLine, self.endCol, self.begLine, - self.begCol)) - - -class Node(object): - nodeName = "Node" - - def __init__(self, parentNode=None): - self.parentNode = parentNode - self.childNodes = [] - - def isEqualToNode(self, n): - for a, b in zip(self.childNodes, n.childNodes): - if not a.isEqualToNode(b): - return 0 - return 1 - - def writexml(self, stream, indent='', addindent='', newl='', strip=0, - nsprefixes={}, namespace=''): - raise NotImplementedError() - - def toxml(self, indent='', addindent='', newl='', strip=0, nsprefixes={}, - namespace=''): - s = StringIO() - self.writexml(s, indent, addindent, newl, strip, nsprefixes, namespace) - rv = s.getvalue() - return rv - - def writeprettyxml(self, stream, indent='', addindent=' ', newl='\n', strip=0): - return self.writexml(stream, indent, addindent, newl, strip) - - def toprettyxml(self, indent='', addindent=' ', newl='\n', strip=0): - return self.toxml(indent, addindent, newl, strip) - - def cloneNode(self, deep=0, parent=None): - raise NotImplementedError() - - def hasChildNodes(self): - if self.childNodes: - return 1 - else: - return 0 - - def appendChild(self, child): - assert isinstance(child, Node) - self.childNodes.append(child) - child.parentNode = self - - def insertBefore(self, new, ref): - i = self.childNodes.index(ref) - new.parentNode = self - self.childNodes.insert(i, new) - return new - - def removeChild(self, child): - if child in self.childNodes: - self.childNodes.remove(child) - child.parentNode = None - return child - - def replaceChild(self, newChild, oldChild): - assert isinstance(newChild, Node) - #if newChild.parentNode: - # newChild.parentNode.removeChild(newChild) - assert (oldChild.parentNode is self, - ('oldChild (%s): oldChild.parentNode (%s) != self (%s)' - % (oldChild, oldChild.parentNode, self))) - self.childNodes[self.childNodes.index(oldChild)] = newChild - oldChild.parentNode = None - newChild.parentNode = self - - def lastChild(self): - return self.childNodes[-1] - - def firstChild(self): - if len(self.childNodes): - return self.childNodes[0] - return None - - #def get_ownerDocument(self): - # """This doesn't really get the owner document; microdom nodes - # don't even have one necessarily. This gets the root node, - # which is usually what you really meant. - # *NOT DOM COMPLIANT.* - # """ - # node=self - # while (node.parentNode): node=node.parentNode - # return node - #ownerDocument=node.get_ownerDocument() - # leaving commented for discussion; see also domhelpers.getParents(node) - -class Document(Node): - - def __init__(self, documentElement=None): - Node.__init__(self) - if documentElement: - self.appendChild(documentElement) - - def cloneNode(self, deep=0, parent=None): - d = Document() - d.doctype = self.doctype - if deep: - newEl = self.documentElement.cloneNode(1, self) - else: - newEl = self.documentElement - d.appendChild(newEl) - return d - - doctype = None - - def isEqualToDocument(self, n): - return (self.doctype == n.doctype) and self.isEqualToNode(n) - - def get_documentElement(self): - return self.childNodes[0] - documentElement=property(get_documentElement) - - def appendChild(self, c): - assert not self.childNodes, "Only one element per document." - Node.appendChild(self, c) - - def writexml(self, stream, indent='', addindent='', newl='', strip=0, - nsprefixes={}, namespace=''): - stream.write('<?xml version="1.0"?>' + newl) - if self.doctype: - stream.write("<!DOCTYPE "+self.doctype+">" + newl) - self.documentElement.writexml(stream, indent, addindent, newl, strip, - nsprefixes, namespace) - - # of dubious utility (?) - def createElement(self, name, **kw): - return Element(name, **kw) - - def createTextNode(self, text): - return Text(text) - - def createComment(self, text): - return Comment(text) - - def getElementsByTagName(self, name): - if self.documentElement.caseInsensitive: - return getElementsByTagNameNoCase(self, name) - return getElementsByTagName(self, name) - - def getElementById(self, id): - childNodes = self.childNodes[:] - while childNodes: - node = childNodes.pop(0) - if node.childNodes: - childNodes.extend(node.childNodes) - if hasattr(node, 'getAttribute') and node.getAttribute("id") == id: - return node - - -class EntityReference(Node): - - def __init__(self, eref, parentNode=None): - Node.__init__(self, parentNode) - self.eref = eref - self.nodeValue = self.data = "&" + eref + ";" - - def isEqualToEntityReference(self, n): - if not isinstance(n, EntityReference): - return 0 - return (self.eref == n.eref) and (self.nodeValue == n.nodeValue) - - def writexml(self, stream, indent='', addindent='', newl='', strip=0, - nsprefixes={}, namespace=''): - stream.write(self.nodeValue) - - def cloneNode(self, deep=0, parent=None): - return EntityReference(self.eref, parent) - - -class CharacterData(Node): - - def __init__(self, data, parentNode=None): - Node.__init__(self, parentNode) - self.value = self.data = self.nodeValue = data - - def isEqualToCharacterData(self, n): - return self.value == n.value - - -class Comment(CharacterData): - """A comment node.""" - - def writexml(self, stream, indent='', addindent='', newl='', strip=0, - nsprefixes={}, namespace=''): - val=self.data - if isinstance(val, UnicodeType): - val=val.encode('utf8') - stream.write("<!--%s-->" % val) - - def cloneNode(self, deep=0, parent=None): - return Comment(self.nodeValue, parent) - - -class Text(CharacterData): - - def __init__(self, data, parentNode=None, raw=0): - CharacterData.__init__(self, data, parentNode) - self.raw = raw - - def cloneNode(self, deep=0, parent=None): - return Text(self.nodeValue, parent, self.raw) - - def writexml(self, stream, indent='', addindent='', newl='', strip=0, - nsprefixes={}, namespace=''): - if self.raw: - val = self.nodeValue - if not isinstance(val, StringTypes): - val = str(self.nodeValue) - else: - v = self.nodeValue - if not isinstance(v, StringTypes): - v = str(v) - if strip: - v = ' '.join(v.split()) - val = escape(v) - if isinstance(val, UnicodeType): - val = val.encode('utf8') - stream.write(val) - - def __repr__(self): - return "Text(%s" % repr(self.nodeValue) + ')' - - -class CDATASection(CharacterData): - def cloneNode(self, deep=0, parent=None): - return CDATASection(self.nodeValue, parent) - - def writexml(self, stream, indent='', addindent='', newl='', strip=0, - nsprefixes={}, namespace=''): - stream.write("<![CDATA[") - stream.write(self.nodeValue) - stream.write("]]>") - -def _genprefix(): - i = 0 - while True: - yield 'p' + str(i) - i = i + 1 -genprefix = _genprefix().next - -class _Attr(CharacterData): - "Support class for getAttributeNode." - -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 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 - -def _unescapeDict(d): - dd = {} - for k, v in d.items(): - dd[k] = unescape(v) - return dd - -def _reverseDict(d): - dd = {} - for k, v in d.items(): - dd[v]=k - return dd - -class MicroDOMParser(XMLParser): - - # <dash> glyph: a quick scan thru the DTD says BODY, AREA, LINK, IMG, HR, - # P, DT, DD, LI, INPUT, OPTION, THEAD, TFOOT, TBODY, COLGROUP, COL, TR, TH, - # TD, HEAD, BASE, META, HTML all have optional closing tags - - soonClosers = 'area link br img hr input base meta'.split() - laterClosers = {'p': ['p', 'dt'], - 'dt': ['dt','dd'], - 'dd': ['dt', 'dd'], - 'li': ['li'], - 'tbody': ['thead', 'tfoot', 'tbody'], - 'thead': ['thead', 'tfoot', 'tbody'], - 'tfoot': ['thead', 'tfoot', 'tbody'], - 'colgroup': ['colgroup'], - 'col': ['col'], - 'tr': ['tr'], - 'td': ['td'], - 'th': ['th'], - 'head': ['body'], - 'title': ['head', 'body'], # this looks wrong... - 'option': ['option'], - } - - - def __init__(self, beExtremelyLenient=0, caseInsensitive=1, preserveCase=0, - soonClosers=soonClosers, laterClosers=laterClosers): - self.elementstack = [] - d = {'xmlns': 'xmlns', '': None} - dr = _reverseDict(d) - self.nsstack = [(d,None,dr)] - self.documents = [] - self._mddoctype = None - self.beExtremelyLenient = beExtremelyLenient - self.caseInsensitive = caseInsensitive - self.preserveCase = preserveCase or not caseInsensitive - self.soonClosers = soonClosers - self.laterClosers = laterClosers - # self.indentlevel = 0 - - def shouldPreserveSpace(self): - for edx in xrange(len(self.elementstack)): - el = self.elementstack[-edx] - if el.tagName == 'pre' or el.getAttribute("xml:space", '') == 'preserve': - return 1 - return 0 - - def _getparent(self): - if self.elementstack: - return self.elementstack[-1] - else: - return None - - COMMENT = re.compile(r"\s*/[/*]\s*") - - def _fixScriptElement(self, el): - # this deals with case where there is comment or CDATA inside - # <script> tag and we want to do the right thing with it - if not self.beExtremelyLenient or not len(el.childNodes) == 1: - return - c = el.firstChild() - if isinstance(c, Text): - # deal with nasty people who do stuff like: - # <script> // <!-- - # x = 1; - # // --></script> - # tidy does this, for example. - prefix = "" - oldvalue = c.value - match = self.COMMENT.match(oldvalue) - if match: - prefix = match.group() - oldvalue = oldvalue[len(prefix):] - - # now see if contents are actual node and comment or CDATA - try: - e = parseString("<a>%s</a>" % oldvalue).childNodes[0] - except (ParseError, MismatchedTags): - return - if len(e.childNodes) != 1: - return - e = e.firstChild() - if isinstance(e, (CDATASection, Comment)): - el.childNodes = [] - if prefix: - el.childNodes.append(Text(prefix)) - el.childNodes.append(e) - - def gotDoctype(self, doctype): - self._mddoctype = doctype - - def gotTagStart(self, name, attributes): - # print ' '*self.indentlevel, 'start tag',name - # self.indentlevel += 1 - parent = self._getparent() - if (self.beExtremelyLenient and isinstance(parent, Element)): - parentName = parent.tagName - myName = name - if self.caseInsensitive: - parentName = parentName.lower() - myName = myName.lower() - if myName in self.laterClosers.get(parentName, []): - self.gotTagEnd(parent.tagName) - parent = self._getparent() - attributes = _unescapeDict(attributes) - namespaces = self.nsstack[-1][0] - newspaces = {} - for k, v in attributes.items(): - if k.startswith('xmlns'): - spacenames = k.split(':',1) - if len(spacenames) == 2: - newspaces[spacenames[1]] = v - else: - newspaces[''] = v - del attributes[k] - if newspaces: - namespaces = namespaces.copy() - namespaces.update(newspaces) - for k, v in attributes.items(): - ksplit = k.split(':', 1) - if len(ksplit) == 2: - pfx, tv = ksplit - if pfx != 'xml' and namespaces.has_key(pfx): - attributes[namespaces[pfx], tv] = v - del attributes[k] - el = Element(name, attributes, parent, - self.filename, self.saveMark(), - caseInsensitive=self.caseInsensitive, - preserveCase=self.preserveCase, - namespace=namespaces.get('')) - revspaces = _reverseDict(newspaces) - el.addPrefixes(revspaces) - - if newspaces: - rscopy = self.nsstack[-1][2].copy() - rscopy.update(revspaces) - self.nsstack.append((namespaces, el, rscopy)) - self.elementstack.append(el) - if parent: - parent.appendChild(el) - if (self.beExtremelyLenient and el.tagName in self.soonClosers): - self.gotTagEnd(name) - - def _gotStandalone(self, factory, data): - parent = self._getparent() - te = factory(data, parent) - if parent: - parent.appendChild(te) - elif self.beExtremelyLenient: - self.documents.append(te) - - def gotText(self, data): - if data.strip() or self.shouldPreserveSpace(): - self._gotStandalone(Text, data) - - def gotComment(self, data): - self._gotStandalone(Comment, data) - - def gotEntityReference(self, entityRef): - self._gotStandalone(EntityReference, entityRef) - - def gotCData(self, cdata): - self._gotStandalone(CDATASection, cdata) - - def gotTagEnd(self, name): - # print ' '*self.indentlevel, 'end tag',name - # self.indentlevel -= 1 - if not self.elementstack: - if self.beExtremelyLenient: - return - raise MismatchedTags(*((self.filename, "NOTHING", name) - +self.saveMark()+(0,0))) - el = self.elementstack.pop() - pfxdix = self.nsstack[-1][2] - if self.nsstack[-1][1] is el: - nstuple = self.nsstack.pop() - else: - nstuple = None - if self.caseInsensitive: - tn = el.tagName.lower() - cname = name.lower() - else: - tn = el.tagName - cname = name - - nsplit = name.split(':',1) - if len(nsplit) == 2: - pfx, newname = nsplit - ns = pfxdix.get(pfx,None) - if ns is not None: - if el.namespace != ns: - if not self.beExtremelyLenient: - raise MismatchedTags(*((self.filename, el.tagName, name) - +self.saveMark()+el._markpos)) - if not (tn == cname): - if self.beExtremelyLenient: - if self.elementstack: - lastEl = self.elementstack[0] - for idx in xrange(len(self.elementstack)): - if self.elementstack[-(idx+1)].tagName == cname: - self.elementstack[-(idx+1)].endTag(name) - break - else: - # this was a garbage close tag; wait for a real one - self.elementstack.append(el) - if nstuple is not None: - self.nsstack.append(nstuple) - return - del self.elementstack[-(idx+1):] - if not self.elementstack: - self.documents.append(lastEl) - return - else: - raise MismatchedTags(*((self.filename, el.tagName, name) - +self.saveMark()+el._markpos)) - el.endTag(name) - if not self.elementstack: - self.documents.append(el) - if self.beExtremelyLenient and el.tagName == "script": - self._fixScriptElement(el) - - def connectionLost(self, reason): - XMLParser.connectionLost(self, reason) # This can cause more events! - if self.elementstack: - if self.beExtremelyLenient: - self.documents.append(self.elementstack[0]) - else: - raise MismatchedTags(*((self.filename, self.elementstack[-1], - "END_OF_FILE") - +self.saveMark() - +self.elementstack[-1]._markpos)) - - -def parse(readable, *args, **kwargs): - """Parse HTML or XML readable.""" - if not hasattr(readable, "read"): - readable = open(readable, "rb") - mdp = MicroDOMParser(*args, **kwargs) - mdp.filename = getattr(readable, "name", "<xmlfile />") - mdp.makeConnection(None) - if hasattr(readable,"getvalue"): - mdp.dataReceived(readable.getvalue()) - else: - r = readable.read(1024) - while r: - mdp.dataReceived(r) - r = readable.read(1024) - mdp.connectionLost(None) - - if not mdp.documents: - raise ParseError(mdp.filename, 0, 0, "No top-level Nodes in document") - - if mdp.beExtremelyLenient: - if len(mdp.documents) == 1: - d = mdp.documents[0] - if not isinstance(d, Element): - el = Element("html") - el.appendChild(d) - d = el - else: - d = Element("html") - for child in mdp.documents: - d.appendChild(child) - else: - d = mdp.documents[0] - doc = Document(d) - doc.doctype = mdp._mddoctype - return doc - -def parseString(st, *args, **kw): - if isinstance(st, UnicodeType): - # this isn't particularly ideal, but it does work. - return parse(StringIO(st.encode('UTF-16')), *args, **kw) - return parse(StringIO(st), *args, **kw) - - -def parseXML(readable): - """Parse an XML readable object.""" - return parse(readable, caseInsensitive=0, preserveCase=1) - - -def parseXMLString(st): - """Parse an XML readable object.""" - return parseString(st, caseInsensitive=0, preserveCase=1) - - -# Utility - -class lmx: - """Easy creation of XML.""" - - def __init__(self, node='div'): - if isinstance(node, StringTypes): - node = Element(node) - self.node = node - - def __getattr__(self, name): - if name[0] == '_': - raise AttributeError("no private attrs") - return lambda **kw: self.add(name,**kw) - - def __setitem__(self, key, val): - self.node.setAttribute(key, val) - - def __getitem__(self, key): - return self.node.getAttribute(key) - - def text(self, txt, raw=0): - nn = Text(txt, raw=raw) - self.node.appendChild(nn) - return self - - def add(self, tagName, **kw): - newNode = Element(tagName, caseInsensitive=0, preserveCase=0) - self.node.appendChild(newNode) - xf = lmx(newNode) - for k, v in kw.items(): - if k[0] == '_': - k = k[1:] - xf[k]=v - return xf diff --git a/tools/buildbot/pylibs/twisted/web/monitor.py b/tools/buildbot/pylibs/twisted/web/monitor.py deleted file mode 100644 index 052e94c..0000000 --- a/tools/buildbot/pylibs/twisted/web/monitor.py +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -from twisted.web import client -from twisted.internet import reactor -import md5 -from zope.interface import implements - -class IChangeNotified: - pass - -class BaseChangeNotified: - - implements(IChangeNotified) - - def reportChange(self, old, new): - pass - - def reportNoChange(self): - pass - -class ChangeChecker: - - working = 0 - call = None - - def __init__(self, notified, url, delay=60): - self.notified = notified - self.url = url - self.md5 = None - self.delay = delay - - def start(self): - self.working = 1 - self._getPage() - - def stop(self): - if self.call: - self.call.cancel() - self.call = None - self.working = 0 - - def _getPage(self): - d = client.getPage(self.url) - d.addErrback(self.noPage) - d.addCallback(self.page) - self.call = None - - def noPage(self, e): - self.gotMD5(None) - - def page(self, p): - if p is None: - return self.gotMD5(None) - m = md5.new() - m.update(p) - self.gotMD5(m.digest()) - - def gotMD5(self, md5): - if not self.working: - return - if md5 != self.md5: - self.notified.reportChange(self.md5, md5) - self.md5 = md5 - else: - self.notified.reportNoChange() - if not self.call: - self.call = reactor.callLater(self.delay, self._getPage) - - -class ProxyChangeChecker(ChangeChecker): - - def __init__(self, proxyHost, proxyPort, notified, url, delay=60): - self.proxyHost = proxyHost - self.proxyPort = proxyPort - ChangeChecker.__init__(self, notified, url, delay) - - def _getPage(self): - factory = client.HTTPClientFactory(self.proxyHost, self.url) - factory.headers = {'pragma': 'no-cache'} - reactor.connectTCP(self.proxyHost, self.proxyPort, factory) - d = factory.deferred - d.addErrback(self.noPage) - d.addCallback(self.page) diff --git a/tools/buildbot/pylibs/twisted/web/proxy.py b/tools/buildbot/pylibs/twisted/web/proxy.py deleted file mode 100644 index 98e5c41..0000000 --- a/tools/buildbot/pylibs/twisted/web/proxy.py +++ /dev/null @@ -1,283 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_proxy -*- -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Simplistic HTTP proxy support. - -This comes in two main variants - the Proxy and the ReverseProxy. - -When a Proxy is in use, a browser trying to connect to a server (say, -www.yahoo.com) will be intercepted by the Proxy, and the proxy will covertly -connect to the server, and return the result. - -When a ReverseProxy is in use, the client connects directly to the ReverseProxy -(say, www.yahoo.com) which farms off the request to one of a pool of servers, -and returns the result. - -Normally, a Proxy is used on the client end of an Internet connection, while a -ReverseProxy is used on the server end. -""" - -import urlparse -from urllib import quote as urlquote - -from twisted.internet import reactor -from twisted.internet.protocol import ClientFactory -from twisted.web.resource import Resource -from twisted.web.server import NOT_DONE_YET -from twisted.web.http import HTTPClient, Request, HTTPChannel - - - -class ProxyClient(HTTPClient): - """ - Used by ProxyClientFactory to implement a simple web proxy. - """ - - def __init__(self, command, rest, version, headers, data, father): - self.father = father - self.command = command - self.rest = rest - if "proxy-connection" in headers: - del headers["proxy-connection"] - headers["connection"] = "close" - self.headers = headers - self.data = data - - - def connectionMade(self): - self.sendCommand(self.command, self.rest) - for header, value in self.headers.items(): - self.sendHeader(header, value) - self.endHeaders() - self.transport.write(self.data) - - - def handleStatus(self, version, code, message): - if message: - # Add a whitespace to message, this allows empty messages - # transparently - message = " %s" % (message,) - self.father.transport.write("%s %s%s\r\n" % (version, code, message)) - - - def handleHeader(self, key, value): - self.father.transport.write("%s: %s\r\n" % (key, value)) - - - def handleEndHeaders(self): - self.father.transport.write("\r\n") - - - def handleResponsePart(self, buffer): - self.father.transport.write(buffer) - - - def handleResponseEnd(self): - self.transport.loseConnection() - self.father.channel.transport.loseConnection() - - - -class ProxyClientFactory(ClientFactory): - """ - Used by ProxyRequest to implement a simple web proxy. - """ - - protocol = ProxyClient - - - def __init__(self, command, rest, version, headers, data, father): - self.father = father - self.command = command - self.rest = rest - self.headers = headers - self.data = data - self.version = version - - - def buildProtocol(self, addr): - return self.protocol(self.command, self.rest, self.version, - self.headers, self.data, self.father) - - - def clientConnectionFailed(self, connector, reason): - self.father.transport.write("HTTP/1.0 501 Gateway error\r\n") - self.father.transport.write("Content-Type: text/html\r\n") - self.father.transport.write("\r\n") - self.father.transport.write('''<H1>Could not connect</H1>''') - self.father.transport.loseConnection() - - - -class ProxyRequest(Request): - """ - Used by Proxy to implement a simple web proxy. - - @ivar reactor: the reactor used to create connections. - @type reactor: object providing L{twisted.internet.interfaces.IReactorTCP} - """ - - protocols = {'http': ProxyClientFactory} - ports = {'http': 80} - - def __init__(self, channel, queued, reactor=reactor): - Request.__init__(self, channel, queued) - self.reactor = reactor - - - def process(self): - parsed = urlparse.urlparse(self.uri) - protocol = parsed[0] - host = parsed[1] - port = self.ports[protocol] - if ':' in host: - host, port = host.split(':') - port = int(port) - rest = urlparse.urlunparse(('', '') + parsed[2:]) - if not rest: - rest = rest + '/' - class_ = self.protocols[protocol] - headers = self.getAllHeaders().copy() - if 'host' not in headers: - headers['host'] = host - self.content.seek(0, 0) - s = self.content.read() - clientFactory = class_(self.method, rest, self.clientproto, headers, - s, self) - self.reactor.connectTCP(host, port, clientFactory) - - - -class Proxy(HTTPChannel): - """ - This class implements a simple web proxy. - - Since it inherits from L{twisted.protocols.http.HTTPChannel}, to use it you - should do something like this:: - - from twisted.web import http - f = http.HTTPFactory() - f.protocol = Proxy - - Make the HTTPFactory a listener on a port as per usual, and you have - a fully-functioning web proxy! - """ - - requestFactory = ProxyRequest - - - -class ReverseProxyRequest(Request): - """ - Used by ReverseProxy to implement a simple reverse proxy. - - @ivar proxyClientFactoryClass: a proxy client factory class, used to create - new connections. - @type proxyClientFactoryClass: L{ClientFactory} - - @ivar reactor: the reactor used to create connections. - @type reactor: object providing L{twisted.internet.interfaces.IReactorTCP} - """ - - proxyClientFactoryClass = ProxyClientFactory - - def __init__(self, channel, queued, reactor=reactor): - Request.__init__(self, channel, queued) - self.reactor = reactor - - - def process(self): - self.received_headers['host'] = self.factory.host - clientFactory = self.proxyClientFactoryClass( - self.method, self.uri, self.clientproto, self.getAllHeaders(), - self.content.read(), self) - self.reactor.connectTCP(self.factory.host, self.factory.port, - clientFactory) - - - -class ReverseProxy(HTTPChannel): - """ - Implements a simple reverse proxy. - - For details of usage, see the file examples/proxy.py. - """ - - requestFactory = ReverseProxyRequest - - - -class ReverseProxyResource(Resource): - """ - Resource that renders the results gotten from another server - - Put this resource in the tree to cause everything below it to be relayed - to a different server. - - @ivar proxyClientFactoryClass: a proxy client factory class, used to create - new connections. - @type proxyClientFactoryClass: L{ClientFactory} - - @ivar reactor: the reactor used to create connections. - @type reactor: object providing L{twisted.internet.interfaces.IReactorTCP} - """ - - proxyClientFactoryClass = ProxyClientFactory - - - def __init__(self, host, port, path, reactor=reactor): - """ - @param host: the host of the web server to proxy. - @type host: C{str} - - @param port: the port of the web server to proxy. - @type port: C{port} - - @param path: the base path to fetch data from. Note that you shouldn't - put any trailing slashes in it, it will be added automatically in - request. For example, if you put B{/foo}, a request on B{/bar} will - be proxied to B{/foo/bar}. Any required encoding of special - characters (such as " " or "/") should have been done already. - - @type path: C{str} - """ - Resource.__init__(self) - self.host = host - self.port = port - self.path = path - self.reactor = reactor - - - def getChild(self, path, request): - """ - Create and return a proxy resource with the same proxy configuration - as this one, except that its path also contains the segment given by - C{path} at the end. - """ - return ReverseProxyResource( - self.host, self.port, self.path + '/' + urlquote(path, safe="")) - - - def render(self, request): - """ - Render a request by forwarding it to the proxied server. - """ - # RFC 2616 tells us that we can omit the port if it's the default port, - # but we have to provide it otherwise - if self.port == 80: - request.received_headers['host'] = self.host - else: - request.received_headers['host'] = "%s:%d" % (self.host, self.port) - request.content.seek(0, 0) - qs = urlparse.urlparse(request.uri)[4] - if qs: - rest = self.path + '?' + qs - else: - rest = self.path - clientFactory = self.proxyClientFactoryClass( - request.method, rest, request.clientproto, - request.getAllHeaders(), request.content.read(), request) - self.reactor.connectTCP(self.host, self.port, clientFactory) - return NOT_DONE_YET diff --git a/tools/buildbot/pylibs/twisted/web/resource.py b/tools/buildbot/pylibs/twisted/web/resource.py deleted file mode 100644 index 0becb8d..0000000 --- a/tools/buildbot/pylibs/twisted/web/resource.py +++ /dev/null @@ -1,204 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_web -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""I hold the lowest-level Resource class.""" - - -# System Imports -from twisted.internet import defer -from twisted.python import roots, reflect -from zope.interface import Attribute, implements, Interface - -class IResource(Interface): - """A web resource.""" - - isLeaf = Attribute(\ -"""Signal if this IResource implementor is a "leaf node" or not. If True, -getChildWithDefault will not be called on this Resource.""") - - def getChildWithDefault(name, request): - """Return a child with the given name for the given request. - This is the external interface used by the Resource publishing - machinery. If implementing IResource without subclassing - Resource, it must be provided. However, if subclassing Resource, - getChild overridden instead. - """ - - def putChild(path, child): - """Put a child IResource implementor at the given path. - """ - - def render(request): - """Render a request. This is called on the leaf resource for - a request. Render must return either a string, which will - be sent to the browser as the HTML for the request, or - server.NOT_DONE_YET. If NOT_DONE_YET is returned, - at some point later (in a Deferred callback, usually) - call request.write("<html>") to write data to the request, - and request.finish() to send the data to the browser. - """ - - -def getChildForRequest(resource, request): - """Traverse resource tree to find who will handle the request.""" - while request.postpath and not resource.isLeaf: - pathElement = request.postpath.pop(0) - request.prepath.append(pathElement) - resource = resource.getChildWithDefault(pathElement, request) - return resource - - -class Resource: - """I define a web-accessible resource. - - I serve 2 main purposes; one is to provide a standard representation for - what HTTP specification calls an 'entity', and the other is to provide an - abstract directory structure for URL retrieval. - """ - - implements(IResource) - - entityType = IResource - - server = None - - def __init__(self): - """Initialize. - """ - self.children = {} - - isLeaf = 0 - - ### Abstract Collection Interface - - def listStaticNames(self): - return self.children.keys() - - def listStaticEntities(self): - return self.children.items() - - def listNames(self): - return self.listStaticNames() + self.listDynamicNames() - - def listEntities(self): - return self.listStaticEntities() + self.listDynamicEntities() - - def listDynamicNames(self): - return [] - - def listDynamicEntities(self, request=None): - return [] - - def getStaticEntity(self, name): - return self.children.get(name) - - def getDynamicEntity(self, name, request): - if not self.children.has_key(name): - return self.getChild(name, request) - else: - return None - - def delEntity(self, name): - del self.children[name] - - def reallyPutEntity(self, name, entity): - self.children[name] = entity - - # Concrete HTTP interface - - def getChild(self, path, request): - """Retrieve a 'child' resource from me. - - Implement this to create dynamic resource generation -- resources which - are always available may be registered with self.putChild(). - - This will not be called if the class-level variable 'isLeaf' is set in - your subclass; instead, the 'postpath' attribute of the request will be - left as a list of the remaining path elements. - - For example, the URL /foo/bar/baz will normally be:: - - | site.resource.getChild('foo').getChild('bar').getChild('baz'). - - However, if the resource returned by 'bar' has isLeaf set to true, then - the getChild call will never be made on it. - - @param path: a string, describing the child - - @param request: a twisted.web.server.Request specifying meta-information - about the request that is being made for this child. - """ - return error.NoResource("No such child resource.") - - def getChildWithDefault(self, path, request): - """Retrieve a static or dynamically generated child resource from me. - - First checks if a resource was added manually by putChild, and then - call getChild to check for dynamic resources. Only override if you want - to affect behaviour of all child lookups, rather than just dynamic - ones. - - This will check to see if I have a pre-registered child resource of the - given name, and call getChild if I do not. - """ - if self.children.has_key(path): - return self.children[path] - - return self.getChild(path, request) - - def getChildForRequest(self, request): - import warnings - warnings.warn("Please use module level getChildForRequest.", DeprecationWarning, 2) - return getChildForRequest(self, request) - - def putChild(self, path, child): - """Register a static child. - - You almost certainly don't want '/' in your path. If you - intended to have the root of a folder, e.g. /foo/, you want - path to be ''. - """ - self.children[path] = child - child.server = self.server - - def render(self, request): - """Render a given resource. See L{IResource}'s render method. - - I delegate to methods of self with the form 'render_METHOD' - where METHOD is the HTTP that was used to make the - request. Examples: render_GET, render_HEAD, render_POST, and - so on. Generally you should implement those methods instead of - overriding this one. - - render_METHOD methods are expected to return a string which - will be the rendered page, unless the return value is - twisted.web.server.NOT_DONE_YET, in which case it is this - class's responsibility to write the results to - request.write(data), then call request.finish(). - - Old code that overrides render() directly is likewise expected - to return a string or NOT_DONE_YET. - """ - m = getattr(self, 'render_' + request.method, None) - if not m: - from twisted.web.server import UnsupportedMethod - raise UnsupportedMethod(getattr(self, 'allowedMethods', ())) - return m(request) - - def render_HEAD(self, request): - """Default handling of HEAD method. - - I just return self.render_GET(request). When method is HEAD, - the framework will handle this correctly. - """ - return self.render_GET(request) - - -#t.w imports -#This is ugly, I know, but since error.py directly access resource.Resource -#during import-time (it subclasses it), the Resource class must be defined -#by the time error is imported. -import error diff --git a/tools/buildbot/pylibs/twisted/web/rewrite.py b/tools/buildbot/pylibs/twisted/web/rewrite.py deleted file mode 100644 index b41ca00..0000000 --- a/tools/buildbot/pylibs/twisted/web/rewrite.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# -from twisted.web import resource - -class RewriterResource(resource.Resource): - - def __init__(self, orig, *rewriteRules): - resource.Resource.__init__(self) - self.resource = orig - self.rewriteRules = list(rewriteRules) - - def _rewrite(self, request): - for rewriteRule in self.rewriteRules: - rewriteRule(request) - - def getChild(self, path, request): - request.postpath.insert(0, path) - request.prepath.pop() - self._rewrite(request) - path = request.postpath.pop(0) - request.prepath.append(path) - return self.resource.getChildWithDefault(path, request) - - def render(self, request): - self._rewrite(request) - return self.resource.render(request) - - -def tildeToUsers(request): - if request.postpath and request.postpath[0][:1]=='~': - request.postpath[:1] = ['users', request.postpath[0][1:]] - request.path = '/'+'/'.join(request.prepath+request.postpath) - -def alias(aliasPath, sourcePath): - """ - I am not a very good aliaser. But I'm the best I can be. If I'm - aliasing to a Resource that generates links, and it uses any parts - of request.prepath to do so, the links will not be relative to the - aliased path, but rather to the aliased-to path. That I can't - alias static.File directory listings that nicely. However, I can - still be useful, as many resources will play nice. - """ - sourcePath = sourcePath.split('/') - aliasPath = aliasPath.split('/') - def rewriter(request): - if request.postpath[:len(aliasPath)] == aliasPath: - after = request.postpath[len(aliasPath):] - request.postpath = sourcePath + after - request.path = '/'+'/'.join(request.prepath+request.postpath) - return rewriter diff --git a/tools/buildbot/pylibs/twisted/web/script.py b/tools/buildbot/pylibs/twisted/web/script.py deleted file mode 100644 index d1fae3f..0000000 --- a/tools/buildbot/pylibs/twisted/web/script.py +++ /dev/null @@ -1,163 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""I contain PythonScript, which is a very simple python script resource. -""" - -import server -import resource -import html -import error - -try: - import cStringIO as StringIO -except ImportError: - import StringIO - -from twisted.web import http -from twisted import copyright -import traceback -import os -from twisted.web import resource -from twisted.web import static - -rpyNoResource = """<p>You forgot to assign to the variable "resource" in your script. For example:</p> -<pre> -# MyCoolWebApp.rpy - -import mygreatresource - -resource = mygreatresource.MyGreatResource() -</pre> -""" - -class AlreadyCached(Exception): - """This exception is raised when a path has already been cached. - """ - -class CacheScanner: - def __init__(self, path, registry): - self.path = path - self.registry = registry - self.doCache = 0 - - def cache(self): - c = self.registry.getCachedPath(self.path) - if c is not None: - raise AlreadyCached(c) - self.recache() - - def recache(self): - self.doCache = 1 - -noRsrc = error.ErrorPage(500, "Whoops! Internal Error", rpyNoResource) - -def ResourceScript(path, registry): - """ - I am a normal py file which must define a 'resource' global, which should - be an instance of (a subclass of) web.resource.Resource; it will be - renderred. - """ - cs = CacheScanner(path, registry) - glob = {'__file__': path, - 'resource': noRsrc, - 'registry': registry, - 'cache': cs.cache, - 'recache': cs.recache} - try: - execfile(path, glob, glob) - except AlreadyCached, ac: - return ac.args[0] - rsrc = glob['resource'] - if cs.doCache and rsrc is not noRsrc: - registry.cachePath(path, rsrc) - return rsrc - -def ResourceTemplate(path, registry): - from quixote import ptl_compile - - glob = {'__file__': path, - 'resource': error.ErrorPage(500, "Whoops! Internal Error", - rpyNoResource), - 'registry': registry} - - e = ptl_compile.compile_template(open(path), path) - exec e in glob - return glob['resource'] - - -class ResourceScriptWrapper(resource.Resource): - - def __init__(self, path, registry=None): - resource.Resource.__init__(self) - self.path = path - self.registry = registry or static.Registry() - - def render(self, request): - res = ResourceScript(self.path, self.registry) - return res.render(request) - - def getChildWithDefault(self, path, request): - res = ResourceScript(self.path, self.registry) - return res.getChildWithDefault(path, request) - - - -class ResourceScriptDirectory(resource.Resource): - def __init__(self, pathname, registry=None): - resource.Resource.__init__(self) - self.path = pathname - self.registry = registry or static.Registry() - - def getChild(self, path, request): - fn = os.path.join(self.path, path) - - if os.path.isdir(fn): - return ResourceScriptDirectory(fn, self.registry) - if os.path.exists(fn): - return ResourceScript(fn, self.registry) - return error.NoResource() - - def render(self, request): - return error.NoResource().render(request) - - -class PythonScript(resource.Resource): - """I am an extremely simple dynamic resource; an embedded python script. - - This will execute a file (usually of the extension '.epy') as Python code, - internal to the webserver. - """ - isLeaf = 1 - def __init__(self, filename, registry): - """Initialize me with a script name. - """ - self.filename = filename - self.registry = registry - - def render(self, request): - """Render me to a web client. - - Load my file, execute it in a special namespace (with 'request' and - '__file__' global vars) and finish the request. Output to the web-page - will NOT be handled with print - standard output goes to the log - but - with request.write. - """ - request.setHeader("x-powered-by","Twisted/%s" % copyright.version) - namespace = {'request': request, - '__file__': self.filename, - 'registry': self.registry} - try: - execfile(self.filename, namespace, namespace) - except IOError, e: - if e.errno == 2: #file not found - request.setResponseCode(http.NOT_FOUND) - request.write(error.NoResource("File not found.").render(request)) - except: - io = StringIO.StringIO() - traceback.print_exc(file=io) - request.write(html.PRE(io.getvalue())) - request.finish() - return server.NOT_DONE_YET diff --git a/tools/buildbot/pylibs/twisted/web/server.py b/tools/buildbot/pylibs/twisted/web/server.py deleted file mode 100644 index 9ee9579..0000000 --- a/tools/buildbot/pylibs/twisted/web/server.py +++ /dev/null @@ -1,571 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_web -*- - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""This is a web-server which integrates with the twisted.internet -infrastructure. -""" - -# System Imports - -import string -import types -import operator -import copy -import time -import os -from urllib import quote -try: - from twisted.protocols._c_urlarg import unquote -except ImportError: - from urllib import unquote - -#some useful constants -NOT_DONE_YET = 1 - -# Twisted Imports -from twisted.spread import pb -from twisted.internet import defer, address, task -from twisted.web import http -from twisted.python import log, reflect, failure, components -from twisted import copyright - -# Sibling Imports -import error, resource -from twisted.web import util as webutil - - -# backwards compatability -date_time_string = http.datetimeToString -string_date_time = http.stringToDatetime - -# Support for other methods may be implemented on a per-resource basis. -supportedMethods = ('GET', 'HEAD', 'POST') - - -class UnsupportedMethod(Exception): - """Raised by a resource when faced with a strange request method. - - RFC 2616 (HTTP 1.1) gives us two choices when faced with this situtation: - If the type of request is known to us, but not allowed for the requested - resource, respond with NOT_ALLOWED. Otherwise, if the request is something - we don't know how to deal with in any case, respond with NOT_IMPLEMENTED. - - When this exception is raised by a Resource's render method, the server - will make the appropriate response. - - This exception's first argument MUST be a sequence of the methods the - resource *does* support. - """ - - allowedMethods = () - - def __init__(self, allowedMethods, *args): - Exception.__init__(self, allowedMethods, *args) - self.allowedMethods = allowedMethods - - if not operator.isSequenceType(allowedMethods): - why = "but my first argument is not a sequence." - s = ("First argument must be a sequence of" - " supported methods, %s" % (why,)) - raise TypeError, s - -def _addressToTuple(addr): - if isinstance(addr, address.IPv4Address): - return ('INET', addr.host, addr.port) - elif isinstance(addr, address.UNIXAddress): - return ('UNIX', addr.name) - else: - return tuple(addr) - -class Request(pb.Copyable, http.Request, components.Componentized): - - site = None - appRootURL = None - __pychecker__ = 'unusednames=issuer' - - def __init__(self, *args, **kw): - http.Request.__init__(self, *args, **kw) - components.Componentized.__init__(self) - self.notifications = [] - - def getStateToCopyFor(self, issuer): - x = self.__dict__.copy() - del x['transport'] - # XXX refactor this attribute out; it's from protocol - # del x['server'] - del x['channel'] - del x['content'] - del x['site'] - self.content.seek(0, 0) - x['content_data'] = self.content.read() - x['remote'] = pb.ViewPoint(issuer, self) - - # Address objects aren't jellyable - x['host'] = _addressToTuple(x['host']) - x['client'] = _addressToTuple(x['client']) - - return x - - # HTML generation helpers - - def sibLink(self, name): - "Return the text that links to a sibling of the requested resource." - if self.postpath: - return (len(self.postpath)*"../") + name - else: - return name - - def childLink(self, name): - "Return the text that links to a child of the requested resource." - lpp = len(self.postpath) - if lpp > 1: - return ((lpp-1)*"../") + name - elif lpp == 1: - return name - else: # lpp == 0 - if len(self.prepath) and self.prepath[-1]: - return self.prepath[-1] + '/' + name - else: - return name - - def process(self): - "Process a request." - - # get site from channel - self.site = self.channel.site - - # set various default headers - self.setHeader('server', version) - self.setHeader('date', http.datetimeToString()) - self.setHeader('content-type', "text/html") - - # Resource Identification - self.prepath = [] - self.postpath = map(unquote, string.split(self.path[1:], '/')) - try: - resrc = self.site.getResourceFor(self) - self.render(resrc) - except: - self.processingFailed(failure.Failure()) - - - def render(self, resrc): - try: - body = resrc.render(self) - except UnsupportedMethod, e: - allowedMethods = e.allowedMethods - if (self.method == "HEAD") and ("GET" in allowedMethods): - # We must support HEAD (RFC 2616, 5.1.1). If the - # resource doesn't, fake it by giving the resource - # a 'GET' request and then return only the headers, - # not the body. - log.msg("Using GET to fake a HEAD request for %s" % - (resrc,)) - self.method = "GET" - body = resrc.render(self) - - if body is NOT_DONE_YET: - log.msg("Tried to fake a HEAD request for %s, but " - "it got away from me." % resrc) - # Oh well, I guess we won't include the content length. - else: - self.setHeader('content-length', str(len(body))) - - self.write('') - self.finish() - return - - if self.method in (supportedMethods): - # We MUST include an Allow header - # (RFC 2616, 10.4.6 and 14.7) - self.setHeader('Allow', allowedMethods) - s = ('''Your browser approached me (at %(URI)s) with''' - ''' the method "%(method)s". I only allow''' - ''' the method%(plural)s %(allowed)s here.''' % { - 'URI': self.uri, - 'method': self.method, - 'plural': ((len(allowedMethods) > 1) and 's') or '', - 'allowed': string.join(allowedMethods, ', ') - }) - epage = error.ErrorPage(http.NOT_ALLOWED, - "Method Not Allowed", s) - body = epage.render(self) - else: - epage = error.ErrorPage(http.NOT_IMPLEMENTED, "Huh?", - """I don't know how to treat a""" - """ %s request.""" - % (self.method)) - body = epage.render(self) - # end except UnsupportedMethod - - if body == NOT_DONE_YET: - return - if type(body) is not types.StringType: - body = error.ErrorPage(http.INTERNAL_SERVER_ERROR, - "Request did not return a string", - "Request: "+html.PRE(reflect.safe_repr(self))+"<br />"+ - "Resource: "+html.PRE(reflect.safe_repr(resrc))+"<br />"+ - "Value: "+html.PRE(reflect.safe_repr(body))).render(self) - - if self.method == "HEAD": - if len(body) > 0: - # This is a Bad Thing (RFC 2616, 9.4) - log.msg("Warning: HEAD request %s for resource %s is" - " returning a message body." - " I think I'll eat it." - % (self, resrc)) - self.setHeader('content-length', str(len(body))) - self.write('') - else: - self.setHeader('content-length', str(len(body))) - self.write(body) - self.finish() - - def processingFailed(self, reason): - log.err(reason) - if self.site.displayTracebacks: - body = ("<html><head><title>web.Server Traceback (most recent call last)</title></head>" - "<body><b>web.Server Traceback (most recent call last):</b>\n\n" - "%s\n\n</body></html>\n" - % webutil.formatFailure(reason)) - else: - body = ("<html><head><title>Processing Failed</title></head><body>" - "<b>Processing Failed</b></body></html>") - - self.setResponseCode(http.INTERNAL_SERVER_ERROR) - self.setHeader('content-type',"text/html") - self.setHeader('content-length', str(len(body))) - self.write(body) - self.finish() - return reason - - def notifyFinish(self): - """Notify when finishing the request - - @return: A deferred. The deferred will be triggered when the - request is finished -- with a C{None} value if the request - finishes successfully or with an error if the request is stopped - by the client. - """ - self.notifications.append(defer.Deferred()) - return self.notifications[-1] - - def connectionLost(self, reason): - for d in self.notifications: - d.errback(reason) - self.notifications = [] - - def finish(self): - http.Request.finish(self) - for d in self.notifications: - d.callback(None) - self.notifications = [] - - def view_write(self, issuer, data): - """Remote version of write; same interface. - """ - self.write(data) - - def view_finish(self, issuer): - """Remote version of finish; same interface. - """ - self.finish() - - def view_addCookie(self, issuer, k, v, **kwargs): - """Remote version of addCookie; same interface. - """ - self.addCookie(k, v, **kwargs) - - def view_setHeader(self, issuer, k, v): - """Remote version of setHeader; same interface. - """ - self.setHeader(k, v) - - def view_setLastModified(self, issuer, when): - """Remote version of setLastModified; same interface. - """ - self.setLastModified(when) - - def view_setETag(self, issuer, tag): - """Remote version of setETag; same interface. - """ - self.setETag(tag) - - def view_setResponseCode(self, issuer, code): - """Remote version of setResponseCode; same interface. - """ - self.setResponseCode(code) - - def view_registerProducer(self, issuer, producer, streaming): - """Remote version of registerProducer; same interface. - (requires a remote producer.) - """ - self.registerProducer(_RemoteProducerWrapper(producer), streaming) - - def view_unregisterProducer(self, issuer): - self.unregisterProducer() - - ### these calls remain local - - session = None - - def getSession(self, sessionInterface = None): - # Session management - if not self.session: - cookiename = string.join(['TWISTED_SESSION'] + self.sitepath, "_") - sessionCookie = self.getCookie(cookiename) - if sessionCookie: - try: - self.session = self.site.getSession(sessionCookie) - except KeyError: - pass - # if it still hasn't been set, fix it up. - if not self.session: - self.session = self.site.makeSession() - self.addCookie(cookiename, self.session.uid, path='/') - self.session.touch() - if sessionInterface: - return self.session.getComponent(sessionInterface) - return self.session - - def _prePathURL(self, prepath): - port = self.getHost().port - if self.isSecure(): - default = 443 - else: - default = 80 - if port == default: - hostport = '' - else: - hostport = ':%d' % port - return 'http%s://%s%s/%s' % ( - self.isSecure() and 's' or '', - self.getRequestHostname(), - hostport, - '/'.join([quote(segment, safe='') for segment in prepath])) - - def prePathURL(self): - return self._prePathURL(self.prepath) - - def URLPath(self): - from twisted.python import urlpath - return urlpath.URLPath.fromRequest(self) - - def rememberRootURL(self): - """ - Remember the currently-processed part of the URL for later - recalling. - """ - url = self._prePathURL(self.prepath[:-1]) - self.appRootURL = url - - def getRootURL(self): - """ - Get a previously-remembered URL. - """ - return self.appRootURL - - -class _RemoteProducerWrapper: - def __init__(self, remote): - self.resumeProducing = remote.remoteMethod("resumeProducing") - self.pauseProducing = remote.remoteMethod("pauseProducing") - self.stopProducing = remote.remoteMethod("stopProducing") - - -class Session(components.Componentized): - """ - A user's session with a system. - - This utility class contains no functionality, but is used to - represent a session. - - @ivar sessionTimeout: timeout of a session, in seconds. - @ivar loopFactory: factory for creating L{task.LoopingCall}. Mainly for - testing. - """ - sessionTimeout = 900 - loopFactory = task.LoopingCall - - def __init__(self, site, uid): - """ - Initialize a session with a unique ID for that session. - """ - components.Componentized.__init__(self) - self.site = site - self.uid = uid - self.expireCallbacks = [] - self.checkExpiredLoop = None - self.touch() - self.sessionNamespaces = {} - - - def startCheckingExpiration(self, lifetime): - """ - Start expiration tracking. - - @type lifetime: C{int} or C{float} - @param lifetime: The number of seconds this session is allowed to be - idle before it expires. - - @return: C{None} - """ - self.checkExpiredLoop = self.loopFactory(self.checkExpired) - self.checkExpiredLoop.start(lifetime, now=False) - - - def notifyOnExpire(self, callback): - """ - Call this callback when the session expires or logs out. - """ - self.expireCallbacks.append(callback) - - - def expire(self): - """ - Expire/logout of the session. - """ - del self.site.sessions[self.uid] - for c in self.expireCallbacks: - c() - self.expireCallbacks = [] - if self.checkExpiredLoop is not None: - self.checkExpiredLoop.stop() - # Break reference cycle. - self.checkExpiredLoop = None - - - def _getTime(self): - """ - Return current time used for session validity. - """ - return time.time() - - - def touch(self): - """ - Notify session modification. - """ - self.lastModified = self._getTime() - - - def checkExpired(self): - """ - Is it time for me to expire? - - If I haven't been touched in fifteen minutes, I will call my - expire method. - """ - # If I haven't been touched in 15 minutes: - if self._getTime() - self.lastModified > self.sessionTimeout: - if self.uid in self.site.sessions: - self.expire() - - -version = "TwistedWeb/%s" % copyright.version - - -class Site(http.HTTPFactory): - """ - A web site: manage log, sessions, and resources. - - @ivar counter: increment value used for generating unique sessions ID. - @ivar requestFactory: factory creating requests objects. Default to - L{Request}. - @ivar displayTracebacks: if set, Twisted internal errors are displayed on - rendered pages. Default to C{True}. - @ivar sessionFactory: factory for sessions objects. Default to L{Session}. - @ivar sessionCheckTime: interval between each check of session expiration. - """ - counter = 0 - requestFactory = Request - displayTracebacks = True - sessionFactory = Session - sessionCheckTime = 1800 - - def __init__(self, resource, logPath=None, timeout=60*60*12): - """ - Initialize. - """ - http.HTTPFactory.__init__(self, logPath=logPath, timeout=timeout) - self.sessions = {} - self.resource = resource - - def _openLogFile(self, path): - from twisted.python import logfile - return logfile.LogFile(os.path.basename(path), os.path.dirname(path)) - - def __getstate__(self): - d = self.__dict__.copy() - d['sessions'] = {} - return d - - def _mkuid(self): - """ - (internal) Generate an opaque, unique ID for a user's session. - """ - import md5, random - self.counter = self.counter + 1 - return md5.new("%s_%s" % (str(random.random()) , str(self.counter))).hexdigest() - - def makeSession(self): - """ - Generate a new Session instance, and store it for future reference. - """ - uid = self._mkuid() - session = self.sessions[uid] = self.sessionFactory(self, uid) - session.startCheckingExpiration(self.sessionCheckTime) - return session - - def getSession(self, uid): - """ - Get a previously generated session, by its unique ID. - This raises a KeyError if the session is not found. - """ - return self.sessions[uid] - - def buildProtocol(self, addr): - """ - Generate a channel attached to this site. - """ - channel = http.HTTPFactory.buildProtocol(self, addr) - channel.requestFactory = self.requestFactory - channel.site = self - return channel - - isLeaf = 0 - - def render(self, request): - """ - Redirect because a Site is always a directory. - """ - request.redirect(request.prePathURL() + '/') - request.finish() - - def getChildWithDefault(self, pathEl, request): - """ - Emulate a resource's getChild method. - """ - request.site = self - return self.resource.getChildWithDefault(pathEl, request) - - def getResourceFor(self, request): - """ - Get a resource for a request. - - This iterates through the resource heirarchy, calling - getChildWithDefault on each resource it finds for a path element, - stopping when it hits an element where isLeaf is true. - """ - request.site = self - # Sitepath is used to determine cookie names between distributed - # servers and disconnected sites. - request.sitepath = copy.copy(request.prepath) - return resource.getChildForRequest(self.resource, request) - - -import html - diff --git a/tools/buildbot/pylibs/twisted/web/soap.py b/tools/buildbot/pylibs/twisted/web/soap.py deleted file mode 100644 index 00b0473..0000000 --- a/tools/buildbot/pylibs/twisted/web/soap.py +++ /dev/null @@ -1,154 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_soap -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -SOAP support for twisted.web. - -Requires SOAPpy 0.10.1 or later. - -Maintainer: U{Itamar Shtull-Trauring<mailto:twisted@itamarst.org>} - -Future plans: -SOAPContext support of some kind. -Pluggable method lookup policies. -""" - -# SOAPpy -import SOAPpy - -# twisted imports -from twisted.web import server, resource, client -from twisted.internet import defer - - -class SOAPPublisher(resource.Resource): - """Publish SOAP methods. - - By default, publish methods beginning with 'soap_'. If the method - has an attribute 'useKeywords', it well get the arguments passed - as keyword args. - """ - - isLeaf = 1 - - # override to change the encoding used for responses - encoding = "UTF-8" - - def lookupFunction(self, functionName): - """Lookup published SOAP function. - - Override in subclasses. Default behaviour - publish methods - starting with soap_. - - @return: callable or None if not found. - """ - return getattr(self, "soap_%s" % functionName, None) - - def render(self, request): - """Handle a SOAP command.""" - data = request.content.read() - - p, header, body, attrs = SOAPpy.parseSOAPRPC(data, 1, 1, 1) - - methodName, args, kwargs, ns = p._name, p._aslist, p._asdict, p._ns - - # deal with changes in SOAPpy 0.11 - if callable(args): - args = args() - if callable(kwargs): - kwargs = kwargs() - - function = self.lookupFunction(methodName) - - if not function: - self._methodNotFound(request, methodName) - return server.NOT_DONE_YET - else: - if hasattr(function, "useKeywords"): - keywords = {} - for k, v in kwargs.items(): - keywords[str(k)] = v - d = defer.maybeDeferred(function, **keywords) - else: - d = defer.maybeDeferred(function, *args) - - d.addCallback(self._gotResult, request, methodName) - d.addErrback(self._gotError, request, methodName) - return server.NOT_DONE_YET - - def _methodNotFound(self, request, methodName): - response = SOAPpy.buildSOAP(SOAPpy.faultType("%s:Client" % - SOAPpy.NS.ENV_T, "Method %s not found" % methodName), - encoding=self.encoding) - self._sendResponse(request, response, status=500) - - def _gotResult(self, result, request, methodName): - if not isinstance(result, SOAPpy.voidType): - result = {"Result": result} - response = SOAPpy.buildSOAP(kw={'%sResponse' % methodName: result}, - encoding=self.encoding) - self._sendResponse(request, response) - - def _gotError(self, failure, request, methodName): - e = failure.value - if isinstance(e, SOAPpy.faultType): - fault = e - else: - fault = SOAPpy.faultType("%s:Server" % SOAPpy.NS.ENV_T, - "Method %s failed." % methodName) - response = SOAPpy.buildSOAP(fault, encoding=self.encoding) - self._sendResponse(request, response, status=500) - - def _sendResponse(self, request, response, status=200): - request.setResponseCode(status) - - if self.encoding is not None: - mimeType = 'text/xml; charset="%s"' % self.encoding - else: - mimeType = "text/xml" - request.setHeader("Content-type", mimeType) - request.setHeader("Content-length", str(len(response))) - request.write(response) - request.finish() - - -class Proxy: - """A Proxy for making remote SOAP calls. - - Pass the URL of the remote SOAP server to the constructor. - - Use proxy.callRemote('foobar', 1, 2) to call remote method - 'foobar' with args 1 and 2, proxy.callRemote('foobar', x=1) - will call foobar with named argument 'x'. - """ - - # at some point this should have encoding etc. kwargs - def __init__(self, url, namespace=None, header=None): - self.url = url - self.namespace = namespace - self.header = header - - def _cbGotResult(self, result): - result = SOAPpy.parseSOAPRPC(result) - if hasattr(result, 'Result'): - return result.Result - elif len(result) == 1: - ## SOAPpy 0.11.6 wraps the return results in a containing structure. - ## This check added to make Proxy behaviour emulate SOAPProxy, which - ## flattens the structure by default. - ## This behaviour is OK because even singleton lists are wrapped in - ## another singleton structType, which is almost always useless. - return result[0] - else: - return result - - def callRemote(self, method, *args, **kwargs): - payload = SOAPpy.buildSOAP(args=args, kw=kwargs, method=method, - header=self.header, namespace=self.namespace) - return client.getPage(self.url, postdata=payload, method="POST", - headers={'content-type': 'text/xml', - 'SOAPAction': method} - ).addCallback(self._cbGotResult) - diff --git a/tools/buildbot/pylibs/twisted/web/static.py b/tools/buildbot/pylibs/twisted/web/static.py deleted file mode 100644 index 9d5dd56..0000000 --- a/tools/buildbot/pylibs/twisted/web/static.py +++ /dev/null @@ -1,466 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_web -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""I deal with static resources. -""" - -from __future__ import nested_scopes - -# System Imports -import os, stat, string -import cStringIO -import traceback -import warnings -import types -StringIO = cStringIO -del cStringIO -import urllib - -# Sibling Imports -from twisted.web import server -from twisted.web import error -from twisted.web import resource -from twisted.web.util import redirectTo - -# Twisted Imports -from twisted.web import http -from twisted.python import threadable, log, components, failure, filepath -from twisted.internet import abstract, interfaces, defer -from twisted.spread import pb -from twisted.persisted import styles -from twisted.python.util import InsensitiveDict -from twisted.python.runtime import platformType - - -dangerousPathError = error.NoResource("Invalid request URL.") - -def isDangerous(path): - return path == '..' or '/' in path or os.sep in path - - -class Data(resource.Resource): - """ - This is a static, in-memory resource. - """ - - def __init__(self, data, type): - resource.Resource.__init__(self) - self.data = data - self.type = type - - def render(self, request): - request.setHeader("content-type", self.type) - request.setHeader("content-length", str(len(self.data))) - if request.method == "HEAD": - return '' - return self.data - -def addSlash(request): - qs = '' - qindex = string.find(request.uri, '?') - if qindex != -1: - qs = request.uri[qindex:] - - return "http%s://%s%s/%s" % ( - request.isSecure() and 's' or '', - request.getHeader("host"), - (string.split(request.uri,'?')[0]), - qs) - -class Redirect(resource.Resource): - def __init__(self, request): - resource.Resource.__init__(self) - self.url = addSlash(request) - - def render(self, request): - return redirectTo(self.url, request) - - -class Registry(components.Componentized, styles.Versioned): - """ - I am a Componentized object that will be made available to internal Twisted - file-based dynamic web content such as .rpy and .epy scripts. - """ - - def __init__(self): - components.Componentized.__init__(self) - self._pathCache = {} - - persistenceVersion = 1 - - def upgradeToVersion1(self): - self._pathCache = {} - - def cachePath(self, path, rsrc): - self._pathCache[path] = rsrc - - def getCachedPath(self, path): - return self._pathCache.get(path) - - -def loadMimeTypes(mimetype_locations=['/etc/mime.types']): - """ - Multiple file locations containing mime-types can be passed as a list. - The files will be sourced in that order, overriding mime-types from the - files sourced beforehand, but only if a new entry explicitly overrides - the current entry. - """ - import mimetypes - # Grab Python's built-in mimetypes dictionary. - contentTypes = mimetypes.types_map - # Update Python's semi-erroneous dictionary with a few of the - # usual suspects. - contentTypes.update( - { - '.conf': 'text/plain', - '.diff': 'text/plain', - '.exe': 'application/x-executable', - '.flac': 'audio/x-flac', - '.java': 'text/plain', - '.ogg': 'application/ogg', - '.oz': 'text/x-oz', - '.swf': 'application/x-shockwave-flash', - '.tgz': 'application/x-gtar', - '.wml': 'text/vnd.wap.wml', - '.xul': 'application/vnd.mozilla.xul+xml', - '.py': 'text/plain', - '.patch': 'text/plain', - } - ) - # Users can override these mime-types by loading them out configuration - # files (this defaults to ['/etc/mime.types']). - for location in mimetype_locations: - if os.path.exists(location): - more = mimetypes.read_mime_types(location) - if more is not None: - contentTypes.update(more) - - return contentTypes - -def getTypeAndEncoding(filename, types, encodings, defaultType): - p, ext = os.path.splitext(filename) - ext = ext.lower() - if encodings.has_key(ext): - enc = encodings[ext] - ext = os.path.splitext(p)[1].lower() - else: - enc = None - type = types.get(ext, defaultType) - return type, enc - -class File(resource.Resource, styles.Versioned, filepath.FilePath): - """ - File is a resource that represents a plain non-interpreted file - (although it can look for an extension like .rpy or .cgi and hand the - file to a processor for interpretation if you wish). Its constructor - takes a file path. - - Alternatively, you can give a directory path to the constructor. In this - case the resource will represent that directory, and its children will - be files underneath that directory. This provides access to an entire - filesystem tree with a single Resource. - - If you map the URL 'http://server/FILE' to a resource created as - File('/tmp'), then http://server/FILE/ will return an HTML-formatted - listing of the /tmp/ directory, and http://server/FILE/foo/bar.html will - return the contents of /tmp/foo/bar.html . - - @cvar childNotFound: L{Resource} used to render 404 Not Found error pages. - """ - - contentTypes = loadMimeTypes() - - contentEncodings = { - ".gz" : "gzip", - ".bz2": "bzip2" - } - - processors = {} - - indexNames = ["index", "index.html", "index.htm", "index.trp", "index.rpy"] - - type = None - - ### Versioning - - persistenceVersion = 6 - - def upgradeToVersion6(self): - self.ignoredExts = [] - if self.allowExt: - self.ignoreExt("*") - del self.allowExt - - def upgradeToVersion5(self): - if not isinstance(self.registry, Registry): - self.registry = Registry() - - def upgradeToVersion4(self): - if not hasattr(self, 'registry'): - self.registry = {} - - def upgradeToVersion3(self): - if not hasattr(self, 'allowExt'): - self.allowExt = 0 - - def upgradeToVersion2(self): - self.defaultType = "text/html" - - def upgradeToVersion1(self): - if hasattr(self, 'indexName'): - self.indexNames = [self.indexName] - del self.indexName - - def __init__(self, path, defaultType="text/html", ignoredExts=(), registry=None, allowExt=0): - """Create a file with the given path. - """ - resource.Resource.__init__(self) - filepath.FilePath.__init__(self, path) - # Remove the dots from the path to split - self.defaultType = defaultType - if ignoredExts in (0, 1) or allowExt: - warnings.warn("ignoredExts should receive a list, not a boolean") - if ignoredExts or allowExt: - self.ignoredExts = ['*'] - else: - self.ignoredExts = [] - else: - self.ignoredExts = list(ignoredExts) - self.registry = registry or Registry() - - def ignoreExt(self, ext): - """Ignore the given extension. - - Serve file.ext if file is requested - """ - self.ignoredExts.append(ext) - - childNotFound = error.NoResource("File not found.") - - def directoryListing(self): - from twisted.web.woven import dirlist - return dirlist.DirectoryLister(self.path, - self.listNames(), - self.contentTypes, - self.contentEncodings, - self.defaultType) - - def getChild(self, path, request): - """See twisted.web.Resource.getChild. - """ - self.restat() - - if not self.isdir(): - return self.childNotFound - - if path: - fpath = self.child(path) - else: - fpath = self.childSearchPreauth(*self.indexNames) - if fpath is None: - return self.directoryListing() - - if not fpath.exists(): - fpath = fpath.siblingExtensionSearch(*self.ignoredExts) - if fpath is None: - return self.childNotFound - - if platformType == "win32": - # don't want .RPY to be different than .rpy, since that would allow - # source disclosure. - processor = InsensitiveDict(self.processors).get(fpath.splitext()[1]) - else: - processor = self.processors.get(fpath.splitext()[1]) - if processor: - return resource.IResource(processor(fpath.path, self.registry)) - return self.createSimilarFile(fpath.path) - - # methods to allow subclasses to e.g. decrypt files on the fly: - def openForReading(self): - """Open a file and return it.""" - return self.open() - - def getFileSize(self): - """Return file size.""" - return self.getsize() - - - def render(self, request): - """You know what you doing.""" - self.restat() - - if self.type is None: - self.type, self.encoding = getTypeAndEncoding(self.basename(), - self.contentTypes, - self.contentEncodings, - self.defaultType) - - if not self.exists(): - return self.childNotFound.render(request) - - if self.isdir(): - return self.redirect(request) - - #for content-length - fsize = size = self.getFileSize() - -# request.setHeader('accept-ranges','bytes') - - if self.type: - request.setHeader('content-type', self.type) - if self.encoding: - request.setHeader('content-encoding', self.encoding) - - try: - f = self.openForReading() - except IOError, e: - import errno - if e[0] == errno.EACCES: - return error.ForbiddenResource().render(request) - else: - raise - - if request.setLastModified(self.getmtime()) is http.CACHED: - return '' - -# Commented out because it's totally broken. --jknight 11/29/04 -# try: -# range = request.getHeader('range') -# -# if range is not None: -# # This is a request for partial data... -# bytesrange = string.split(range, '=') -# assert bytesrange[0] == 'bytes',\ -# "Syntactically invalid http range header!" -# start, end = string.split(bytesrange[1],'-') -# if start: -# f.seek(int(start)) -# if end: -# end = int(end) -# size = end -# else: -# end = size -# request.setResponseCode(http.PARTIAL_CONTENT) -# request.setHeader('content-range',"bytes %s-%s/%s " % ( -# str(start), str(end), str(size))) -# #content-length should be the actual size of the stuff we're -# #sending, not the full size of the on-server entity. -# fsize = end - int(start) -# -# request.setHeader('content-length', str(fsize)) -# except: -# traceback.print_exc(file=log.logfile) - - request.setHeader('content-length', str(fsize)) - if request.method == 'HEAD': - return '' - - # return data - FileTransfer(f, size, request) - # and make sure the connection doesn't get closed - return server.NOT_DONE_YET - - def redirect(self, request): - return redirectTo(addSlash(request), request) - - def listNames(self): - if not self.isdir(): - return [] - directory = self.listdir() - directory.sort() - return directory - - def listEntities(self): - return map(lambda fileName, self=self: self.createSimilarFile(os.path.join(self.path, fileName)), self.listNames()) - - def createPickleChild(self, name, child): - if not os.path.isdir(self.path): - resource.Resource.putChild(self, name, child) - # xxx use a file-extension-to-save-function dictionary instead - if type(child) == type(""): - fl = open(os.path.join(self.path, name), 'wb') - fl.write(child) - else: - if '.' not in name: - name = name + '.trp' - fl = open(os.path.join(self.path, name), 'wb') - from pickle import Pickler - pk = Pickler(fl) - pk.dump(child) - fl.close() - - def createSimilarFile(self, path): - f = self.__class__(path, self.defaultType, self.ignoredExts, self.registry) - # refactoring by steps, here - constructor should almost certainly take these - f.processors = self.processors - f.indexNames = self.indexNames[:] - f.childNotFound = self.childNotFound - return f - -class FileTransfer(pb.Viewable): - """ - A class to represent the transfer of a file over the network. - """ - request = None - - def __init__(self, file, size, request): - self.file = file - self.size = size - self.request = request - self.written = self.file.tell() - request.registerProducer(self, 0) - - def resumeProducing(self): - if not self.request: - return - data = self.file.read(min(abstract.FileDescriptor.bufferSize, self.size - self.written)) - if data: - self.written += len(data) - # this .write will spin the reactor, calling .doWrite and then - # .resumeProducing again, so be prepared for a re-entrant call - self.request.write(data) - if self.request and self.file.tell() == self.size: - self.request.unregisterProducer() - self.request.finish() - self.request = None - - def pauseProducing(self): - pass - - def stopProducing(self): - self.file.close() - self.request = None - - # Remotely relay producer interface. - - def view_resumeProducing(self, issuer): - self.resumeProducing() - - def view_pauseProducing(self, issuer): - self.pauseProducing() - - def view_stopProducing(self, issuer): - self.stopProducing() - - - synchronized = ['resumeProducing', 'stopProducing'] - -threadable.synchronize(FileTransfer) - -"""I contain AsIsProcessor, which serves files 'As Is' - Inspired by Apache's mod_asis -""" - -class ASISProcessor(resource.Resource): - - def __init__(self, path, registry=None): - resource.Resource.__init__(self) - self.path = path - self.registry = registry or Registry() - - def render(self, request): - request.startedWriting = 1 - res = File(self.path, registry=self.registry) - return res.render(request) diff --git a/tools/buildbot/pylibs/twisted/web/sux.py b/tools/buildbot/pylibs/twisted/web/sux.py deleted file mode 100644 index 6f8fea1..0000000 --- a/tools/buildbot/pylibs/twisted/web/sux.py +++ /dev/null @@ -1,657 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_xml -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -*S*mall, *U*ncomplicated *X*ML. - -This is a very simple implementation of XML/HTML as a network -protocol. It is not at all clever. Its main features are that it -does not: - - - support namespaces - - mung mnemonic entity references - - validate - - perform *any* external actions (such as fetching URLs or writing files) - under *any* circumstances - - has lots and lots of horrible hacks for supporting broken HTML (as an - option, they're not on by default). -""" - -from twisted.internet.protocol import Protocol, FileWrapper -from twisted.python.reflect import prefixedMethodNames - - - -# Elements of the three-tuples in the state table. -BEGIN_HANDLER = 0 -DO_HANDLER = 1 -END_HANDLER = 2 - -identChars = '.-_:' -lenientIdentChars = identChars + ';+#/%~' - -def nop(*args, **kw): - "Do nothing." - - -def unionlist(*args): - l = [] - for x in args: - l.extend(x) - d = dict([(x, 1) for x in l]) - return d.keys() - - -def zipfndict(*args, **kw): - default = kw.get('default', nop) - d = {} - for key in unionlist(*[fndict.keys() for fndict in args]): - d[key] = tuple([x.get(key, default) for x in args]) - return d - - -def prefixedMethodClassDict(clazz, prefix): - return dict([(name, getattr(clazz, prefix + name)) for name in prefixedMethodNames(clazz, prefix)]) - - -def prefixedMethodObjDict(obj, prefix): - return dict([(name, getattr(obj, prefix + name)) for name in prefixedMethodNames(obj.__class__, prefix)]) - - -class ParseError(Exception): - - def __init__(self, filename, line, col, message): - self.filename = filename - self.line = line - self.col = col - self.message = message - - def __str__(self): - return "%s:%s:%s: %s" % (self.filename, self.line, self.col, - self.message) - -class XMLParser(Protocol): - - state = None - encodings = None - filename = "<xml />" - beExtremelyLenient = 0 - _prepend = None - - # _leadingBodyData will sometimes be set before switching to the - # 'bodydata' state, when we "accidentally" read a byte of bodydata - # in a different state. - _leadingBodyData = None - - def connectionMade(self): - self.lineno = 1 - self.colno = 0 - self.encodings = [] - - def saveMark(self): - '''Get the line number and column of the last character parsed''' - # This gets replaced during dataReceived, restored afterwards - return (self.lineno, self.colno) - - def _parseError(self, message): - raise ParseError(*((self.filename,)+self.saveMark()+(message,))) - - def _buildStateTable(self): - '''Return a dictionary of begin, do, end state function tuples''' - # _buildStateTable leaves something to be desired but it does what it - # does.. probably slowly, so I'm doing some evil caching so it doesn't - # get called more than once per class. - stateTable = getattr(self.__class__, '__stateTable', None) - if stateTable is None: - stateTable = self.__class__.__stateTable = zipfndict( - *[prefixedMethodObjDict(self, prefix) - for prefix in ('begin_', 'do_', 'end_')]) - return stateTable - - def _decode(self, data): - if 'UTF-16' in self.encodings or 'UCS-2' in self.encodings: - assert not len(data) & 1, 'UTF-16 must come in pairs for now' - if self._prepend: - data = self._prepend + data - for encoding in self.encodings: - data = unicode(data, encoding) - return data - - def maybeBodyData(self): - if self.endtag: - return 'bodydata' - - # Get ready for fun! We're going to allow - # <script>if (foo < bar)</script> to work! - # We do this by making everything between <script> and - # </script> a Text - # BUT <script src="foo"> will be special-cased to do regular, - # lenient behavior, because those may not have </script> - # -radix - - if (self.tagName == 'script' - and not self.tagAttributes.has_key('src')): - # we do this ourselves rather than having begin_waitforendscript - # becuase that can get called multiple times and we don't want - # bodydata to get reset other than the first time. - self.begin_bodydata(None) - return 'waitforendscript' - return 'bodydata' - - - - def dataReceived(self, data): - stateTable = self._buildStateTable() - if not self.state: - # all UTF-16 starts with this string - if data.startswith('\xff\xfe'): - self._prepend = '\xff\xfe' - self.encodings.append('UTF-16') - data = data[2:] - elif data.startswith('\xfe\xff'): - self._prepend = '\xfe\xff' - self.encodings.append('UTF-16') - data = data[2:] - self.state = 'begin' - if self.encodings: - data = self._decode(data) - # bring state, lineno, colno into local scope - lineno, colno = self.lineno, self.colno - curState = self.state - # replace saveMark with a nested scope function - _saveMark = self.saveMark - def saveMark(): - return (lineno, colno) - self.saveMark = saveMark - # fetch functions from the stateTable - beginFn, doFn, endFn = stateTable[curState] - try: - for byte in data: - # do newline stuff - if byte == '\n': - lineno += 1 - colno = 0 - else: - colno += 1 - newState = doFn(byte) - if newState is not None and newState != curState: - # this is the endFn from the previous state - endFn() - curState = newState - beginFn, doFn, endFn = stateTable[curState] - beginFn(byte) - finally: - self.saveMark = _saveMark - self.lineno, self.colno = lineno, colno - # state doesn't make sense if there's an exception.. - self.state = curState - - - def connectionLost(self, reason): - """ - End the last state we were in. - """ - stateTable = self._buildStateTable() - stateTable[self.state][END_HANDLER]() - - - # state methods - - def do_begin(self, byte): - if byte.isspace(): - return - if byte != '<': - if self.beExtremelyLenient: - self._leadingBodyData = byte - return 'bodydata' - self._parseError("First char of document [%r] wasn't <" % (byte,)) - return 'tagstart' - - def begin_comment(self, byte): - self.commentbuf = '' - - def do_comment(self, byte): - self.commentbuf += byte - if self.commentbuf.endswith('-->'): - self.gotComment(self.commentbuf[:-3]) - return 'bodydata' - - def begin_tagstart(self, byte): - self.tagName = '' # name of the tag - self.tagAttributes = {} # attributes of the tag - self.termtag = 0 # is the tag self-terminating - self.endtag = 0 - - def do_tagstart(self, byte): - if byte.isalnum() or byte in identChars: - self.tagName += byte - if self.tagName == '!--': - return 'comment' - elif byte.isspace(): - if self.tagName: - if self.endtag: - # properly strict thing to do here is probably to only - # accept whitespace - return 'waitforgt' - return 'attrs' - else: - self._parseError("Whitespace before tag-name") - elif byte == '>': - if self.endtag: - self.gotTagEnd(self.tagName) - return 'bodydata' - else: - self.gotTagStart(self.tagName, {}) - return (not self.beExtremelyLenient) and 'bodydata' or self.maybeBodyData() - elif byte == '/': - if self.tagName: - return 'afterslash' - else: - self.endtag = 1 - elif byte in '!?': - if self.tagName: - if not self.beExtremelyLenient: - self._parseError("Invalid character in tag-name") - else: - self.tagName += byte - self.termtag = 1 - elif byte == '[': - if self.tagName == '!': - return 'expectcdata' - else: - self._parseError("Invalid '[' in tag-name") - else: - if self.beExtremelyLenient: - self.bodydata = '<' - return 'unentity' - self._parseError('Invalid tag character: %r'% byte) - - def begin_unentity(self, byte): - self.bodydata += byte - - def do_unentity(self, byte): - self.bodydata += byte - return 'bodydata' - - def end_unentity(self): - self.gotText(self.bodydata) - - def begin_expectcdata(self, byte): - self.cdatabuf = byte - - def do_expectcdata(self, byte): - self.cdatabuf += byte - cdb = self.cdatabuf - cd = '[CDATA[' - if len(cd) > len(cdb): - if cd.startswith(cdb): - return - elif self.beExtremelyLenient: - ## WHAT THE CRAP!? MSWord9 generates HTML that includes these - ## bizarre <![if !foo]> <![endif]> chunks, so I've gotta ignore - ## 'em as best I can. this should really be a separate parse - ## state but I don't even have any idea what these _are_. - return 'waitforgt' - else: - self._parseError("Mal-formed CDATA header") - if cd == cdb: - self.cdatabuf = '' - return 'cdata' - self._parseError("Mal-formed CDATA header") - - def do_cdata(self, byte): - self.cdatabuf += byte - if self.cdatabuf.endswith("]]>"): - self.cdatabuf = self.cdatabuf[:-3] - return 'bodydata' - - def end_cdata(self): - self.gotCData(self.cdatabuf) - self.cdatabuf = '' - - def do_attrs(self, byte): - if byte.isalnum() or byte in identChars: - # XXX FIXME really handle !DOCTYPE at some point - if self.tagName == '!DOCTYPE': - return 'doctype' - if self.tagName[0] in '!?': - return 'waitforgt' - return 'attrname' - elif byte.isspace(): - return - elif byte == '>': - self.gotTagStart(self.tagName, self.tagAttributes) - return (not self.beExtremelyLenient) and 'bodydata' or self.maybeBodyData() - elif byte == '/': - return 'afterslash' - elif self.beExtremelyLenient: - # discard and move on? Only case I've seen of this so far was: - # <foo bar="baz""> - return - self._parseError("Unexpected character: %r" % byte) - - def begin_doctype(self, byte): - self.doctype = byte - - def do_doctype(self, byte): - if byte == '>': - return 'bodydata' - self.doctype += byte - - def end_doctype(self): - self.gotDoctype(self.doctype) - self.doctype = None - - def do_waitforgt(self, byte): - if byte == '>': - if self.endtag or not self.beExtremelyLenient: - return 'bodydata' - return self.maybeBodyData() - - def begin_attrname(self, byte): - self.attrname = byte - self._attrname_termtag = 0 - - def do_attrname(self, byte): - if byte.isalnum() or byte in identChars: - self.attrname += byte - return - elif byte == '=': - return 'beforeattrval' - elif byte.isspace(): - return 'beforeeq' - elif self.beExtremelyLenient: - if byte in '"\'': - return 'attrval' - if byte in lenientIdentChars or byte.isalnum(): - self.attrname += byte - return - if byte == '/': - self._attrname_termtag = 1 - return - if byte == '>': - self.attrval = 'True' - self.tagAttributes[self.attrname] = self.attrval - self.gotTagStart(self.tagName, self.tagAttributes) - if self._attrname_termtag: - self.gotTagEnd(self.tagName) - return 'bodydata' - return self.maybeBodyData() - # something is really broken. let's leave this attribute where it - # is and move on to the next thing - return - self._parseError("Invalid attribute name: %r %r" % (self.attrname, byte)) - - def do_beforeattrval(self, byte): - if byte in '"\'': - return 'attrval' - elif byte.isspace(): - return - elif self.beExtremelyLenient: - if byte in lenientIdentChars or byte.isalnum(): - return 'messyattr' - if byte == '>': - self.attrval = 'True' - self.tagAttributes[self.attrname] = self.attrval - self.gotTagStart(self.tagName, self.tagAttributes) - return self.maybeBodyData() - if byte == '\\': - # I saw this in actual HTML once: - # <font size=\"3\"><sup>SM</sup></font> - return - self._parseError("Invalid initial attribute value: %r; Attribute values must be quoted." % byte) - - attrname = '' - attrval = '' - - def begin_beforeeq(self,byte): - self._beforeeq_termtag = 0 - - def do_beforeeq(self, byte): - if byte == '=': - return 'beforeattrval' - elif byte.isspace(): - return - elif self.beExtremelyLenient: - if byte.isalnum() or byte in identChars: - self.attrval = 'True' - self.tagAttributes[self.attrname] = self.attrval - return 'attrname' - elif byte == '>': - self.attrval = 'True' - self.tagAttributes[self.attrname] = self.attrval - self.gotTagStart(self.tagName, self.tagAttributes) - if self._beforeeq_termtag: - self.gotTagEnd(self.tagName) - return 'bodydata' - return self.maybeBodyData() - elif byte == '/': - self._beforeeq_termtag = 1 - return - self._parseError("Invalid attribute") - - def begin_attrval(self, byte): - self.quotetype = byte - self.attrval = '' - - def do_attrval(self, byte): - if byte == self.quotetype: - return 'attrs' - self.attrval += byte - - def end_attrval(self): - self.tagAttributes[self.attrname] = self.attrval - self.attrname = self.attrval = '' - - def begin_messyattr(self, byte): - self.attrval = byte - - def do_messyattr(self, byte): - if byte.isspace(): - return 'attrs' - elif byte == '>': - endTag = 0 - if self.attrval.endswith('/'): - endTag = 1 - self.attrval = self.attrval[:-1] - self.tagAttributes[self.attrname] = self.attrval - self.gotTagStart(self.tagName, self.tagAttributes) - if endTag: - self.gotTagEnd(self.tagName) - return 'bodydata' - return self.maybeBodyData() - else: - self.attrval += byte - - def end_messyattr(self): - if self.attrval: - self.tagAttributes[self.attrname] = self.attrval - - def begin_afterslash(self, byte): - self._after_slash_closed = 0 - - def do_afterslash(self, byte): - # this state is only after a self-terminating slash, e.g. <foo/> - if self._after_slash_closed: - self._parseError("Mal-formed")#XXX When does this happen?? - if byte != '>': - if self.beExtremelyLenient: - return - else: - self._parseError("No data allowed after '/'") - self._after_slash_closed = 1 - self.gotTagStart(self.tagName, self.tagAttributes) - self.gotTagEnd(self.tagName) - # don't need maybeBodyData here because there better not be - # any javascript code after a <script/>... we'll see :( - return 'bodydata' - - def begin_bodydata(self, byte): - if self._leadingBodyData: - self.bodydata = self._leadingBodyData - del self._leadingBodyData - else: - self.bodydata = '' - - def do_bodydata(self, byte): - if byte == '<': - return 'tagstart' - if byte == '&': - return 'entityref' - self.bodydata += byte - - def end_bodydata(self): - self.gotText(self.bodydata) - self.bodydata = '' - - def do_waitforendscript(self, byte): - if byte == '<': - return 'waitscriptendtag' - self.bodydata += byte - - def begin_waitscriptendtag(self, byte): - self.temptagdata = '' - self.tagName = '' - self.endtag = 0 - - def do_waitscriptendtag(self, byte): - # 1 enforce / as first byte read - # 2 enforce following bytes to be subset of "script" until - # tagName == "script" - # 2a when that happens, gotText(self.bodydata) and gotTagEnd(self.tagName) - # 3 spaces can happen anywhere, they're ignored - # e.g. < / script > - # 4 anything else causes all data I've read to be moved to the - # bodydata, and switch back to waitforendscript state - - # If it turns out this _isn't_ a </script>, we need to - # remember all the data we've been through so we can append it - # to bodydata - self.temptagdata += byte - - # 1 - if byte == '/': - self.endtag = True - elif not self.endtag: - self.bodydata += "<" + self.temptagdata - return 'waitforendscript' - # 2 - elif byte.isalnum() or byte in identChars: - self.tagName += byte - if not 'script'.startswith(self.tagName): - self.bodydata += "<" + self.temptagdata - return 'waitforendscript' - elif self.tagName == 'script': - self.gotText(self.bodydata) - self.gotTagEnd(self.tagName) - return 'waitforgt' - # 3 - elif byte.isspace(): - return 'waitscriptendtag' - # 4 - else: - self.bodydata += "<" + self.temptagdata - return 'waitforendscript' - - - def begin_entityref(self, byte): - self.erefbuf = '' - self.erefextra = '' # extra bit for lenient mode - - def do_entityref(self, byte): - if byte.isspace() or byte == "<": - if self.beExtremelyLenient: - # '&foo' probably was '&foo' - if self.erefbuf and self.erefbuf != "amp": - self.erefextra = self.erefbuf - self.erefbuf = "amp" - if byte == "<": - return "tagstart" - else: - self.erefextra += byte - return 'spacebodydata' - self._parseError("Bad entity reference") - elif byte != ';': - self.erefbuf += byte - else: - return 'bodydata' - - def end_entityref(self): - self.gotEntityReference(self.erefbuf) - - # hacky support for space after & in entityref in beExtremelyLenient - # state should only happen in that case - def begin_spacebodydata(self, byte): - self.bodydata = self.erefextra - self.erefextra = None - do_spacebodydata = do_bodydata - end_spacebodydata = end_bodydata - - # Sorta SAX-ish API - - def gotTagStart(self, name, attributes): - '''Encountered an opening tag. - - Default behaviour is to print.''' - print 'begin', name, attributes - - def gotText(self, data): - '''Encountered text - - Default behaviour is to print.''' - print 'text:', repr(data) - - def gotEntityReference(self, entityRef): - '''Encountered mnemonic entity reference - - Default behaviour is to print.''' - print 'entityRef: &%s;' % entityRef - - def gotComment(self, comment): - '''Encountered comment. - - Default behaviour is to ignore.''' - pass - - def gotCData(self, cdata): - '''Encountered CDATA - - Default behaviour is to call the gotText method''' - self.gotText(cdata) - - def gotDoctype(self, doctype): - """Encountered DOCTYPE - - This is really grotty: it basically just gives you everything between - '<!DOCTYPE' and '>' as an argument. - """ - print '!DOCTYPE', repr(doctype) - - def gotTagEnd(self, name): - '''Encountered closing tag - - Default behaviour is to print.''' - print 'end', name - -if __name__ == '__main__': - from cStringIO import StringIO - testDocument = ''' - - <!DOCTYPE ignore all this shit, hah its malformed!!!!@$> - <?xml version="suck it"?> - <foo> - A - <bar /> - <baz boz="buz">boz &zop;</baz> - <![CDATA[ foo bar baz ]]> - </foo> - ''' - x = XMLParser() - x.makeConnection(FileWrapper(StringIO())) - # fn = "/home/glyph/Projects/Twisted/doc/howto/ipc10paper.html" - fn = "/home/glyph/gruesome.xml" - # testDocument = open(fn).read() - x.dataReceived(testDocument) diff --git a/tools/buildbot/pylibs/twisted/web/tap.py b/tools/buildbot/pylibs/twisted/web/tap.py deleted file mode 100644 index 559b801..0000000 --- a/tools/buildbot/pylibs/twisted/web/tap.py +++ /dev/null @@ -1,201 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Support for creating a service which runs a web server. -""" - -import os - -# Twisted Imports -from twisted.web import server, static, twcgi, script, demo, distrib, trp -from twisted.internet import interfaces -from twisted.python import usage, reflect -from twisted.spread import pb -from twisted.application import internet, service, strports - - -class Options(usage.Options): - synopsis = "Usage: mktap web [options]" - optParameters = [["port", "p", "8080","Port to start the server on."], - ["logfile", "l", None, "Path to web CLF (Combined Log Format) log file."], - ["https", None, None, "Port to listen on for Secure HTTP."], - ["certificate", "c", "server.pem", "SSL certificate to use for HTTPS. "], - ["privkey", "k", "server.pem", "SSL certificate to use for HTTPS."], - ] - optFlags = [["personal", "", - "Instead of generating a webserver, generate a " - "ResourcePublisher which listens on " - "~/%s" % distrib.UserDirectory.userSocketName], - ["notracebacks", "n", "Display tracebacks in broken web pages. " + - "Displaying tracebacks to users may be security risk!"], -] - zsh_actions = {"logfile" : "_files -g '*.log'", "certificate" : "_files -g '*.pem'", - "privkey" : "_files -g '*.pem'"} - - - longdesc = """\ -This creates a web.tap file that can be used by twistd. If you specify -no arguments, it will be a demo webserver that has the Test class from -twisted.web.demo in it.""" - - def __init__(self): - usage.Options.__init__(self) - self['indexes'] = [] - self['root'] = None - - def opt_index(self, indexName): - """Add the name of a file used to check for directory indexes. - [default: index, index.html] - """ - self['indexes'].append(indexName) - - opt_i = opt_index - - def opt_user(self): - """Makes a server with ~/public_html and ~/.twistd-web-pb support for - users. - """ - self['root'] = distrib.UserDirectory() - - opt_u = opt_user - - def opt_path(self, path): - """<path> is either a specific file or a directory to - be set as the root of the web server. Use this if you - have a directory full of HTML, cgi, php3, epy, or rpy files or - any other files that you want to be served up raw. - """ - - self['root'] = static.File(os.path.abspath(path)) - self['root'].processors = { - '.cgi': twcgi.CGIScript, - '.php3': twcgi.PHP3Script, - '.php': twcgi.PHPScript, - '.epy': script.PythonScript, - '.rpy': script.ResourceScript, - '.trp': trp.ResourceUnpickler, - } - - def opt_processor(self, proc): - """`ext=class' where `class' is added as a Processor for files ending - with `ext'. - """ - if not isinstance(self['root'], static.File): - raise usage.UsageError("You can only use --processor after --path.") - ext, klass = proc.split('=', 1) - self['root'].processors[ext] = reflect.namedClass(klass) - - def opt_static(self, path): - """Same as --path, this is deprecated and will be removed in a - future release.""" - print ("WARNING: --static is deprecated and will be removed in" - "a future release. Please use --path.") - self.opt_path(path) - opt_s = opt_static - - def opt_class(self, className): - """Create a Resource subclass with a zero-argument constructor. - """ - classObj = reflect.namedClass(className) - self['root'] = classObj() - - - def opt_resource_script(self, name): - """An .rpy file to be used as the root resource of the webserver.""" - self['root'] = script.ResourceScriptWrapper(name) - - - def opt_mime_type(self, defaultType): - """Specify the default mime-type for static files.""" - if not isinstance(self['root'], static.File): - raise usage.UsageError("You can only use --mime_type after --path.") - self['root'].defaultType = defaultType - opt_m = opt_mime_type - - - def opt_allow_ignore_ext(self): - """Specify whether or not a request for 'foo' should return 'foo.ext'""" - if not isinstance(self['root'], static.File): - raise usage.UsageError("You can only use --allow_ignore_ext " - "after --path.") - self['root'].ignoreExt('*') - - def opt_ignore_ext(self, ext): - """Specify an extension to ignore. These will be processed in order. - """ - if not isinstance(self['root'], static.File): - raise usage.UsageError("You can only use --ignore_ext " - "after --path.") - self['root'].ignoreExt(ext) - - def opt_flashconduit(self, port=None): - """Start a flashconduit on the specified port. - """ - if not port: - port = "4321" - self['flashconduit'] = port - - def postOptions(self): - if self['https']: - try: - from twisted.internet.ssl import DefaultOpenSSLContextFactory - except ImportError: - raise usage.UsageError("SSL support not installed") - - - -def makePersonalServerFactory(site): - """ - Create and return a factory which will respond to I{distrib} requests - against the given site. - - @type site: L{twisted.web.server.Site} - @rtype: L{twisted.internet.protocol.Factory} - """ - return pb.PBServerFactory(distrib.ResourcePublisher(site)) - - - -def makeService(config): - s = service.MultiService() - if config['root']: - root = config['root'] - if config['indexes']: - config['root'].indexNames = config['indexes'] - else: - # This really ought to be web.Admin or something - root = demo.Test() - - if isinstance(root, static.File): - root.registry.setComponent(interfaces.IServiceCollection, s) - - if config['logfile']: - site = server.Site(root, logPath=config['logfile']) - else: - site = server.Site(root) - - site.displayTracebacks = not config["notracebacks"] - - if config['personal']: - import pwd - name, passwd, uid, gid, gecos, dir, shell = pwd.getpwuid(os.getuid()) - personal = internet.UNIXServer( - os.path.join(dir, distrib.UserDirectory.userSocketName), - makePersonalServerFactory(site)) - personal.setServiceParent(s) - else: - if config['https']: - from twisted.internet.ssl import DefaultOpenSSLContextFactory - i = internet.SSLServer(int(config['https']), site, - DefaultOpenSSLContextFactory(config['privkey'], - config['certificate'])) - i.setServiceParent(s) - strports.service(config['port'], site).setServiceParent(s) - - flashport = config.get('flashconduit', None) - if flashport: - from twisted.web.woven.flashconduit import FlashConduitFactory - i = internet.TCPServer(int(flashport), FlashConduitFactory(site)) - i.setServiceParent(s) - return s diff --git a/tools/buildbot/pylibs/twisted/web/test/__init__.py b/tools/buildbot/pylibs/twisted/web/test/__init__.py deleted file mode 100644 index 1ca3db1..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/__init__.py +++ /dev/null @@ -1 +0,0 @@ -'web tests' diff --git a/tools/buildbot/pylibs/twisted/web/test/test_cgi.py b/tools/buildbot/pylibs/twisted/web/test/test_cgi.py deleted file mode 100644 index 528c4d1..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/test_cgi.py +++ /dev/null @@ -1,121 +0,0 @@ -import sys, os - -from twisted.trial import unittest -from twisted.internet import reactor, interfaces -from twisted.python import util -from twisted.web import static, twcgi, server, resource -from twisted.web import client - -DUMMY_CGI = '''\ -print "Header: OK" -print -print "cgi output" -''' - -READINPUT_CGI = '''\ -# this is an example of a correctly-written CGI script which reads a body -# from stdin, which only reads env['CONTENT_LENGTH'] bytes. - -import os, sys - -body_length = int(os.environ.get('CONTENT_LENGTH',0)) -indata = sys.stdin.read(body_length) -print "Header: OK" -print -print "readinput ok" -''' - -READALLINPUT_CGI = '''\ -# this is an example of the typical (incorrect) CGI script which expects -# the server to close stdin when the body of the request is complete. -# A correct CGI should only read env['CONTENT_LENGTH'] bytes. - -import sys - -indata = sys.stdin.read() -print "Header: OK" -print -print "readallinput ok" -''' - -class PythonScript(twcgi.FilteredScript): - filter = sys.executable - filters = sys.executable, # web2's version - -class CGI(unittest.TestCase): - def startServer(self, cgi): - root = resource.Resource() - cgipath = util.sibpath(__file__, cgi) - root.putChild("cgi", PythonScript(cgipath)) - site = server.Site(root) - self.p = reactor.listenTCP(0, site) - return self.p.getHost().port - - def tearDown(self): - if self.p: - return self.p.stopListening() - - - def testCGI(self): - cgiFilename = os.path.abspath(self.mktemp()) - cgiFile = file(cgiFilename, 'wt') - cgiFile.write(DUMMY_CGI) - cgiFile.close() - - portnum = self.startServer(cgiFilename) - d = client.getPage("http://localhost:%d/cgi" % portnum) - d.addCallback(self._testCGI_1) - return d - def _testCGI_1(self, res): - self.failUnlessEqual(res, "cgi output" + os.linesep) - - - def testReadEmptyInput(self): - cgiFilename = os.path.abspath(self.mktemp()) - cgiFile = file(cgiFilename, 'wt') - cgiFile.write(READINPUT_CGI) - cgiFile.close() - - portnum = self.startServer(cgiFilename) - d = client.getPage("http://localhost:%d/cgi" % portnum) - d.addCallback(self._testReadEmptyInput_1) - return d - testReadEmptyInput.timeout = 5 - def _testReadEmptyInput_1(self, res): - self.failUnlessEqual(res, "readinput ok%s" % os.linesep) - - def testReadInput(self): - cgiFilename = os.path.abspath(self.mktemp()) - cgiFile = file(cgiFilename, 'wt') - cgiFile.write(READINPUT_CGI) - cgiFile.close() - - portnum = self.startServer(cgiFilename) - d = client.getPage("http://localhost:%d/cgi" % portnum, - method="POST", - postdata="Here is your stdin") - d.addCallback(self._testReadInput_1) - return d - testReadInput.timeout = 5 - def _testReadInput_1(self, res): - self.failUnlessEqual(res, "readinput ok%s" % os.linesep) - - - def testReadAllInput(self): - cgiFilename = os.path.abspath(self.mktemp()) - cgiFile = file(cgiFilename, 'wt') - cgiFile.write(READALLINPUT_CGI) - cgiFile.close() - - portnum = self.startServer(cgiFilename) - d = client.getPage("http://localhost:%d/cgi" % portnum, - method="POST", - postdata="Here is your stdin") - d.addCallback(self._testReadAllInput_1) - return d - testReadAllInput.timeout = 5 - def _testReadAllInput_1(self, res): - self.failUnlessEqual(res, "readallinput ok%s" % os.linesep) - -if not interfaces.IReactorProcess.providedBy(reactor): - CGI.skip = "CGI tests require a functional reactor.spawnProcess()" diff --git a/tools/buildbot/pylibs/twisted/web/test/test_distrib.py b/tools/buildbot/pylibs/twisted/web/test/test_distrib.py deleted file mode 100644 index 152b3f3..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/test_distrib.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright (c) 2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.web.distrib}. -""" - -from twisted.trial import unittest -from twisted.web import http, distrib, client, resource, static, server -from twisted.internet import reactor, defer -from twisted.spread import pb -from twisted.python import log - -class MySite(server.Site): - def stopFactory(self): - if hasattr(self, "logFile"): - if self.logFile != log.logfile: - self.logFile.close() - del self.logFile - - -class PBServerFactory(pb.PBServerFactory): - def buildProtocol(self, addr): - self.proto = pb.PBServerFactory.buildProtocol(self, addr) - return self.proto - - -class DistribTest(unittest.TestCase): - port1 = None - port2 = None - sub = None - - def tearDown(self): - dl = [defer.Deferred(), defer.Deferred()] - self.f1.proto.notifyOnDisconnect(lambda: dl[0].callback(None)) - if self.sub is not None: - self.sub.publisher.broker.notifyOnDisconnect( - lambda: dl[1].callback(None)) - self.sub.publisher.broker.transport.loseConnection() - http._logDateTimeStop() - if self.port1 is not None: - dl.append(self.port1.stopListening()) - if self.port2 is not None: - dl.append(self.port2.stopListening()) - return defer.gatherResults(dl) - - def testDistrib(self): - # site1 is the publisher - r1 = resource.Resource() - r1.putChild("there", static.Data("root", "text/plain")) - site1 = server.Site(r1) - self.f1 = PBServerFactory(distrib.ResourcePublisher(site1)) - self.port1 = reactor.listenTCP(0, self.f1) - self.sub = distrib.ResourceSubscription("127.0.0.1", - self.port1.getHost().port) - r2 = resource.Resource() - r2.putChild("here", self.sub) - f2 = MySite(r2) - self.port2 = reactor.listenTCP(0, f2) - d = client.getPage("http://127.0.0.1:%d/here/there" % \ - self.port2.getHost().port) - d.addCallback(self.failUnlessEqual, 'root') - return d - diff --git a/tools/buildbot/pylibs/twisted/web/test/test_domhelpers.py b/tools/buildbot/pylibs/twisted/web/test/test_domhelpers.py deleted file mode 100644 index 6d52fc2..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/test_domhelpers.py +++ /dev/null @@ -1,234 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_domhelpers -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -"""Specific tests for (some of) the methods in t.web.domhelpers""" - -from twisted.trial.unittest import TestCase - -from twisted.web import microdom - -from twisted.web import domhelpers - -class DomHelpersTest(TestCase): - def test_getElementsByTagName(self): - doc1=microdom.parseString('<foo/>') - actual=domhelpers.getElementsByTagName(doc1, 'foo')[0].nodeName - expected='foo' - self.assertEquals(actual, expected) - el1=doc1.documentElement - actual=domhelpers.getElementsByTagName(el1, 'foo')[0].nodeName - self.assertEqual(actual, expected) - - doc2_xml='<a><foo in="a"/><b><foo in="b"/></b><c><foo in="c"/></c><foo in="d"/><foo in="ef"/><g><foo in="g"/><h><foo in="h"/></h></g></a>' - doc2=microdom.parseString(doc2_xml) - tag_list=domhelpers.getElementsByTagName(doc2, 'foo') - actual=''.join([node.getAttribute('in') for node in tag_list]) - expected='abcdefgh' - self.assertEquals(actual, expected) - el2=doc2.documentElement - tag_list=domhelpers.getElementsByTagName(el2, 'foo') - actual=''.join([node.getAttribute('in') for node in tag_list]) - self.assertEqual(actual, expected) - - doc3_xml=''' -<a><foo in="a"/> - <b><foo in="b"/> - <d><foo in="d"/> - <g><foo in="g"/></g> - <h><foo in="h"/></h> - </d> - <e><foo in="e"/> - <i><foo in="i"/></i> - </e> - </b> - <c><foo in="c"/> - <f><foo in="f"/> - <j><foo in="j"/></j> - </f> - </c> -</a>''' - doc3=microdom.parseString(doc3_xml) - tag_list=domhelpers.getElementsByTagName(doc3, 'foo') - actual=''.join([node.getAttribute('in') for node in tag_list]) - expected='abdgheicfj' - self.assertEquals(actual, expected) - el3=doc3.documentElement - tag_list=domhelpers.getElementsByTagName(el3, 'foo') - actual=''.join([node.getAttribute('in') for node in tag_list]) - self.assertEqual(actual, expected) - - doc4_xml='<foo><bar></bar><baz><foo/></baz></foo>' - doc4=microdom.parseString(doc4_xml) - actual=domhelpers.getElementsByTagName(doc4, 'foo') - root=doc4.documentElement - expected=[root, root.lastChild().firstChild()] - self.assertEquals(actual, expected) - actual=domhelpers.getElementsByTagName(root, 'foo') - self.assertEqual(actual, expected) - - - def test_gatherTextNodes(self): - doc1=microdom.parseString('<a>foo</a>') - actual=domhelpers.gatherTextNodes(doc1) - expected='foo' - self.assertEqual(actual, expected) - actual=domhelpers.gatherTextNodes(doc1.documentElement) - self.assertEqual(actual, expected) - - doc2_xml='<a>a<b>b</b><c>c</c>def<g>g<h>h</h></g></a>' - doc2=microdom.parseString(doc2_xml) - actual=domhelpers.gatherTextNodes(doc2) - expected='abcdefgh' - self.assertEqual(actual, expected) - actual=domhelpers.gatherTextNodes(doc2.documentElement) - self.assertEqual(actual, expected) - - doc3_xml=('<a>a<b>b<d>d<g>g</g><h>h</h></d><e>e<i>i</i></e></b>' + - '<c>c<f>f<j>j</j></f></c></a>') - doc3=microdom.parseString(doc3_xml) - actual=domhelpers.gatherTextNodes(doc3) - expected='abdgheicfj' - self.assertEqual(actual, expected) - actual=domhelpers.gatherTextNodes(doc3.documentElement) - self.assertEqual(actual, expected) - - doc4_xml='''<html> - <head> - </head> - <body> - stuff - </body> -</html> -''' - doc4=microdom.parseString(doc4_xml) - actual=domhelpers.gatherTextNodes(doc4) - expected='\n stuff\n ' - assert actual==expected, 'expected %s, got %s' % (expected, actual) - actual=domhelpers.gatherTextNodes(doc4.documentElement) - self.assertEqual(actual, expected) - - doc5_xml='<x>Soufflé</x>' - doc5=microdom.parseString(doc5_xml) - actual=domhelpers.gatherTextNodes(doc5) - expected='Soufflé' - self.assertEqual(actual, expected) - actual=domhelpers.gatherTextNodes(doc5.documentElement) - self.assertEqual(actual, expected) - - def test_clearNode(self): - doc1=microdom.parseString('<a><b><c><d/></c></b></a>') - a_node=doc1.documentElement - domhelpers.clearNode(a_node) - actual=doc1.documentElement.toxml() - expected='<a></a>' - assert actual==expected, 'expected %s, got %s' % (expected, actual) - - doc2=microdom.parseString('<a><b><c><d/></c></b></a>') - b_node=doc2.documentElement.childNodes[0] - domhelpers.clearNode(b_node) - actual=doc2.documentElement.toxml() - expected='<a><b></b></a>' - assert actual==expected, 'expected %s, got %s' % (expected, actual) - - doc3=microdom.parseString('<a><b><c><d/></c></b></a>') - c_node=doc3.documentElement.childNodes[0].childNodes[0] - domhelpers.clearNode(c_node) - actual=doc3.documentElement.toxml() - expected='<a><b><c></c></b></a>' - assert actual==expected, 'expected %s, got %s' % (expected, actual) - - def test_get(self): - doc1=microdom.parseString('<a><b id="bar"/><c class="foo"/></a>') - node=domhelpers.get(doc1, "foo") - actual=node.toxml() - expected='<c class="foo"></c>' - assert actual==expected, 'expected %s, got %s' % (expected, actual) - - node=domhelpers.get(doc1, "bar") - actual=node.toxml() - expected='<b id="bar"></b>' - assert actual==expected, 'expected %s, got %s' % (expected, actual) - - self.assertRaises(domhelpers.NodeLookupError, - domhelpers.get, - doc1, - "pzork") - - def test_getIfExists(self): - doc1=microdom.parseString('<a><b id="bar"/><c class="foo"/></a>') - node=domhelpers.getIfExists(doc1, "foo") - actual=node.toxml() - expected='<c class="foo"></c>' - assert actual==expected, 'expected %s, got %s' % (expected, actual) - - node=domhelpers.getIfExists(doc1, "pzork") - assert node==None, 'expected None, didn\'t get None' - - def test_getAndClear(self): - doc1=microdom.parseString('<a><b id="foo"><c></c></b></a>') - node=domhelpers.getAndClear(doc1, "foo") - actual=node.toxml() - expected='<b id="foo"></b>' - assert actual==expected, 'expected %s, got %s' % (expected, actual) - - def test_locateNodes(self): - doc1=microdom.parseString('<a><b foo="olive"><c foo="olive"/></b><d foo="poopy"/></a>') - node_list=domhelpers.locateNodes(doc1.childNodes, 'foo', 'olive', - noNesting=1) - actual=''.join([node.toxml() for node in node_list]) - expected='<b foo="olive"><c foo="olive"></c></b>' - assert actual==expected, 'expected %s, got %s' % (expected, actual) - - node_list=domhelpers.locateNodes(doc1.childNodes, 'foo', 'olive', - noNesting=0) - actual=''.join([node.toxml() for node in node_list]) - expected='<b foo="olive"><c foo="olive"></c></b><c foo="olive"></c>' - assert actual==expected, 'expected %s, got %s' % (expected, actual) - - def test_getParents(self): - doc1=microdom.parseString('<a><b><c><d/></c><e/></b><f/></a>') - node_list=domhelpers.getParents(doc1.childNodes[0].childNodes[0].childNodes[0]) - actual=''.join([node.tagName for node in node_list - if hasattr(node, 'tagName')]) - expected='cba' - assert actual==expected, 'expected %s, got %s' % (expected, actual) - - def test_findElementsWithAttribute(self): - doc1=microdom.parseString('<a foo="1"><b foo="2"/><c foo="1"/><d/></a>') - node_list=domhelpers.findElementsWithAttribute(doc1, 'foo') - actual=''.join([node.tagName for node in node_list]) - expected='abc' - assert actual==expected, 'expected %s, got %s' % (expected, actual) - - node_list=domhelpers.findElementsWithAttribute(doc1, 'foo', '1') - actual=''.join([node.tagName for node in node_list]) - expected='ac' - assert actual==expected, 'expected %s, got %s' % (expected, actual) - - def test_findNodesNamed(self): - doc1=microdom.parseString('<doc><foo/><bar/><foo>a</foo></doc>') - node_list=domhelpers.findNodesNamed(doc1, 'foo') - actual=len(node_list) - expected=2 - assert actual==expected, 'expected %d, got %d' % (expected, actual) - - # NOT SURE WHAT THESE ARE SUPPOSED TO DO.. - # def test_RawText FIXME - # def test_superSetAttribute FIXME - # def test_superPrependAttribute FIXME - # def test_superAppendAttribute FIXME - # def test_substitute FIXME - - def test_escape(self): - j='this string " contains many & characters> xml< won\'t like' - expected='this string " contains many & characters> xml< won\'t like' - self.assertEqual(domhelpers.escape(j), expected) - - def test_unescape(self): - j='this string " has && entities > < and some characters xml won\'t like<' - expected='this string " has && entities > < and some characters xml won\'t like<' - self.assertEqual(domhelpers.unescape(j), expected) diff --git a/tools/buildbot/pylibs/twisted/web/test/test_http.py b/tools/buildbot/pylibs/twisted/web/test/test_http.py deleted file mode 100644 index 97caba5..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/test_http.py +++ /dev/null @@ -1,548 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Test HTTP support. -""" - -from urlparse import urlparse, urlunsplit, clear_cache -import string, random, urllib, cgi - -from twisted.trial import unittest -from twisted.web import http -from twisted.protocols import loopback -from twisted.internet import protocol -from twisted.test.test_protocols import StringIOWithoutClosing - - -class DateTimeTest(unittest.TestCase): - """Test date parsing functions.""" - - def testRoundtrip(self): - for i in range(10000): - time = random.randint(0, 2000000000) - timestr = http.datetimeToString(time) - time2 = http.stringToDatetime(timestr) - self.assertEquals(time, time2) - - -class OrderedDict: - - def __init__(self, dict): - self.dict = dict - self.l = dict.keys() - - def __setitem__(self, k, v): - self.l.append(k) - self.dict[k] = v - - def __getitem__(self, k): - return self.dict[k] - - def items(self): - result = [] - for i in self.l: - result.append((i, self.dict[i])) - return result - - def __getattr__(self, attr): - return getattr(self.dict, attr) - - -class DummyHTTPHandler(http.Request): - - def process(self): - self.headers = OrderedDict(self.headers) - self.content.seek(0, 0) - data = self.content.read() - length = self.getHeader('content-length') - request = "'''\n"+str(length)+"\n"+data+"'''\n" - self.setResponseCode(200) - self.setHeader("Request", self.uri) - self.setHeader("Command", self.method) - self.setHeader("Version", self.clientproto) - self.setHeader("Content-Length", len(request)) - self.write(request) - self.finish() - - -class LoopbackHTTPClient(http.HTTPClient): - - def connectionMade(self): - self.sendCommand("GET", "/foo/bar") - self.sendHeader("Content-Length", 10) - self.endHeaders() - self.transport.write("0123456789") - - -class HTTP1_0TestCase(unittest.TestCase): - - requests = '''\ -GET / HTTP/1.0 - -GET / HTTP/1.1 -Accept: text/html - -''' - requests = string.replace(requests, '\n', '\r\n') - - expected_response = "HTTP/1.0 200 OK\015\012Request: /\015\012Command: GET\015\012Version: HTTP/1.0\015\012Content-length: 13\015\012\015\012'''\012None\012'''\012" - - def test_buffer(self): - """ - Send requests over a channel and check responses match what is expected. - """ - b = StringIOWithoutClosing() - a = http.HTTPChannel() - a.requestFactory = DummyHTTPHandler - a.makeConnection(protocol.FileWrapper(b)) - # one byte at a time, to stress it. - for byte in self.requests: - a.dataReceived(byte) - a.connectionLost(IOError("all one")) - value = b.getvalue() - self.assertEquals(value, self.expected_response) - - -class HTTP1_1TestCase(HTTP1_0TestCase): - - requests = '''\ -GET / HTTP/1.1 -Accept: text/html - -POST / HTTP/1.1 -Content-Length: 10 - -0123456789POST / HTTP/1.1 -Content-Length: 10 - -0123456789HEAD / HTTP/1.1 - -''' - requests = string.replace(requests, '\n', '\r\n') - - expected_response = "HTTP/1.1 200 OK\015\012Request: /\015\012Command: GET\015\012Version: HTTP/1.1\015\012Content-length: 13\015\012\015\012'''\012None\012'''\012HTTP/1.1 200 OK\015\012Request: /\015\012Command: POST\015\012Version: HTTP/1.1\015\012Content-length: 21\015\012\015\012'''\01210\0120123456789'''\012HTTP/1.1 200 OK\015\012Request: /\015\012Command: POST\015\012Version: HTTP/1.1\015\012Content-length: 21\015\012\015\012'''\01210\0120123456789'''\012HTTP/1.1 200 OK\015\012Request: /\015\012Command: HEAD\015\012Version: HTTP/1.1\015\012Content-length: 13\015\012\015\012" - -class HTTP1_1_close_TestCase(HTTP1_0TestCase): - - requests = '''\ -GET / HTTP/1.1 -Accept: text/html -Connection: close - -GET / HTTP/1.0 - -''' - - requests = string.replace(requests, '\n', '\r\n') - - expected_response = "HTTP/1.1 200 OK\015\012Connection: close\015\012Request: /\015\012Command: GET\015\012Version: HTTP/1.1\015\012Content-length: 13\015\012\015\012'''\012None\012'''\012" - - -class HTTP0_9TestCase(HTTP1_0TestCase): - - requests = '''\ -GET / -''' - requests = string.replace(requests, '\n', '\r\n') - - expected_response = "HTTP/1.1 400 Bad Request\r\n\r\n" - - -class HTTPLoopbackTestCase(unittest.TestCase): - - expectedHeaders = {'request' : '/foo/bar', - 'command' : 'GET', - 'version' : 'HTTP/1.0', - 'content-length' : '21'} - numHeaders = 0 - gotStatus = 0 - gotResponse = 0 - gotEndHeaders = 0 - - def _handleStatus(self, version, status, message): - self.gotStatus = 1 - self.assertEquals(version, "HTTP/1.0") - self.assertEquals(status, "200") - - def _handleResponse(self, data): - self.gotResponse = 1 - self.assertEquals(data, "'''\n10\n0123456789'''\n") - - def _handleHeader(self, key, value): - self.numHeaders = self.numHeaders + 1 - self.assertEquals(self.expectedHeaders[string.lower(key)], value) - - def _handleEndHeaders(self): - self.gotEndHeaders = 1 - self.assertEquals(self.numHeaders, 4) - - def testLoopback(self): - server = http.HTTPChannel() - server.requestFactory = DummyHTTPHandler - client = LoopbackHTTPClient() - client.handleResponse = self._handleResponse - client.handleHeader = self._handleHeader - client.handleEndHeaders = self._handleEndHeaders - client.handleStatus = self._handleStatus - d = loopback.loopbackAsync(server, client) - d.addCallback(self._cbTestLoopback) - return d - - def _cbTestLoopback(self, ignored): - if not (self.gotStatus and self.gotResponse and self.gotEndHeaders): - raise RuntimeError( - "didn't got all callbacks %s" - % [self.gotStatus, self.gotResponse, self.gotEndHeaders]) - del self.gotEndHeaders - del self.gotResponse - del self.gotStatus - del self.numHeaders - - -class PRequest: - """Dummy request for persistence tests.""" - - def __init__(self, **headers): - self.received_headers = headers - self.headers = {} - - def getHeader(self, k): - return self.received_headers.get(k, '') - - def setHeader(self, k, v): - self.headers[k] = v - - -class PersistenceTestCase(unittest.TestCase): - """Tests for persistent HTTP connections.""" - - ptests = [#(PRequest(connection="Keep-Alive"), "HTTP/1.0", 1, {'connection' : 'Keep-Alive'}), - (PRequest(), "HTTP/1.0", 0, {'connection': None}), - (PRequest(connection="close"), "HTTP/1.1", 0, {'connection' : 'close'}), - (PRequest(), "HTTP/1.1", 1, {'connection': None}), - (PRequest(), "HTTP/0.9", 0, {'connection': None}), - ] - - - def testAlgorithm(self): - c = http.HTTPChannel() - for req, version, correctResult, resultHeaders in self.ptests: - result = c.checkPersistence(req, version) - self.assertEquals(result, correctResult) - for header in resultHeaders.keys(): - self.assertEquals(req.headers.get(header, None), resultHeaders[header]) - - -class ChunkingTestCase(unittest.TestCase): - - strings = ["abcv", "", "fdfsd423", "Ffasfas\r\n", - "523523\n\rfsdf", "4234"] - - def testChunks(self): - for s in self.strings: - self.assertEquals((s, ''), http.fromChunk(''.join(http.toChunk(s)))) - self.assertRaises(ValueError, http.fromChunk, '-5\r\nmalformed!\r\n') - - def testConcatenatedChunks(self): - chunked = ''.join([''.join(http.toChunk(t)) for t in self.strings]) - result = [] - buffer = "" - for c in chunked: - buffer = buffer + c - try: - data, buffer = http.fromChunk(buffer) - result.append(data) - except ValueError: - pass - self.assertEquals(result, self.strings) - - - -class ParsingTestCase(unittest.TestCase): - - def runRequest(self, httpRequest, requestClass, success=1): - httpRequest = httpRequest.replace("\n", "\r\n") - b = StringIOWithoutClosing() - a = http.HTTPChannel() - a.requestFactory = requestClass - a.makeConnection(protocol.FileWrapper(b)) - # one byte at a time, to stress it. - for byte in httpRequest: - if a.transport.closed: - break - a.dataReceived(byte) - a.connectionLost(IOError("all done")) - if success: - self.assertEquals(self.didRequest, 1) - del self.didRequest - else: - self.assert_(not hasattr(self, "didRequest")) - - def testBasicAuth(self): - testcase = self - class Request(http.Request): - l = [] - def process(self): - testcase.assertEquals(self.getUser(), self.l[0]) - testcase.assertEquals(self.getPassword(), self.l[1]) - for u, p in [("foo", "bar"), ("hello", "there:z")]: - Request.l[:] = [u, p] - s = "%s:%s" % (u, p) - f = "GET / HTTP/1.0\nAuthorization: Basic %s\n\n" % (s.encode("base64").strip(), ) - self.runRequest(f, Request, 0) - - def testTooManyHeaders(self): - httpRequest = "GET / HTTP/1.0\n" - for i in range(502): - httpRequest += "%s: foo\n" % i - httpRequest += "\n" - class MyRequest(http.Request): - def process(self): - raise RuntimeError, "should not get called" - self.runRequest(httpRequest, MyRequest, 0) - - def testHeaders(self): - httpRequest = """\ -GET / HTTP/1.0 -Foo: bar -baz: 1 2 3 - -""" - testcase = self - - class MyRequest(http.Request): - def process(self): - testcase.assertEquals(self.getHeader('foo'), 'bar') - testcase.assertEquals(self.getHeader('Foo'), 'bar') - testcase.assertEquals(self.getHeader('bAz'), '1 2 3') - testcase.didRequest = 1 - self.finish() - - self.runRequest(httpRequest, MyRequest) - - def testCookies(self): - """ - Test cookies parsing and reading. - """ - httpRequest = '''\ -GET / HTTP/1.0 -Cookie: rabbit="eat carrot"; ninja=secret; spam="hey 1=1!" - -''' - testcase = self - - class MyRequest(http.Request): - def process(self): - testcase.assertEquals(self.getCookie('rabbit'), '"eat carrot"') - testcase.assertEquals(self.getCookie('ninja'), 'secret') - testcase.assertEquals(self.getCookie('spam'), '"hey 1=1!"') - testcase.didRequest = 1 - self.finish() - - self.runRequest(httpRequest, MyRequest) - - def testGET(self): - httpRequest = '''\ -GET /?key=value&multiple=two+words&multiple=more%20words&empty= HTTP/1.0 - -''' - testcase = self - class MyRequest(http.Request): - def process(self): - testcase.assertEquals(self.method, "GET") - testcase.assertEquals(self.args["key"], ["value"]) - testcase.assertEquals(self.args["empty"], [""]) - testcase.assertEquals(self.args["multiple"], ["two words", "more words"]) - testcase.didRequest = 1 - self.finish() - - self.runRequest(httpRequest, MyRequest) - - - def test_extraQuestionMark(self): - """ - While only a single '?' is allowed in an URL, several other servers - allow several and pass all after the first through as part of the - query arguments. Test that we emulate this behavior. - """ - httpRequest = 'GET /foo?bar=?&baz=quux HTTP/1.0\n\n' - - testcase = self - class MyRequest(http.Request): - def process(self): - testcase.assertEqual(self.method, 'GET') - testcase.assertEqual(self.path, '/foo') - testcase.assertEqual(self.args['bar'], ['?']) - testcase.assertEqual(self.args['baz'], ['quux']) - testcase.didRequest = 1 - self.finish() - - self.runRequest(httpRequest, MyRequest) - - - def testPOST(self): - query = 'key=value&multiple=two+words&multiple=more%20words&empty=' - httpRequest = '''\ -POST / HTTP/1.0 -Content-Length: %d -Content-Type: application/x-www-form-urlencoded - -%s''' % (len(query), query) - - testcase = self - class MyRequest(http.Request): - def process(self): - testcase.assertEquals(self.method, "POST") - testcase.assertEquals(self.args["key"], ["value"]) - testcase.assertEquals(self.args["empty"], [""]) - testcase.assertEquals(self.args["multiple"], ["two words", "more words"]) - testcase.didRequest = 1 - self.finish() - - self.runRequest(httpRequest, MyRequest) - - def testMissingContentDisposition(self): - req = '''\ -POST / HTTP/1.0 -Content-Type: multipart/form-data; boundary=AaB03x -Content-Length: 103 - ---AaB03x -Content-Type: text/plain -Content-Transfer-Encoding: quoted-printable - -abasdfg ---AaB03x-- -''' - self.runRequest(req, http.Request, success=False) - -class QueryArgumentsTestCase(unittest.TestCase): - def testUnquote(self): - try: - from twisted.protocols import _c_urlarg - except ImportError: - raise unittest.SkipTest("_c_urlarg module is not available") - # work exactly like urllib.unquote, including stupid things - # % followed by a non-hexdigit in the middle and in the end - self.failUnlessEqual(urllib.unquote("%notreally%n"), - _c_urlarg.unquote("%notreally%n")) - # % followed by hexdigit, followed by non-hexdigit - self.failUnlessEqual(urllib.unquote("%1quite%1"), - _c_urlarg.unquote("%1quite%1")) - # unquoted text, followed by some quoted chars, ends in a trailing % - self.failUnlessEqual(urllib.unquote("blah%21%40%23blah%"), - _c_urlarg.unquote("blah%21%40%23blah%")) - # Empty string - self.failUnlessEqual(urllib.unquote(""), _c_urlarg.unquote("")) - - def testParseqs(self): - self.failUnlessEqual(cgi.parse_qs("a=b&d=c;+=f"), - http.parse_qs("a=b&d=c;+=f")) - self.failUnlessRaises(ValueError, http.parse_qs, "blah", - strict_parsing = 1) - self.failUnlessEqual(cgi.parse_qs("a=&b=c", keep_blank_values = 1), - http.parse_qs("a=&b=c", keep_blank_values = 1)) - self.failUnlessEqual(cgi.parse_qs("a=&b=c"), - http.parse_qs("a=&b=c")) - - - def test_urlparse(self): - """ - For a given URL, L{http.urlparse} should behave the same as - L{urlparse}, except it should always return C{str}, never C{unicode}. - """ - def urls(): - for scheme in ('http', 'https'): - for host in ('example.com',): - for port in (None, 100): - for path in ('', 'path'): - if port is not None: - host = host + ':' + str(port) - yield urlunsplit((scheme, host, path, '', '')) - - - def assertSameParsing(url, decode): - """ - Verify that C{url} is parsed into the same objects by both - L{http.urlparse} and L{urlparse}. - """ - urlToStandardImplementation = url - if decode: - urlToStandardImplementation = url.decode('ascii') - standardResult = urlparse(urlToStandardImplementation) - scheme, netloc, path, params, query, fragment = http.urlparse(url) - self.assertEqual( - (scheme, netloc, path, params, query, fragment), - standardResult) - self.assertTrue(isinstance(scheme, str)) - self.assertTrue(isinstance(netloc, str)) - self.assertTrue(isinstance(path, str)) - self.assertTrue(isinstance(params, str)) - self.assertTrue(isinstance(query, str)) - self.assertTrue(isinstance(fragment, str)) - - # With caching, unicode then str - clear_cache() - for url in urls(): - assertSameParsing(url, True) - assertSameParsing(url, False) - - # With caching, str then unicode - clear_cache() - for url in urls(): - assertSameParsing(url, False) - assertSameParsing(url, True) - - # Without caching - for url in urls(): - clear_cache() - assertSameParsing(url, True) - clear_cache() - assertSameParsing(url, False) - - - def test_urlparseRejectsUnicode(self): - """ - L{http.urlparse} should reject unicode input early. - """ - self.assertRaises(TypeError, http.urlparse, u'http://example.org/path') - - - def testEscchar(self): - try: - from twisted.protocols import _c_urlarg - except ImportError: - raise unittest.SkipTest("_c_urlarg module is not available") - self.failUnlessEqual("!@#+b", - _c_urlarg.unquote("+21+40+23+b", "+")) - -class ClientDriver(http.HTTPClient): - def handleStatus(self, version, status, message): - self.version = version - self.status = status - self.message = message - -class ClientStatusParsing(unittest.TestCase): - def testBaseline(self): - c = ClientDriver() - c.lineReceived('HTTP/1.0 201 foo') - self.failUnlessEqual(c.version, 'HTTP/1.0') - self.failUnlessEqual(c.status, '201') - self.failUnlessEqual(c.message, 'foo') - - def testNoMessage(self): - c = ClientDriver() - c.lineReceived('HTTP/1.0 201') - self.failUnlessEqual(c.version, 'HTTP/1.0') - self.failUnlessEqual(c.status, '201') - self.failUnlessEqual(c.message, '') - - def testNoMessage_trailingSpace(self): - c = ClientDriver() - c.lineReceived('HTTP/1.0 201 ') - self.failUnlessEqual(c.version, 'HTTP/1.0') - self.failUnlessEqual(c.status, '201') - self.failUnlessEqual(c.message, '') - diff --git a/tools/buildbot/pylibs/twisted/web/test/test_mvc.py b/tools/buildbot/pylibs/twisted/web/test/test_mvc.py deleted file mode 100644 index 312eaf9..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/test_mvc.py +++ /dev/null @@ -1,122 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Test cases for Twisted Model-View-Controller architecture.""" - -import random - -try: - import cPickle as pickle -except ImportError: - import pickle - -from twisted.trial import unittest - -from twisted.web.woven import model, view, controller, interfaces -from twisted.python import components - -# simple pickled string storage to test persistence -persisted_model = "" - -class MyModel(model.Model): - def __init__(self, foo, random=None): - # I hate having to explicitly initialize the super - model.Model.__init__(self) - self.foo=foo - self.random=random - -class MyView(view.View): - def __init__(self, model, *args, **kwargs): - view.View.__init__(self, model, *args, **kwargs) - self.model.addView(self) - # pretend self.foo is what the user now sees on their screen - self.foo = self.model.foo - self.random = self.model.random - self.controller = interfaces.IController(self.model, None) - - def modelChanged(self, changed): - if changed.has_key('foo'): - self.foo = changed['foo'] - if changed.has_key('random'): - self.random = changed['random'] - - def twiddleControl(self, newValue): - """ - The user twiddled a control onscreen, causing this event - """ - self.controller.setFoo(newValue) - - def pushButton(self): - """ - The user hit a button onscreen, causing this event - """ - return self.controller.doRandom() - -# Register MyView as the view for instances of type MyModel -components.registerAdapter(MyView, MyModel, interfaces.IView) - -class MyController(controller.Controller): - def setFoo(self, newValue): - self.model.foo = newValue - self.model.notify({'foo': newValue}) - self.persist() - - def doRandom(self): - rnd = random.choice(range(100)) - self.model.random = rnd - self.model.notify({'random': rnd}) - self.persist() - return rnd - - def persist(self): - """ - Save the model object to persistent storage - """ - global persisted_model - - persisted_model = pickle.dumps(self.model) - -# Register MyController as the controller for instances of type MyModel -components.registerAdapter(MyController, MyModel, interfaces.IController) - -class MVCTestCase(unittest.TestCase): - """Test MVC.""" - def setUp(self): - self.model = MyModel("foo") - - def getView(self): - return interfaces.IView(self.model, None) - - def testViewConstruction(self): - view = self.getView() - self.assert_(isinstance(view, MyView)) - - def testControllerConstruction(self): - view = self.getView() - self.assert_(isinstance(view.controller, MyController)) - - def testModelManipulation(self): - view = self.getView() - view.twiddleControl("bar") - self.assertEquals("bar", self.model.foo) - - def testMoreModelManipulation(self): - view = self.getView() - value = view.pushButton() - self.assertEquals(value, self.model.random) - - def testViewManipulation(self): - """When the model updates the view should too""" - view = self.getView() - view.twiddleControl("bar") - self.assertEquals("bar", view.foo) - - def testMoreViewManipulation(self): - """When the model updates the view should too""" - view = self.getView() - value = view.pushButton() - self.assertEquals(value, view.random) - - -testCases = [MVCTestCase] diff --git a/tools/buildbot/pylibs/twisted/web/test/test_proxy.py b/tools/buildbot/pylibs/twisted/web/test/test_proxy.py deleted file mode 100644 index 4b0194b..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/test_proxy.py +++ /dev/null @@ -1,407 +0,0 @@ -# Copyright (c) 2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test for L{twisted.web.proxy}. -""" - -from twisted.trial.unittest import TestCase -from twisted.test.proto_helpers import StringTransportWithDisconnection -from twisted.internet.error import ConnectionDone - -from twisted.web.resource import Resource -from twisted.web.server import Site -from twisted.web.proxy import ReverseProxyResource, ProxyClientFactory -from twisted.web.proxy import ProxyClient, ProxyRequest, ReverseProxyRequest - - - -class FakeReactor(object): - """ - A fake reactor to be used in tests. - - @ivar connect: a list that keeps track of connection attempts (ie, calls - to C{connectTCP}). - @type connect: C{list} - """ - - def __init__(self): - """ - Initialize the C{connect} list. - """ - self.connect = [] - - - def connectTCP(self, host, port, factory): - """ - Fake L{reactor.connectTCP}, that does nothing but log the call. - """ - self.connect.append([host, port, factory]) - - - -class ReverseProxyResourceTestCase(TestCase): - """ - Tests for L{ReverseProxyResource}. - """ - - def _testRender(self, uri, expectedURI): - """ - Check that a request pointing at C{uri} produce a new proxy connection, - with the path of this request pointing at C{expectedURI}. - """ - root = Resource() - reactor = FakeReactor() - resource = ReverseProxyResource("127.0.0.1", 1234, "/path", reactor) - root.putChild('index', resource) - site = Site(root) - - transport = StringTransportWithDisconnection() - channel = site.buildProtocol(None) - channel.makeConnection(transport) - # Clear the timeout if the tests failed - self.addCleanup(channel.connectionLost, None) - - channel.dataReceived("GET %s HTTP/1.1\r\nAccept: text/html\r\n\r\n" % - (uri,)) - - # Check that one connection has been created, to the good host/port - self.assertEquals(len(reactor.connect), 1) - self.assertEquals(reactor.connect[0][0], "127.0.0.1") - self.assertEquals(reactor.connect[0][1], 1234) - - # Check the factory passed to the connect, and its given path - factory = reactor.connect[0][2] - self.assertIsInstance(factory, ProxyClientFactory) - self.assertEquals(factory.rest, expectedURI) - self.assertEquals(factory.headers["host"], "127.0.0.1:1234") - - - def test_render(self): - """ - Test that L{ReverseProxyResource.render} initiates a connection to the - given server with a L{ProxyClientFactory} as parameter. - """ - return self._testRender("/index", "/path") - - - def test_renderWithQuery(self): - """ - Test that L{ReverseProxyResource.render} passes query parameters to the - created factory. - """ - return self._testRender("/index?foo=bar", "/path?foo=bar") - - - def test_getChild(self): - """ - The L{ReverseProxyResource.getChild} method should return a resource - instance with the same class as the originating resource, forward port - and host values, and update the path value with the value passed. - """ - resource = ReverseProxyResource("127.0.0.1", 1234, "/path") - child = resource.getChild('foo', None) - # The child should keep the same class - self.assertIsInstance(child, ReverseProxyResource) - self.assertEquals(child.path, "/path/foo") - self.assertEquals(child.port, 1234) - self.assertEquals(child.host, "127.0.0.1") - - - def test_getChildWithSpecial(self): - """ - The L{ReverseProxyResource} return by C{getChild} has a path which has - already been quoted. - """ - resource = ReverseProxyResource("127.0.0.1", 1234, "/path") - child = resource.getChild(' /%', None) - self.assertEqual(child.path, "/path/%20%2F%25") - - - -class DummyParent(object): - """ - A dummy parent request that holds a channel and its transport. - - @ivar channel: the request channel. - @ivar transport: the transport of the channel. - """ - - def __init__(self, channel): - """ - Hold a reference to the channel and its transport. - """ - self.channel = channel - self.transport = channel.transport - - - -class DummyChannel(object): - """ - A dummy HTTP channel, that does nothing but holds a transport and saves - connection lost. - - @ivar transport: the transport used by the client. - @ivar lostReason: the reason saved at connection lost. - """ - - def __init__(self, transport): - """ - Hold a reference to the transport. - """ - self.transport = transport - self.lostReason = None - - - def connectionLost(self, reason): - """ - Keep track of the connection lost reason. - """ - self.lostReason = reason - - - -class ProxyClientTestCase(TestCase): - """ - Tests for L{ProxyClient}. - """ - - def _testDataForward(self, data, method="GET", body=""): - """ - Build a fake proxy connection, and send C{data} over it, checking that - it's forwarded to the originating request. - """ - # Connect everything - clientTransport = StringTransportWithDisconnection() - serverTransport = StringTransportWithDisconnection() - channel = DummyChannel(serverTransport) - parent = DummyParent(channel) - serverTransport.protocol = channel - - client = ProxyClient(method, '/foo', 'HTTP/1.0', - {"accept": "text/html"}, body, parent) - clientTransport.protocol = client - client.makeConnection(clientTransport) - - # Check data sent - self.assertEquals(clientTransport.value(), - "%s /foo HTTP/1.0\r\n" - "connection: close\r\n" - "accept: text/html\r\n\r\n%s" % (method, body)) - - # Fake an answer - client.dataReceived(data) - - # Check that the data has been forwarded - self.assertEquals(serverTransport.value(), data) - - clientTransport.loseConnection() - self.assertIsInstance(channel.lostReason, ConnectionDone) - - - def test_forward(self): - """ - When connected to the server, L{ProxyClient} should send the saved - request, with modifications of the headers, and then forward the result - to the parent request. - """ - return self._testDataForward("200 OK\r\nFoo: bar\r\n\r\nSome data\r\n") - - - def test_postData(self): - """ - Try to post content in the request, and check that the proxy client - forward the body of the request. - """ - return self._testDataForward( - "200 OK\r\nFoo: bar\r\n\r\nSome data\r\n", "POST", "Some content") - - - def test_statusWithMessage(self): - """ - If the response contains a status with a message, it should be - forwarded to the parent request with all the information. - """ - return self._testDataForward("404 Not Found\r\n") - - - def test_headersCleanups(self): - """ - The headers given at initialization should be modified: - B{proxy-connection} should be removed if present, and B{connection} - should be added. - """ - client = ProxyClient('GET', '/foo', 'HTTP/1.0', - {"accept": "text/html", "proxy-connection": "foo"}, '', None) - self.assertEquals(client.headers, - {"accept": "text/html", "connection": "close"}) - - - -class ProxyClientFactoryTestCase(TestCase): - """ - Tests for L{ProxyClientFactory}. - """ - - def test_connectionFailed(self): - """ - Check that L{ProxyClientFactory.clientConnectionFailed} produces - a B{501} response to the parent request. - """ - serverTransport = StringTransportWithDisconnection() - channel = DummyChannel(serverTransport) - parent = DummyParent(channel) - serverTransport.protocol = channel - factory = ProxyClientFactory('GET', '/foo', 'HTTP/1.0', - {"accept": "text/html"}, '', parent) - - factory.clientConnectionFailed(None, None) - self.assertEquals(serverTransport.value(), - "HTTP/1.0 501 Gateway error\r\n" - "Content-Type: text/html\r\n\r\n" - "<H1>Could not connect</H1>") - self.assertIsInstance(channel.lostReason, ConnectionDone) - - - def test_buildProtocol(self): - """ - L{ProxyClientFactory.buildProtocol} should produce a L{ProxyClient} - with the same values of attributes (with updates on the headers). - """ - factory = ProxyClientFactory('GET', '/foo', 'HTTP/1.0', - {"accept": "text/html"}, 'Some data', - None) - proto = factory.buildProtocol(None) - self.assertIsInstance(proto, ProxyClient) - self.assertEquals(proto.command, 'GET') - self.assertEquals(proto.rest, '/foo') - self.assertEquals(proto.data, 'Some data') - self.assertEquals(proto.headers, - {"accept": "text/html", "connection": "close"}) - - - -class ProxyRequestTestCase(TestCase): - """ - Tests for L{ProxyRequest}. - """ - - def _testProcess(self, uri, expectedURI, method="GET", data=""): - """ - Build a request pointing at C{uri}, and check that a proxied request - is created, pointing a C{expectedURI}. - """ - transport = StringTransportWithDisconnection() - channel = DummyChannel(transport) - reactor = FakeReactor() - request = ProxyRequest(channel, False, reactor) - request.gotLength(len(data)) - request.handleContentChunk(data) - request.requestReceived(method, 'http://example.com%s' % (uri,), - 'HTTP/1.0') - - self.assertEquals(len(reactor.connect), 1) - self.assertEquals(reactor.connect[0][0], "example.com") - self.assertEquals(reactor.connect[0][1], 80) - - factory = reactor.connect[0][2] - self.assertIsInstance(factory, ProxyClientFactory) - self.assertEquals(factory.command, method) - self.assertEquals(factory.version, 'HTTP/1.0') - self.assertEquals(factory.headers, {'host': 'example.com'}) - self.assertEquals(factory.data, data) - self.assertEquals(factory.rest, expectedURI) - self.assertEquals(factory.father, request) - - - def test_process(self): - """ - L{ProxyRequest.process} should create a connection to the given server, - with a L{ProxyClientFactory} as connection factory, with the correct - parameters: - - forward comment, version and data values - - update headers with the B{host} value - - remove the host from the URL - - pass the request as parent request - """ - return self._testProcess("/foo/bar", "/foo/bar") - - - def test_processWithoutTrailingSlash(self): - """ - If the incoming request doesn't contain a slash, - L{ProxyRequest.process} should add one when instantiating - L{ProxyClientFactory}. - """ - return self._testProcess("", "/") - - - def test_processWithData(self): - """ - L{ProxyRequest.process} should be able to retrieve request body and - to forward it. - """ - return self._testProcess( - "/foo/bar", "/foo/bar", "POST", "Some content") - - - def test_processWithPort(self): - """ - Check that L{ProxyRequest.process} correctly parse port in the incoming - URL, and create a outgoing connection with this port. - """ - transport = StringTransportWithDisconnection() - channel = DummyChannel(transport) - reactor = FakeReactor() - request = ProxyRequest(channel, False, reactor) - request.gotLength(0) - request.requestReceived('GET', 'http://example.com:1234/foo/bar', - 'HTTP/1.0') - - # That should create one connection, with the port parsed from the URL - self.assertEquals(len(reactor.connect), 1) - self.assertEquals(reactor.connect[0][0], "example.com") - self.assertEquals(reactor.connect[0][1], 1234) - - - -class DummyFactory(object): - """ - A simple holder for C{host} and C{port} information. - """ - - def __init__(self, host, port): - self.host = host - self.port = port - - - -class ReverseProxyRequestTestCase(TestCase): - """ - Tests for L{ReverseProxyRequest}. - """ - - def test_process(self): - """ - L{ReverseProxyRequest.process} should create a connection to its - factory host/port, using a L{ProxyClientFactory} instantiated with the - correct parameters, and particulary set the B{host} header to the - factory host. - """ - transport = StringTransportWithDisconnection() - channel = DummyChannel(transport) - reactor = FakeReactor() - request = ReverseProxyRequest(channel, False, reactor) - request.factory = DummyFactory("example.com", 1234) - request.gotLength(0) - request.requestReceived('GET', '/foo/bar', 'HTTP/1.0') - - # Check that one connection has been created, to the good host/port - self.assertEquals(len(reactor.connect), 1) - self.assertEquals(reactor.connect[0][0], "example.com") - self.assertEquals(reactor.connect[0][1], 1234) - - # Check the factory passed to the connect, and its headers - factory = reactor.connect[0][2] - self.assertIsInstance(factory, ProxyClientFactory) - self.assertEquals(factory.headers, {'host': 'example.com'}) diff --git a/tools/buildbot/pylibs/twisted/web/test/test_soap.py b/tools/buildbot/pylibs/twisted/web/test/test_soap.py deleted file mode 100644 index 54e990e..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/test_soap.py +++ /dev/null @@ -1,114 +0,0 @@ -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. -# - -"""Test SOAP support.""" - -try: - import SOAPpy -except ImportError: - SOAPpy = None - class SOAPPublisher: pass -else: - from twisted.web import soap - SOAPPublisher = soap.SOAPPublisher - -from twisted.trial import unittest -from twisted.web import server, error -from twisted.internet import reactor, defer - - -class Test(SOAPPublisher): - - def soap_add(self, a, b): - return a + b - - def soap_kwargs(self, a=1, b=2): - return a + b - soap_kwargs.useKeywords=True - - def soap_triple(self, string, num): - return [string, num, None] - - def soap_struct(self): - return SOAPpy.structType({"a": "c"}) - - def soap_defer(self, x): - return defer.succeed(x) - - def soap_deferFail(self): - return defer.fail(ValueError()) - - def soap_fail(self): - raise RuntimeError - - def soap_deferFault(self): - return defer.fail(ValueError()) - - def soap_complex(self): - return {"a": ["b", "c", 12, []], "D": "foo"} - - def soap_dict(self, map, key): - return map[key] - - -class SOAPTestCase(unittest.TestCase): - - def setUp(self): - self.publisher = Test() - self.p = reactor.listenTCP(0, server.Site(self.publisher), - interface="127.0.0.1") - self.port = self.p.getHost().port - - def tearDown(self): - return self.p.stopListening() - - def proxy(self): - return soap.Proxy("http://127.0.0.1:%d/" % self.port) - - def testResults(self): - inputOutput = [ - ("add", (2, 3), 5), - ("defer", ("a",), "a"), - ("dict", ({"a": 1}, "a"), 1), - ("triple", ("a", 1), ["a", 1, None])] - - dl = [] - for meth, args, outp in inputOutput: - d = self.proxy().callRemote(meth, *args) - d.addCallback(self.assertEquals, outp) - dl.append(d) - - # SOAPpy kinda blows. - d = self.proxy().callRemote('complex') - d.addCallback(lambda result: result._asdict()) - d.addCallback(self.assertEquals, {"a": ["b", "c", 12, []], "D": "foo"}) - dl.append(d) - - # We now return to our regularly scheduled program, already in progress. - return defer.DeferredList(dl, fireOnOneErrback=True) - - def testMethodNotFound(self): - """ - Check that a non existing method return error 500. - """ - d = self.proxy().callRemote('doesntexist') - self.assertFailure(d, error.Error) - def cb(err): - self.assertEquals(int(err.status), 500) - d.addCallback(cb) - return d - - def testLookupFunction(self): - """ - Test lookupFunction method on publisher, to see available remote - methods. - """ - self.assertTrue(self.publisher.lookupFunction("add")) - self.assertTrue(self.publisher.lookupFunction("fail")) - self.assertFalse(self.publisher.lookupFunction("foobar")) - -if not SOAPpy: - SOAPTestCase.skip = "SOAPpy not installed" - diff --git a/tools/buildbot/pylibs/twisted/web/test/test_static.py b/tools/buildbot/pylibs/twisted/web/test/test_static.py deleted file mode 100644 index eb0463a..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/test_static.py +++ /dev/null @@ -1,64 +0,0 @@ -from twisted.trial import unittest -import os -from twisted.web import static - -class FakeRequest: - method = 'GET' - - _headers = None - _setHeaders = None - _written = '' - - def __init__(self): - self._headers = {} - self._setHeaders = {} - - def getHeader(self, k): - if self._headers is None: - return None - return self._headers.get(k) - - def setHeader(self, k, v): - self._setHeaders.setdefault(k, []).append(v) - - def setLastModified(self, x): - pass - def registerProducer(self, producer, x): - producer.resumeProducing() - def unregisterProducer(self): - pass - def finish(self): - pass - - def write(self, data): - self._written = self._written + data - -class Range(unittest.TestCase): - todo = (unittest.FailTest, 'No range support yet.') - - def setUp(self): - self.tmpdir = self.mktemp() - os.mkdir(self.tmpdir) - name = os.path.join(self.tmpdir, 'junk') - f = file(name, 'w') - f.write(8000 * 'x') - f.close() - self.file = static.File(name) - self.request = FakeRequest() - - def testBodyLength(self): - self.request._headers['range'] = 'bytes=0-1999' - self.file.render(self.request) - self.assertEquals(len(self.request._written), 2000) - - def testContentLength(self): - """Content-Length of a request is correct.""" - self.request._headers['range'] = 'bytes=0-1999' - self.file.render(self.request) - self.assertEquals(self.request._setHeaders['content-length'], ['2000']) - - def testContentRange(self): - """Content-Range of a request is correct.""" - self.request._headers['range'] = 'bytes=0-1999' - self.file.render(self.request) - self.assertEquals(self.request._setHeaders.get('content-range'), ['bytes 0-1999/8000']) diff --git a/tools/buildbot/pylibs/twisted/web/test/test_tap.py b/tools/buildbot/pylibs/twisted/web/test/test_tap.py deleted file mode 100644 index 553f9ca..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/test_tap.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) 2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.web.tap}. -""" - -from twisted.trial.unittest import TestCase - -from twisted.web.server import Site -from twisted.web.static import Data -from twisted.web.distrib import ResourcePublisher -from twisted.web.tap import makePersonalServerFactory - -from twisted.spread.pb import PBServerFactory - - -class ServiceTests(TestCase): - """ - Tests for the service creation APIs in L{twisted.web.tap}. - """ - def test_makePersonalServerFactory(self): - """ - L{makePersonalServerFactory} returns a PB server factory which has - as its root object a L{ResourcePublisher}. - """ - # The fact that this pile of objects can actually be used somehow is - # verified by twisted.web.test.test_distrib. - site = Site(Data("foo bar", "text/plain")) - serverFactory = makePersonalServerFactory(site) - self.assertIsInstance(serverFactory, PBServerFactory) - self.assertIsInstance(serverFactory.root, ResourcePublisher) - self.assertIdentical(serverFactory.root.site, site) diff --git a/tools/buildbot/pylibs/twisted/web/test/test_web.py b/tools/buildbot/pylibs/twisted/web/test/test_web.py deleted file mode 100644 index 2bbb390..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/test_web.py +++ /dev/null @@ -1,611 +0,0 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -from twisted.trial import unittest -from cStringIO import StringIO - -from twisted.web import server, resource, util -from twisted.internet import defer, interfaces, error, task -from twisted.web import http -from twisted.python import log -from twisted.internet.address import IPv4Address -from zope.interface import implements - -class DummyRequest: - uri='http://dummy/' - method = 'GET' - - def getHeader(self, h): - return None - - def registerProducer(self, prod,s): - self.go = 1 - while self.go: - prod.resumeProducing() - - def unregisterProducer(self): - self.go = 0 - - def __init__(self, postpath, session=None): - self.sitepath = [] - self.written = [] - self.finished = 0 - self.postpath = postpath - self.prepath = [] - self.session = None - self.protoSession = session or server.Session(0, self) - self.args = {} - self.outgoingHeaders = {} - - def setHeader(self, name, value): - """TODO: make this assert on write() if the header is content-length - """ - self.outgoingHeaders[name.lower()] = value - - def getSession(self): - if self.session: - return self.session - assert not self.written, "Session cannot be requested after data has been written." - self.session = self.protoSession - return self.session - def write(self, data): - self.written.append(data) - def finish(self): - self.finished = self.finished + 1 - def addArg(self, name, value): - self.args[name] = [value] - def setResponseCode(self, code): - assert not self.written, "Response code cannot be set after data has been written: %s." % "@@@@".join(self.written) - def setLastModified(self, when): - assert not self.written, "Last-Modified cannot be set after data has been written: %s." % "@@@@".join(self.written) - def setETag(self, tag): - assert not self.written, "ETag cannot be set after data has been written: %s." % "@@@@".join(self.written) - -class ResourceTestCase(unittest.TestCase): - def testListEntities(self): - r = resource.Resource() - self.failUnlessEqual([], r.listEntities()) - - -class SimpleResource(resource.Resource): - def render(self, request): - if http.CACHED in (request.setLastModified(10), - request.setETag('MatchingTag')): - return '' - else: - return "correct" - -class SiteTest(unittest.TestCase): - def testSimplestSite(self): - sres1 = SimpleResource() - sres2 = SimpleResource() - sres1.putChild("",sres2) - site = server.Site(sres1) - assert site.getResourceFor(DummyRequest([''])) is sres2, "Got the wrong resource." - - - -class SessionTest(unittest.TestCase): - - def setUp(self): - """ - Set up a session using a simulated scheduler. Creates a - C{times} attribute which specifies the return values of the - session's C{_getTime} method. - """ - clock = self.clock = task.Clock() - times = self.times = [] - - class MockSession(server.Session): - """ - A mock L{server.Session} object which fakes out scheduling - with the C{clock} attribute and fakes out the current time - to be the elements of L{SessionTest}'s C{times} attribute. - """ - def loopFactory(self, *a, **kw): - """ - Create a L{task.LoopingCall} which uses - L{SessionTest}'s C{clock} attribute. - """ - call = task.LoopingCall(*a, **kw) - call.clock = clock - return call - - def _getTime(self): - return times.pop(0) - - self.site = server.Site(SimpleResource()) - self.site.sessionFactory = MockSession - - - def test_basicExpiration(self): - """ - Test session expiration: setup a session, and simulate an expiration - time. - """ - self.times.extend([0, server.Session.sessionTimeout + 1]) - session = self.site.makeSession() - hasExpired = [False] - def cbExpire(): - hasExpired[0] = True - session.notifyOnExpire(cbExpire) - self.clock.advance(server.Site.sessionCheckTime - 1) - # Looping call should not have been executed - self.failIf(hasExpired[0]) - - self.clock.advance(1) - - self.failUnless(hasExpired[0]) - - - def test_delayedCallCleanup(self): - """ - Checking to make sure Sessions do not leave extra DelayedCalls. - """ - self.times.extend([0, 100]) - - session = self.site.makeSession() - loop = session.checkExpiredLoop - session.touch() - self.failUnless(loop.running) - - session.expire() - - self.failIf(self.clock.calls) - self.failIf(loop.running) - - - -# Conditional requests: -# If-None-Match, If-Modified-Since - -# make conditional request: -# normal response if condition succeeds -# if condition fails: -# response code -# no body - -def httpBody(whole): - return whole.split('\r\n\r\n', 1)[1] - -def httpHeader(whole, key): - key = key.lower() - headers = whole.split('\r\n\r\n', 1)[0] - for header in headers.split('\r\n'): - if header.lower().startswith(key): - return header.split(':', 1)[1].strip() - return None - -def httpCode(whole): - l1 = whole.split('\r\n', 1)[0] - return int(l1.split()[1]) - -class ConditionalTest(unittest.TestCase): - """web.server's handling of conditional requests for cache validation.""" - - # XXX: test web.distrib. - - def setUp(self): - self.resrc = SimpleResource() - self.resrc.putChild('', self.resrc) - self.site = server.Site(self.resrc) - self.site = server.Site(self.resrc) - self.site.logFile = log.logfile - - # HELLLLLLLLLLP! This harness is Very Ugly. - self.channel = self.site.buildProtocol(None) - self.transport = http.StringTransport() - self.transport.close = lambda *a, **kw: None - self.transport.disconnecting = lambda *a, **kw: 0 - self.transport.getPeer = lambda *a, **kw: "peer" - self.transport.getHost = lambda *a, **kw: "host" - self.channel.makeConnection(self.transport) - for l in ["GET / HTTP/1.1", - "Accept: text/html"]: - self.channel.lineReceived(l) - - def tearDown(self): - self.channel.connectionLost(None) - - def test_modified(self): - """If-Modified-Since cache validator (positive)""" - self.channel.lineReceived("If-Modified-Since: %s" - % http.datetimeToString(1)) - self.channel.lineReceived('') - result = self.transport.getvalue() - self.failUnlessEqual(httpCode(result), http.OK) - self.failUnlessEqual(httpBody(result), "correct") - - def test_unmodified(self): - """If-Modified-Since cache validator (negative)""" - self.channel.lineReceived("If-Modified-Since: %s" - % http.datetimeToString(100)) - self.channel.lineReceived('') - result = self.transport.getvalue() - self.failUnlessEqual(httpCode(result), http.NOT_MODIFIED) - self.failUnlessEqual(httpBody(result), "") - - def test_etagMatchedNot(self): - """If-None-Match ETag cache validator (positive)""" - self.channel.lineReceived("If-None-Match: unmatchedTag") - self.channel.lineReceived('') - result = self.transport.getvalue() - self.failUnlessEqual(httpCode(result), http.OK) - self.failUnlessEqual(httpBody(result), "correct") - - def test_etagMatched(self): - """If-None-Match ETag cache validator (negative)""" - self.channel.lineReceived("If-None-Match: MatchingTag") - self.channel.lineReceived('') - result = self.transport.getvalue() - self.failUnlessEqual(httpHeader(result, "ETag"), "MatchingTag") - self.failUnlessEqual(httpCode(result), http.NOT_MODIFIED) - self.failUnlessEqual(httpBody(result), "") - -from twisted.web import google -class GoogleTestCase(unittest.TestCase): - def testCheckGoogle(self): - raise unittest.SkipTest("no violation of google ToS") - d = google.checkGoogle('site:www.twistedmatrix.com twisted') - d.addCallback(self.assertEquals, 'http://twistedmatrix.com/') - return d - -from twisted.web import static -from twisted.web import script - -class StaticFileTest(unittest.TestCase): - - def testStaticPaths(self): - import os - dp = os.path.join(self.mktemp(),"hello") - ddp = os.path.join(dp, "goodbye") - tp = os.path.abspath(os.path.join(dp,"world.txt")) - tpy = os.path.join(dp,"wyrld.rpy") - os.makedirs(dp) - f = open(tp,"wb") - f.write("hello world") - f = open(tpy, "wb") - f.write(""" -from twisted.web.static import Data -resource = Data('dynamic world','text/plain') -""") - f = static.File(dp) - f.processors = { - '.rpy': script.ResourceScript, - } - - f.indexNames = f.indexNames + ['world.txt'] - self.assertEquals(f.getChild('', DummyRequest([''])).path, - tp) - self.assertEquals(f.getChild('wyrld.rpy', DummyRequest(['wyrld.rpy']) - ).__class__, - static.Data) - f = static.File(dp) - wtextr = DummyRequest(['world.txt']) - wtext = f.getChild('world.txt', wtextr) - self.assertEquals(wtext.path, tp) - wtext.render(wtextr) - self.assertEquals(wtextr.outgoingHeaders.get('content-length'), - str(len('hello world'))) - self.assertNotEquals(f.getChild('', DummyRequest([''])).__class__, - static.File) - - def testIgnoreExt(self): - f = static.File(".") - f.ignoreExt(".foo") - self.assertEquals(f.ignoredExts, [".foo"]) - f = static.File(".") - self.assertEquals(f.ignoredExts, []) - f = static.File(".", ignoredExts=(".bar", ".baz")) - self.assertEquals(f.ignoredExts, [".bar", ".baz"]) - - def testIgnoredExts(self): - import os - dp = os.path.join(self.mktemp(), 'allYourBase') - fp = os.path.join(dp, 'AreBelong.ToUs') - os.makedirs(dp) - open(fp, 'wb').write("Take off every 'Zig'!!") - f = static.File(dp) - f.ignoreExt('.ToUs') - dreq = DummyRequest(['']) - child_without_ext = f.getChild('AreBelong', dreq) - self.assertNotEquals(child_without_ext, f.childNotFound) - -class DummyChannel: - class TCP: - port = 80 - def getPeer(self): - return IPv4Address("TCP", 'client.example.com', 12344) - def getHost(self): - return IPv4Address("TCP", 'example.com', self.port) - class SSL(TCP): - implements(interfaces.ISSLTransport) - transport = TCP() - site = server.Site(resource.Resource()) - -class TestRequest(unittest.TestCase): - - def testChildLink(self): - request = server.Request(DummyChannel(), 1) - request.gotLength(0) - request.requestReceived('GET', '/foo/bar', 'HTTP/1.0') - self.assertEqual(request.childLink('baz'), 'bar/baz') - request = server.Request(DummyChannel(), 1) - request.gotLength(0) - request.requestReceived('GET', '/foo/bar/', 'HTTP/1.0') - self.assertEqual(request.childLink('baz'), 'baz') - - def testPrePathURLSimple(self): - request = server.Request(DummyChannel(), 1) - request.gotLength(0) - request.requestReceived('GET', '/foo/bar', 'HTTP/1.0') - request.setHost('example.com', 80) - self.assertEqual(request.prePathURL(), 'http://example.com/foo/bar') - - def testPrePathURLNonDefault(self): - d = DummyChannel() - d.transport = DummyChannel.TCP() - d.transport.port = 81 - request = server.Request(d, 1) - request.setHost('example.com', 81) - request.gotLength(0) - request.requestReceived('GET', '/foo/bar', 'HTTP/1.0') - self.assertEqual(request.prePathURL(), 'http://example.com:81/foo/bar') - - def testPrePathURLSSLPort(self): - d = DummyChannel() - d.transport = DummyChannel.TCP() - d.transport.port = 443 - request = server.Request(d, 1) - request.setHost('example.com', 443) - request.gotLength(0) - request.requestReceived('GET', '/foo/bar', 'HTTP/1.0') - self.assertEqual(request.prePathURL(), 'http://example.com:443/foo/bar') - - def testPrePathURLSSLPortAndSSL(self): - d = DummyChannel() - d.transport = DummyChannel.SSL() - d.transport.port = 443 - request = server.Request(d, 1) - request.setHost('example.com', 443) - request.gotLength(0) - request.requestReceived('GET', '/foo/bar', 'HTTP/1.0') - self.assertEqual(request.prePathURL(), 'https://example.com/foo/bar') - - def testPrePathURLHTTPPortAndSSL(self): - d = DummyChannel() - d.transport = DummyChannel.SSL() - d.transport.port = 80 - request = server.Request(d, 1) - request.setHost('example.com', 80) - request.gotLength(0) - request.requestReceived('GET', '/foo/bar', 'HTTP/1.0') - self.assertEqual(request.prePathURL(), 'https://example.com:80/foo/bar') - - def testPrePathURLSSLNonDefault(self): - d = DummyChannel() - d.transport = DummyChannel.SSL() - d.transport.port = 81 - request = server.Request(d, 1) - request.setHost('example.com', 81) - request.gotLength(0) - request.requestReceived('GET', '/foo/bar', 'HTTP/1.0') - self.assertEqual(request.prePathURL(), 'https://example.com:81/foo/bar') - - def testPrePathURLSetSSLHost(self): - d = DummyChannel() - d.transport = DummyChannel.TCP() - d.transport.port = 81 - request = server.Request(d, 1) - request.setHost('foo.com', 81, 1) - request.gotLength(0) - request.requestReceived('GET', '/foo/bar', 'HTTP/1.0') - self.assertEqual(request.prePathURL(), 'https://foo.com:81/foo/bar') - - - def test_prePathURLQuoting(self): - """ - L{Request.prePathURL} quotes special characters in the URL segments to - preserve the original meaning. - """ - d = DummyChannel() - request = server.Request(d, 1) - request.setHost('example.com', 80) - request.gotLength(0) - request.requestReceived('GET', '/foo%2Fbar', 'HTTP/1.0') - self.assertEqual(request.prePathURL(), 'http://example.com/foo%2Fbar') - - - def testNotifyFinishConnectionLost(self): - d = DummyChannel() - d.transport = DummyChannel.TCP() - request = server.Request(d, 1) - finished = request.notifyFinish() - request.connectionLost(error.ConnectionDone("Connection done")) - return self.assertFailure(finished, error.ConnectionDone) - - -class RootResource(resource.Resource): - isLeaf=0 - def getChildWithDefault(self, name, request): - request.rememberRootURL() - return resource.Resource.getChildWithDefault(self, name, request) - def render(self, request): - return '' - -class RememberURLTest(unittest.TestCase): - def createServer(self, r): - chan = DummyChannel() - chan.transport = DummyChannel.TCP() - chan.site = server.Site(r) - return chan - - def testSimple(self): - r = resource.Resource() - r.isLeaf=0 - rr = RootResource() - r.putChild('foo', rr) - rr.putChild('', rr) - rr.putChild('bar', resource.Resource()) - chan = self.createServer(r) - for url in ['/foo/', '/foo/bar', '/foo/bar/baz', '/foo/bar/']: - request = server.Request(chan, 1) - request.setHost('example.com', 81) - request.gotLength(0) - request.requestReceived('GET', url, 'HTTP/1.0') - self.assertEqual(request.getRootURL(), "http://example.com/foo") - - def testRoot(self): - rr = RootResource() - rr.putChild('', rr) - rr.putChild('bar', resource.Resource()) - chan = self.createServer(rr) - for url in ['/', '/bar', '/bar/baz', '/bar/']: - request = server.Request(chan, 1) - request.setHost('example.com', 81) - request.gotLength(0) - request.requestReceived('GET', url, 'HTTP/1.0') - self.assertEqual(request.getRootURL(), "http://example.com/") - - -class NewRenderResource(resource.Resource): - def render_GET(self, request): - return "hi hi" - - def render_HEH(self, request): - return "ho ho" - - -class NewRenderTestCase(unittest.TestCase): - def _getReq(self): - d = DummyChannel() - d.site.resource.putChild('newrender', NewRenderResource()) - d.transport = DummyChannel.TCP() - d.transport.port = 81 - request = server.Request(d, 1) - request.setHost('example.com', 81) - request.gotLength(0) - return request - - def testGoodMethods(self): - req = self._getReq() - req.requestReceived('GET', '/newrender', 'HTTP/1.0') - self.assertEquals(req.transport.getvalue().splitlines()[-1], 'hi hi') - - req = self._getReq() - req.requestReceived('HEH', '/newrender', 'HTTP/1.0') - self.assertEquals(req.transport.getvalue().splitlines()[-1], 'ho ho') - - def testBadMethods(self): - req = self._getReq() - req.requestReceived('CONNECT', '/newrender', 'HTTP/1.0') - self.assertEquals(req.code, 501) - - req = self._getReq() - req.requestReceived('hlalauguG', '/newrender', 'HTTP/1.0') - self.assertEquals(req.code, 501) - - def testImplicitHead(self): - req = self._getReq() - req.requestReceived('HEAD', '/newrender', 'HTTP/1.0') - self.assertEquals(req.code, 200) - self.assertEquals(-1, req.transport.getvalue().find('hi hi')) - - -class SDResource(resource.Resource): - def __init__(self,default): self.default=default - def getChildWithDefault(self,name,request): - d=defer.succeed(self.default) - return util.DeferredResource(d).getChildWithDefault(name, request) - -class SDTest(unittest.TestCase): - - def testDeferredResource(self): - r = resource.Resource() - r.isLeaf = 1 - s = SDResource(r) - d = DummyRequest(['foo', 'bar', 'baz']) - resource.getChildForRequest(s, d) - self.assertEqual(d.postpath, ['bar', 'baz']) - -class DummyRequestForLogTest(DummyRequest): - uri='/dummy' # parent class uri has "http://", which doesn't really happen - code = 123 - client = '1.2.3.4' - clientproto = 'HTTP/1.0' - sentLength = None - - def __init__(self, *a, **kw): - DummyRequest.__init__(self, *a, **kw) - self.headers = {} - - def getHeader(self, h): - return self.headers.get(h.lower(), None) - - def getClientIP(self): - return self.client - -class TestLogEscaping(unittest.TestCase): - def setUp(self): - self.site = http.HTTPFactory() - self.site.logFile = StringIO() - self.request = DummyRequestForLogTest(self.site, False) - - def testSimple(self): - http._logDateTime = "[%02d/%3s/%4d:%02d:%02d:%02d +0000]" % ( - 25, 'Oct', 2004, 12, 31, 59) - self.site.log(self.request) - self.site.logFile.seek(0) - self.assertEqual( - self.site.logFile.read(), - '1.2.3.4 - - [25/Oct/2004:12:31:59 +0000] "GET /dummy HTTP/1.0" 123 - "-" "-"\n') - - def testMethodQuote(self): - http._logDateTime = "[%02d/%3s/%4d:%02d:%02d:%02d +0000]" % ( - 25, 'Oct', 2004, 12, 31, 59) - self.request.method = 'G"T' - self.site.log(self.request) - self.site.logFile.seek(0) - self.assertEqual( - self.site.logFile.read(), - '1.2.3.4 - - [25/Oct/2004:12:31:59 +0000] "G\\"T /dummy HTTP/1.0" 123 - "-" "-"\n') - - def testRequestQuote(self): - http._logDateTime = "[%02d/%3s/%4d:%02d:%02d:%02d +0000]" % ( - 25, 'Oct', 2004, 12, 31, 59) - self.request.uri='/dummy"withquote' - self.site.log(self.request) - self.site.logFile.seek(0) - self.assertEqual( - self.site.logFile.read(), - '1.2.3.4 - - [25/Oct/2004:12:31:59 +0000] "GET /dummy\\"withquote HTTP/1.0" 123 - "-" "-"\n') - - def testProtoQuote(self): - http._logDateTime = "[%02d/%3s/%4d:%02d:%02d:%02d +0000]" % ( - 25, 'Oct', 2004, 12, 31, 59) - self.request.clientproto='HT"P/1.0' - self.site.log(self.request) - self.site.logFile.seek(0) - self.assertEqual( - self.site.logFile.read(), - '1.2.3.4 - - [25/Oct/2004:12:31:59 +0000] "GET /dummy HT\\"P/1.0" 123 - "-" "-"\n') - - def testRefererQuote(self): - http._logDateTime = "[%02d/%3s/%4d:%02d:%02d:%02d +0000]" % ( - 25, 'Oct', 2004, 12, 31, 59) - self.request.headers['referer'] = 'http://malicious" ".website.invalid' - self.site.log(self.request) - self.site.logFile.seek(0) - self.assertEqual( - self.site.logFile.read(), - '1.2.3.4 - - [25/Oct/2004:12:31:59 +0000] "GET /dummy HTTP/1.0" 123 - "http://malicious\\" \\".website.invalid" "-"\n') - - def testUserAgentQuote(self): - http._logDateTime = "[%02d/%3s/%4d:%02d:%02d:%02d +0000]" % ( - 25, 'Oct', 2004, 12, 31, 59) - self.request.headers['user-agent'] = 'Malicious Web" Evil' - self.site.log(self.request) - self.site.logFile.seek(0) - self.assertEqual( - self.site.logFile.read(), - '1.2.3.4 - - [25/Oct/2004:12:31:59 +0000] "GET /dummy HTTP/1.0" 123 - "-" "Malicious Web\\" Evil"\n') diff --git a/tools/buildbot/pylibs/twisted/web/test/test_webclient.py b/tools/buildbot/pylibs/twisted/web/test/test_webclient.py deleted file mode 100644 index a1bab78..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/test_webclient.py +++ /dev/null @@ -1,475 +0,0 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for L{twisted.web.client}. -""" - -import os - -from urlparse import urlparse - -from twisted.trial import unittest -from twisted.web import server, static, client, error, util, resource -from twisted.internet import reactor, defer, interfaces -from twisted.python.filepath import FilePath - -try: - from twisted.internet import ssl -except: - ssl = None - -serverCallID = None - -class LongTimeTakingResource(resource.Resource): - def render(self, request): - global serverCallID - serverCallID = reactor.callLater(1, self.writeIt, request) - return server.NOT_DONE_YET - - def writeIt(self, request): - request.write("hello!!!") - request.finish() - -class CookieMirrorResource(resource.Resource): - def render(self, request): - l = [] - for k,v in request.received_cookies.items(): - l.append((k, v)) - l.sort() - return repr(l) - -class RawCookieMirrorResource(resource.Resource): - def render(self, request): - return repr(request.getHeader('cookie')) - -class ErrorResource(resource.Resource): - - def render(self, request): - request.setResponseCode(401) - if request.args.get("showlength"): - request.setHeader("content-length", "0") - return "" - -class NoLengthResource(resource.Resource): - - def render(self, request): - return "nolength" - -class HostHeaderResource(resource.Resource): - - def render(self, request): - return request.received_headers["host"] - -class PayloadResource(resource.Resource): - - def render(self, request): - data = request.content.read() - if len(data) != 100 or int(request.received_headers["content-length"]) != 100: - return "ERROR" - return data - -class BrokenDownloadResource(resource.Resource): - - def render(self, request): - # only sends 3 bytes even though it claims to send 5 - request.setHeader("content-length", "5") - request.write('abc') - return '' - - - -class ParseUrlTestCase(unittest.TestCase): - """ - Test URL parsing facility and defaults values. - """ - - def testParse(self): - scheme, host, port, path = client._parse("http://127.0.0.1/") - self.assertEquals(path, "/") - self.assertEquals(port, 80) - scheme, host, port, path = client._parse("https://127.0.0.1/") - self.assertEquals(path, "/") - self.assertEquals(port, 443) - scheme, host, port, path = client._parse("http://spam:12345/") - self.assertEquals(port, 12345) - scheme, host, port, path = client._parse("http://foo ") - self.assertEquals(host, "foo") - self.assertEquals(path, "/") - scheme, host, port, path = client._parse("http://egg:7890") - self.assertEquals(port, 7890) - self.assertEquals(host, "egg") - self.assertEquals(path, "/") - - - def test_externalUnicodeInterference(self): - """ - L{client._parse} should return C{str} for the scheme, host, and path - elements of its return tuple, even when passed an URL which has - previously been passed to L{urlparse} as a C{unicode} string. - """ - badInput = u'http://example.com/path' - goodInput = badInput.encode('ascii') - urlparse(badInput) - scheme, host, port, path = client._parse(goodInput) - self.assertTrue(isinstance(scheme, str)) - self.assertTrue(isinstance(host, str)) - self.assertTrue(isinstance(path, str)) - - - -class WebClientTestCase(unittest.TestCase): - def _listen(self, site): - return reactor.listenTCP(0, site, interface="127.0.0.1") - - def setUp(self): - name = self.mktemp() - os.mkdir(name) - FilePath(name).child("file").setContent("0123456789") - r = static.File(name) - r.putChild("redirect", util.Redirect("/file")) - r.putChild("wait", LongTimeTakingResource()) - r.putChild("error", ErrorResource()) - r.putChild("nolength", NoLengthResource()) - r.putChild("host", HostHeaderResource()) - r.putChild("payload", PayloadResource()) - r.putChild("broken", BrokenDownloadResource()) - site = server.Site(r, timeout=None) - self.port = self._listen(site) - self.portno = self.port.getHost().port - - def tearDown(self): - if serverCallID and serverCallID.active(): - serverCallID.cancel() - return self.port.stopListening() - - def getURL(self, path): - return "http://127.0.0.1:%d/%s" % (self.portno, path) - - def testPayload(self): - s = "0123456789" * 10 - return client.getPage(self.getURL("payload"), postdata=s - ).addCallback(self.assertEquals, s - ) - - def testBrokenDownload(self): - # test what happens when download gets disconnected in the middle - d = client.getPage(self.getURL("broken")) - d = self.assertFailure(d, client.PartialDownloadError) - d.addCallback(lambda exc: self.assertEquals(exc.response, "abc")) - return d - - def testHostHeader(self): - # if we pass Host header explicitly, it should be used, otherwise - # it should extract from url - return defer.gatherResults([ - client.getPage(self.getURL("host")).addCallback(self.assertEquals, "127.0.0.1"), - client.getPage(self.getURL("host"), headers={"Host": "www.example.com"}).addCallback(self.assertEquals, "www.example.com")]) - - - def test_getPage(self): - """ - L{client.getPage} returns a L{Deferred} which is called back with - the body of the response if the default method B{GET} is used. - """ - d = client.getPage(self.getURL("file")) - d.addCallback(self.assertEquals, "0123456789") - return d - - - def test_getPageHead(self): - """ - L{client.getPage} returns a L{Deferred} which is called back with - the empty string if the method is C{HEAD} and there is a successful - response code. - """ - def getPage(method): - return client.getPage(self.getURL("file"), method=method) - return defer.gatherResults([ - getPage("head").addCallback(self.assertEqual, ""), - getPage("HEAD").addCallback(self.assertEqual, "")]) - - - def testTimeoutNotTriggering(self): - # Test that when the timeout doesn't trigger, things work as expected. - d = client.getPage(self.getURL("wait"), timeout=100) - d.addCallback(self.assertEquals, "hello!!!") - return d - - def testTimeoutTriggering(self): - # Test that when the timeout does trigger, we get a defer.TimeoutError. - return self.assertFailure( - client.getPage(self.getURL("wait"), timeout=0.5), - defer.TimeoutError) - - def testDownloadPage(self): - downloads = [] - downloadData = [("file", self.mktemp(), "0123456789"), - ("nolength", self.mktemp(), "nolength")] - - for (url, name, data) in downloadData: - d = client.downloadPage(self.getURL(url), name) - d.addCallback(self._cbDownloadPageTest, data, name) - downloads.append(d) - return defer.gatherResults(downloads) - - def _cbDownloadPageTest(self, ignored, data, name): - bytes = file(name, "rb").read() - self.assertEquals(bytes, data) - - def testDownloadPageError1(self): - class errorfile: - def write(self, data): - raise IOError, "badness happened during write" - def close(self): - pass - ef = errorfile() - return self.assertFailure( - client.downloadPage(self.getURL("file"), ef), - IOError) - - def testDownloadPageError2(self): - class errorfile: - def write(self, data): - pass - def close(self): - raise IOError, "badness happened during close" - ef = errorfile() - return self.assertFailure( - client.downloadPage(self.getURL("file"), ef), - IOError) - - def testDownloadPageError3(self): - # make sure failures in open() are caught too. This is tricky. - # Might only work on posix. - tmpfile = open("unwritable", "wb") - tmpfile.close() - os.chmod("unwritable", 0) # make it unwritable (to us) - d = self.assertFailure( - client.downloadPage(self.getURL("file"), "unwritable"), - IOError) - d.addBoth(self._cleanupDownloadPageError3) - return d - - def _cleanupDownloadPageError3(self, ignored): - os.chmod("unwritable", 0700) - os.unlink("unwritable") - return ignored - - def _downloadTest(self, method): - dl = [] - for (url, code) in [("nosuchfile", "404"), ("error", "401"), - ("error?showlength=1", "401")]: - d = method(url) - d = self.assertFailure(d, error.Error) - d.addCallback(lambda exc, code=code: self.assertEquals(exc.args[0], code)) - dl.append(d) - return defer.DeferredList(dl, fireOnOneErrback=True) - - def testServerError(self): - return self._downloadTest(lambda url: client.getPage(self.getURL(url))) - - def testDownloadServerError(self): - return self._downloadTest(lambda url: client.downloadPage(self.getURL(url), url.split('?')[0])) - - def testFactoryInfo(self): - url = self.getURL('file') - scheme, host, port, path = client._parse(url) - factory = client.HTTPClientFactory(url) - reactor.connectTCP(host, port, factory) - return factory.deferred.addCallback(self._cbFactoryInfo, factory) - - def _cbFactoryInfo(self, ignoredResult, factory): - self.assertEquals(factory.status, '200') - self.assert_(factory.version.startswith('HTTP/')) - self.assertEquals(factory.message, 'OK') - self.assertEquals(factory.response_headers['content-length'][0], '10') - - - def testRedirect(self): - return client.getPage(self.getURL("redirect")).addCallback(self._cbRedirect) - - def _cbRedirect(self, pageData): - self.assertEquals(pageData, "0123456789") - d = self.assertFailure( - client.getPage(self.getURL("redirect"), followRedirect=0), - error.PageRedirect) - d.addCallback(self._cbCheckLocation) - return d - - def _cbCheckLocation(self, exc): - self.assertEquals(exc.location, "/file") - - def testPartial(self): - name = self.mktemp() - f = open(name, "wb") - f.write("abcd") - f.close() - - downloads = [] - partialDownload = [(True, "abcd456789"), - (True, "abcd456789"), - (False, "0123456789")] - - d = defer.succeed(None) - for (partial, expectedData) in partialDownload: - d.addCallback(self._cbRunPartial, name, partial) - d.addCallback(self._cbPartialTest, expectedData, name) - - return d - - testPartial.skip = "Cannot test until webserver can serve partial data properly" - - def _cbRunPartial(self, ignored, name, partial): - return client.downloadPage(self.getURL("file"), name, supportPartial=partial) - - def _cbPartialTest(self, ignored, expectedData, filename): - bytes = file(filename, "rb").read() - self.assertEquals(bytes, expectedData) - -class WebClientSSLTestCase(WebClientTestCase): - def _listen(self, site): - from twisted import test - return reactor.listenSSL(0, site, - contextFactory=ssl.DefaultOpenSSLContextFactory( - FilePath(test.__file__).sibling('server.pem').path, - FilePath(test.__file__).sibling('server.pem').path, - ), - interface="127.0.0.1") - - def getURL(self, path): - return "https://127.0.0.1:%d/%s" % (self.portno, path) - - def testFactoryInfo(self): - url = self.getURL('file') - scheme, host, port, path = client._parse(url) - factory = client.HTTPClientFactory(url) - reactor.connectSSL(host, port, factory, ssl.ClientContextFactory()) - # The base class defines _cbFactoryInfo correctly for this - return factory.deferred.addCallback(self._cbFactoryInfo, factory) - -class WebClientRedirectBetweenSSLandPlainText(unittest.TestCase): - def getHTTPS(self, path): - return "https://127.0.0.1:%d/%s" % (self.tlsPortno, path) - - def getHTTP(self, path): - return "http://127.0.0.1:%d/%s" % (self.plainPortno, path) - - def setUp(self): - plainRoot = static.Data('not me', 'text/plain') - tlsRoot = static.Data('me neither', 'text/plain') - - plainSite = server.Site(plainRoot, timeout=None) - tlsSite = server.Site(tlsRoot, timeout=None) - - from twisted import test - self.tlsPort = reactor.listenSSL(0, tlsSite, - contextFactory=ssl.DefaultOpenSSLContextFactory( - FilePath(test.__file__).sibling('server.pem').path, - FilePath(test.__file__).sibling('server.pem').path, - ), - interface="127.0.0.1") - self.plainPort = reactor.listenTCP(0, plainSite, interface="127.0.0.1") - - self.plainPortno = self.plainPort.getHost().port - self.tlsPortno = self.tlsPort.getHost().port - - plainRoot.putChild('one', util.Redirect(self.getHTTPS('two'))) - tlsRoot.putChild('two', util.Redirect(self.getHTTP('three'))) - plainRoot.putChild('three', util.Redirect(self.getHTTPS('four'))) - tlsRoot.putChild('four', static.Data('FOUND IT!', 'text/plain')) - - def tearDown(self): - ds = map(defer.maybeDeferred, - [self.plainPort.stopListening, self.tlsPort.stopListening]) - return defer.gatherResults(ds) - - def testHoppingAround(self): - return client.getPage(self.getHTTP("one") - ).addCallback(self.assertEquals, "FOUND IT!" - ) - -class FakeTransport: - disconnecting = False - def __init__(self): - self.data = [] - def write(self, stuff): - self.data.append(stuff) - -class CookieTestCase(unittest.TestCase): - def _listen(self, site): - return reactor.listenTCP(0, site, interface="127.0.0.1") - - def setUp(self): - root = static.Data('El toro!', 'text/plain') - root.putChild("cookiemirror", CookieMirrorResource()) - root.putChild("rawcookiemirror", RawCookieMirrorResource()) - site = server.Site(root, timeout=None) - self.port = self._listen(site) - self.portno = self.port.getHost().port - - def tearDown(self): - return self.port.stopListening() - - def getHTTP(self, path): - return "http://127.0.0.1:%d/%s" % (self.portno, path) - - def testNoCookies(self): - return client.getPage(self.getHTTP("cookiemirror") - ).addCallback(self.assertEquals, "[]" - ) - - def testSomeCookies(self): - cookies = {'foo': 'bar', 'baz': 'quux'} - return client.getPage(self.getHTTP("cookiemirror"), cookies=cookies - ).addCallback(self.assertEquals, "[('baz', 'quux'), ('foo', 'bar')]" - ) - - def testRawNoCookies(self): - return client.getPage(self.getHTTP("rawcookiemirror") - ).addCallback(self.assertEquals, "None" - ) - - def testRawSomeCookies(self): - cookies = {'foo': 'bar', 'baz': 'quux'} - return client.getPage(self.getHTTP("rawcookiemirror"), cookies=cookies - ).addCallback(self.assertEquals, "'foo=bar; baz=quux'" - ) - - def testCookieHeaderParsing(self): - d = defer.Deferred() - factory = client.HTTPClientFactory('http://foo.example.com/') - proto = factory.buildProtocol('127.42.42.42') - proto.transport = FakeTransport() - proto.connectionMade() - for line in [ - '200 Ok', - 'Squash: yes', - 'Hands: stolen', - 'Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT', - 'Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/', - 'Set-Cookie: SHIPPING=FEDEX; path=/foo', - '', - 'body', - 'more body', - ]: - proto.dataReceived(line + '\r\n') - self.assertEquals(proto.transport.data, - ['GET / HTTP/1.0\r\n', - 'Host: foo.example.com\r\n', - 'User-Agent: Twisted PageGetter\r\n', - '\r\n']) - self.assertEquals(factory.cookies, - { - 'CUSTOMER': 'WILE_E_COYOTE', - 'PART_NUMBER': 'ROCKET_LAUNCHER_0001', - 'SHIPPING': 'FEDEX', - }) - -if ssl is None or not hasattr(ssl, 'DefaultOpenSSLContextFactory'): - for case in [WebClientSSLTestCase, WebClientRedirectBetweenSSLandPlainText]: - case.skip = "OpenSSL not present" - -if not interfaces.IReactorSSL(reactor, None): - for case in [WebClientSSLTestCase, WebClientRedirectBetweenSSLandPlainText]: - case.skip = "Reactor doesn't support SSL" diff --git a/tools/buildbot/pylibs/twisted/web/test/test_woven.py b/tools/buildbot/pylibs/twisted/web/test/test_woven.py deleted file mode 100644 index 29dd17f..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/test_woven.py +++ /dev/null @@ -1,570 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.trial import unittest -from twisted.web import server, resource, microdom, domhelpers -from twisted.web import http -from twisted.web.test import test_web -from twisted.internet import reactor, defer, address - -from twisted.web.woven import template, model, view, controller, widgets, input, page, guard - -outputNum = 0 - -# Reusable test harness - -class WovenTC(unittest.TestCase): - modelFactory = lambda self: None - resourceFactory = None - def setUp(self): - self.m = self.modelFactory() - self.t = self.resourceFactory(self.m) - self.r = test_web.DummyRequest(['']) - self.r.prepath = [''] - self.prerender() - self.t.render(self.r) - - self.channel = "a fake channel" - self.output = ''.join(self.r.written) - assert self.output, "No output was generated by the test." - global outputNum - open("wovenTestOutput%s.html" % (outputNum + 1), 'w').write(self.output) - outputNum += 1 - self.d = microdom.parseString(self.output) - - def prerender(self): - pass - -# Test 1 -# Test that replacing nodes with a string works properly - - -class SimpleTemplate(template.DOMTemplate): - template = """<http> - <head> - <title id="title"><span view="getTitle">Hello</span></title> - </head> - <body> - <h3 id="hello"><span view="getHello">Hi</span></h3> - </body> -</http>""" - - def factory_getTitle(self, request, node): - return "Title" - - def factory_getHello(self, request, node): - return "Hello" - - -class DOMTemplateTest(WovenTC): - resourceFactory = SimpleTemplate - def testSimpleRender(self): - titleNode = self.d.getElementById("title") - helloNode = self.d.getElementById("hello") - - self.assert_(domhelpers.gatherTextNodes(titleNode) == 'Title') - self.assert_(domhelpers.gatherTextNodes(helloNode) == 'Hello') - - -# Test 2 -# Test just like the first, but with Text widgets - -class TemplateWithWidgets(SimpleTemplate): - def wcfactory_getTitle(self, request, node): - return widgets.Text("Title") - - def wcfactory_getHello(self, request, node): - return widgets.Text("Hello") - - -class TWWTest(DOMTemplateTest): - resourceFactory = TemplateWithWidgets - - -# Test 3 -# Test a fancier widget, and controllers handling submitted input - - -class MDemo(model.AttributeModel): - foo = "Hello world" - color = 'blue' - - -class FancyBox(widgets.Widget): - def setUp(self, request, node, data): - self['style'] = 'margin: 1em; padding: 1em; background-color: %s' % data - - -class VDemo(view.View): - template = """<html> - -<div id="box" model="color" view="FancyBox"></div> - -<form action=""> -Type a color and hit submit: -<input type="text" controller="change" model="color" name="color" /> -<input type="submit" /> -</form> - -</html> -""" - def wvfactory_FancyBox(self, request, node, model): - return FancyBox(model) - - def renderFailure(self, failure, request): - return failure - - -class ChangeColor(input.Anything): - def commit(self, request, node, data): - session = request.getSession() - session.color = data - self.model.setData(request, data) - self.model.notify({'request': request}) - - -class CDemo(controller.Controller): - def setUp(self, request): - session = request.getSession() - self.model.color = getattr(session, 'color', self.model.color) - - def wcfactory_change(self, request, node, model): - return ChangeColor(model) - - -view.registerViewForModel(VDemo, MDemo) -controller.registerControllerForModel(CDemo, MDemo) - - -class ControllerTest(WovenTC): - modelFactory = MDemo - resourceFactory = CDemo - - def prerender(self): - self.r.addArg('color', 'red') - - def testControllerOutput(self): - boxNode = self.d.getElementById("box") - assert boxNode, "Test %s failed" % outputNum - style = boxNode.getAttribute("style") - styles = style.split(";") - sDict = {} - for item in styles: - key, value = item.split(":") - key = key.strip() - value = value.strip() - sDict[key] = value - -# print sDict - assert sDict['background-color'] == 'red' - - -# Test 4 -# Test a list, a list widget, and Deferred data handling - -identityList = ['asdf', 'foo', 'fredf', 'bob'] - -class MIdentityList(model.AttributeModel): - def __init__(self): - model.Model.__init__(self) - self.identityList = defer.Deferred() - self.identityList.callback(identityList) - - -class VIdentityList(view.View): - template = """<html> - <ul id="list" view="identityList" model="identityList"> - <li listItemOf="identityList" view="text"> - Stuff. - </li> - </ul> -</html>""" - - def wvfactory_identityList(self, request, node, model): - return widgets.List(model) - - def wvfactory_text(self, request, node, model): - return widgets.Text(model) - - def renderFailure(self, failure, request): - return failure - - -class CIdentityList(controller.Controller): - pass - - -view.registerViewForModel(VIdentityList, MIdentityList) -controller.registerControllerForModel(CIdentityList, MIdentityList) - - -class ListDeferredTest(WovenTC): - modelFactory = MIdentityList - resourceFactory = CIdentityList - - def testOutput(self): - listNode = self.d.getElementById("list") - assert listNode, "Test %s failed; there was no element with the id 'list' in the output" % outputNum - liNodes = domhelpers.getElementsByTagName(listNode, 'li') - assert len(liNodes) == len(identityList), "Test %s failed; the number of 'li' nodes did not match the list size" % outputNum - - -# Test 5 -# Test nested lists - -class LLModel(model.AttributeModel): - data = [['foo', 'bar', 'baz'], - ['gum', 'shoe'], - ['ggg', 'hhh', 'iii'] - ] - - -class LLView(view.View): - template = """<html> - <ul id="first" view="List" model="data"> - <li pattern="listItem" view="DefaultWidget"> - <ol view="List"> - <li pattern="listItem" view="Text" /> - </ol> - </li> - </ul> -</html>""" - - def wvfactory_List(self, request, node, model): - return widgets.List(model) - - -class NestedListTest(WovenTC): - modelFactory = LLModel - resourceFactory = LLView - - def testOutput(self): - listNode = self.d.getElementById("first") - assert listNode, "Test %s failed" % outputNum - liNodes = filter(lambda x: hasattr(x, 'tagName') and x.tagName == 'li', listNode.childNodes) -# print len(liNodes), len(self.m.data), liNodes, self.m.data - assert len(liNodes) == len(self.m.data), "Test %s failed" % outputNum - for i in range(len(liNodes)): - sublistNode = domhelpers.getElementsByTagName(liNodes[i], 'ol')[0] - subLiNodes = domhelpers.getElementsByTagName(sublistNode, 'li') - assert len(self.m.data[i]) == len(subLiNodes) - -# Test 6 -# Test notification when a model is a dict or a list - -class MNotifyTest(model.AttributeModel): - def initialize(self, *args, **kwargs): - self.root = {"inventory": [], 'log': ""} - - -class VNotifyTest(view.View): - template = """<html> - <body> - <ol id="theList" model="root/inventory" view="List"> - <li view="someText" pattern="listItem" /> - </ol> - - <form action=""> - <input model="root" view="DefaultWidget" controller="updateInventory" name="root" /> - <input type="submit" /> - </form> - </body> -</html>""" - - def wvfactory_someText(self, request, node, m): - return widgets.Text(m) - -class InventoryUpdater(input.Anything): - def commit(self, request, node, data): - invmodel = self.model.getSubmodel(request, "inventory") - log = self.model.getSubmodel(request, "log") - inv = invmodel.getData(request) - inv.append(data) # just add a string to the list - log.setData(request, log.getData(request) + ("%s added to servers\n" % data)) - invmodel.setData(request, inv) - invmodel.notify({'request': request}) - - -class CNotifyTest(controller.Controller): - def wcfactory_updateInventory(self, request, node, model): - return InventoryUpdater(model) - - -view.registerViewForModel(VNotifyTest, MNotifyTest) -controller.registerControllerForModel(CNotifyTest, MNotifyTest) - -class NotifyTest(WovenTC): - modelFactory = MNotifyTest - resourceFactory = CNotifyTest - - def prerender(self): - self.r.addArg('root', 'test') - - def testComplexNotification(self): - listNode = self.d.getElementById("theList") - self.assert_(listNode, "Test %s failed" % outputNum) - liNodes = domhelpers.getElementsByTagName(listNode, 'li') - self.assert_(liNodes, - "DOM was not updated by notifying Widgets. Test %s" % outputNum) - text = domhelpers.gatherTextNodes(liNodes[0]) - self.assert_(text.strip() == "test", - "Wrong output: %s. Test %s" % (text, outputNum)) - -view.registerViewForModel(LLView, LLModel) - -#### Test 7 -# Test model path syntax -# model="/" should get you the root object -# model="." should get you the current object -# model=".." should get you the parent model object - - -# xxx sanity check for now; just make sure it doesn't raise anything - -class ModelPathTest(WovenTC): - modelFactory = lambda self: ['hello', ['hi', 'there'], - 'hi', ['asdf', ['qwer', 'asdf']]] - resourceFactory = page.Page - - def prerender(self): - self.t.template = """<html> - <div model="0" view="None"> - <div model=".." view="Text" /> - </div> - - <div model="0" view="None"> - <div model="../1/../2/../3" view="Text" /> - </div> - - <div model="0" view="None"> - <div model="../3/1/./1" view="Text" /> - </div> - - <div model="3/1/0" view="None"> - <div model="/" view="Text" /> - </div> - - <div model="3/1/0" view="None"> - <div model="/3" view="Text" /> - </div> - -</html>""" - -#### Test 8 -# Test a large number of widgets - -class HugeTest(WovenTC): - modelFactory = lambda self: ['hello' for x in range(100)] - resourceFactory = page.Page - - def prerender(self): - self.t.template = """<html> - <div model="." view="List"> - <div pattern="listItem" view="Text" /> - </div> -</html>""" - - def testHugeTest(self): - pass - - -class ListOfDeferredsTest(WovenTC): - """Test rendering a model which is a list of Deferreds.""" - - modelFactory = lambda self: [defer.succeed("hello"), defer.succeed("world")] - resourceFactory = page.Page - - def prerender(self): - t = '''<div model="." view="List"> - <b pattern="listItem" view="Text" /> - </div>''' - self.t.template = t - - def testResult(self): - n = self.d.firstChild() - self.assertEquals(len(n.childNodes), 2) - for c in n.childNodes: - self.assertEquals(c.nodeName, "b") - self.assertEquals(n.firstChild().firstChild().toxml().strip(), "hello") - self.assertEquals(n.lastChild().firstChild().toxml().strip(), "world") - - -class FakeHTTPChannel: - # TODO: this should be an interface in twisted.protocols.http... lots of - # things want to fake out HTTP - def __init__(self): - self.transport = self - self.factory = self - self.received_cookies = {} - - # 'factory' attribute needs this - def log(self, req): - pass - - # 'channel' of request needs this - def requestDone(self, req): - self.req = req - - # 'transport' attribute needs this - def getPeer(self): - return address.IPv4Address("TCP", "fake", "fake") - def getHost(self): - return address.IPv4Address("TCP", "fake", 80) - - def write(self, data): - # print data - pass - def writeSequence(self, datas): - for data in datas: - self.write(data) - - # Utility for testing. - - def makeFakeRequest(self, path, **vars): - req = FakeHTTPRequest(self, queued=0) - req.received_cookies.update(self.received_cookies) - req.requestReceived("GET", path, "1.0") - return req - -class FakeHTTPRequest(server.Request): - def __init__(self, *args, **kw): - server.Request.__init__(self, *args, **kw) - self._cookieCache = {} - from cStringIO import StringIO - self.content = StringIO() - self.received_headers['host'] = 'fake.com' - self.written = StringIO() - - def write(self, data): - self.written.write(data) - server.Request.write(self, data) - - def addCookie(self, k, v, *args,**kw): - server.Request.addCookie(self,k,v,*args,**kw) - assert not self._cookieCache.has_key(k), "Should not be setting duplicate cookies!" - self._cookieCache[k] = v - self.channel.received_cookies[k] = v - - def processingFailed(self, fail): - raise fail - -class FakeSite(server.Site): - def getResourceFor(self, req): - res = server.Site.getResourceFor(self,req) - self.caughtRes = res - return res - -from twisted.web import static - -class GuardTest(unittest.TestCase): - def testSessionInit(self): - sessWrapped = static.Data("you should never see this", "text/plain") - swChild = static.Data("NO", "text/plain") - sessWrapped.putChild("yyy",swChild) - swrap = guard.SessionWrapper(sessWrapped) - da = static.Data("b","text/plain") - da.putChild("xxx", swrap) - st = FakeSite(da) - chan = FakeHTTPChannel() - chan.site = st - - # first we're going to make sure that the session doesn't get set by - # accident when browsing without first explicitly initializing the - # session - req = FakeHTTPRequest(chan, queued=0) - req.requestReceived("GET", "/xxx/yyy", "1.0") - assert len(req._cookieCache.values()) == 0, req._cookieCache.values() - self.assertEquals(req.getSession(),None) - - # now we're going to make sure that the redirect and cookie are properly set - req = FakeHTTPRequest(chan, queued=0) - req.requestReceived("GET", "/xxx/"+guard.INIT_SESSION, "1.0") - ccv = req._cookieCache.values() - self.assertEquals(len(ccv),1) - cookie = ccv[0] - # redirect set? - self.failUnless(req.headers.has_key('location')) - # redirect matches cookie? - self.assertEquals(req.headers['location'].split('/')[-1], guard.SESSION_KEY+cookie) - # URL is correct? - self.assertEquals(req.headers['location'], - 'http://fake.com/xxx/'+guard.SESSION_KEY+cookie) - oldreq = req - - # now let's try with a request for the session-cookie URL that has a cookie set - url = "/"+(oldreq.headers['location'].split('http://fake.com/',1))[1] - req = chan.makeFakeRequest(url) - self.assertEquals(req.headers['location'].split('?')[0], - 'http://fake.com/xxx/') - for sz in swrap.sessions.values(): - sz.expire() - - - -class _TestPage(page.Page): - template = """ - <html><body> - - <div>First: <span model="title" view="Text"/></div> - <div>Second: <span model="title" view="Text"/></div> - <div>Third: <span model="title" view="Text"/></div> - - </body></html> - """ - - def wmfactory_title(self, request): - d = defer.Deferred() - reactor.callLater(0, d.callback, 'The Result') - return d - -class DeferredModelTestCase(unittest.TestCase): - def testDeferredModel(self): - # Test that multiple uses of a deferred model work correctly. - channel = FakeHTTPChannel() - channel.site = FakeSite(_TestPage()) - request = channel.makeFakeRequest('/') - - d = request.notifyFinish() - def check(_): - dom = microdom.parseXMLString(request.written.getvalue()) - spanElems = domhelpers.findNodesNamed(dom, 'span') - for spanElem in spanElems: - self.failUnlessEqual('The Result', spanElem.childNodes[0].data) - - return d.addCallback(check) - - -class MyMacroPage(page.Page): - template = """\ -<html macro='foo'> -<head fill-slot='head'> -<script> -<![CDATA[ - <>'"& -]]> -</script> -</head> -</html> -""" - def wvfactory_foo(self, request, node, model): - return widgets.ExpandMacro(model, macroFile = 'cdataxtester.html', - macroFileDirectory = '.', - macroName = 'foo' - ) - -class ExpandMacroTestCase(WovenTC): - resourceFactory = MyMacroPage - def setUp(self, *args, **kwargs): - thepage = """\ -<html> -<head slot='head' /> -</html> -""" - file('cdatatester.html', 'wb').write(thepage) - WovenTC.setUp(self, *args, **kwargs) - def testCDATANotQuoted(self): - self.failUnless(self.output.find('<>\'"&')>=0) - - - diff --git a/tools/buildbot/pylibs/twisted/web/test/test_xml.py b/tools/buildbot/pylibs/twisted/web/test/test_xml.py deleted file mode 100644 index a2e235c..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/test_xml.py +++ /dev/null @@ -1,760 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_xml -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Some fairly inadequate testcases for Twisted XML support.""" - -from __future__ import nested_scopes - -from twisted.trial.unittest import TestCase - -from twisted.web import sux - -from twisted.web import microdom - -from twisted.web import domhelpers - -class Sux0r(sux.XMLParser): - def __init__(self): - self.tokens = [] - - def getTagStarts(self): - return [token for token in self.tokens if token[0] == 'start'] - - def gotTagStart(self, name, attrs): - self.tokens.append(("start", name, attrs)) - - def gotText(self, text): - self.tokens.append(("text", text)) - -class SUXTest(TestCase): - - def testBork(self): - s = "<bork><bork><bork>" - ms = Sux0r() - ms.connectionMade() - ms.dataReceived(s) - self.failUnlessEqual(len(ms.getTagStarts()),3) - - -class MicroDOMTest(TestCase): - - def test_leadingTextDropping(self): - """ - Make sure that if there's no top-level node lenient-mode won't - drop leading text that's outside of any elements. - """ - s = "Hi orders! <br>Well. <br>" - d = microdom.parseString(s, beExtremelyLenient=True) - self.assertEquals(d.firstChild().toxml(), - '<html>Hi orders! <br />Well. <br /></html>') - - def test_trailingTextDropping(self): - """ - Ensure that no *trailing* text in a mal-formed - no-top-level-element document(s) will not be dropped. - """ - s = "<br>Hi orders!" - d = microdom.parseString(s, beExtremelyLenient=True) - self.assertEquals(d.firstChild().toxml(), - '<html><br />Hi orders!</html>') - - - def test_noTags(self): - """ - A string with nothing that looks like a tag at all should just - be parsed as body text. - """ - s = "Hi orders!" - d = microdom.parseString(s, beExtremelyLenient=True) - self.assertEquals(d.firstChild().toxml(), - "<html>Hi orders!</html>") - - - def test_surroundingCrap(self): - """ - If a document is surrounded by non-xml text, the text should - be remain in the XML. - """ - s = "Hi<br> orders!" - d = microdom.parseString(s, beExtremelyLenient=True) - self.assertEquals(d.firstChild().toxml(), - "<html>Hi<br /> orders!</html>") - - - def testCaseSensitiveSoonCloser(self): - s = """ - <HTML><BODY> - <P ALIGN="CENTER"> - <A HREF="http://www.apache.org/"><IMG SRC="/icons/apache_pb.gif"></A> - </P> - - <P> - This is an insane set of text nodes that should NOT be gathered under - the A tag above. - </P> - </BODY></HTML> - """ - d = microdom.parseString(s, beExtremelyLenient=1) - l = domhelpers.findNodesNamed(d.documentElement, 'a') - n = domhelpers.gatherTextNodes(l[0],1).replace(' ',' ') - self.assertEquals(n.find('insane'), -1) - - - def test_lenientParenting(self): - """ - Test that C{parentNode} attributes are set to meaningful values when - we are parsing HTML that lacks a root node. - """ - # Spare the rod, ruin the child. - s = "<br/><br/>" - d = microdom.parseString(s, beExtremelyLenient=1) - self.assertIdentical(d.documentElement, - d.documentElement.firstChild().parentNode) - - - def test_lenientParentSingle(self): - """ - Test that the C{parentNode} attribute is set to a meaningful value - when we parse an HTML document that has a non-Element root node. - """ - s = "Hello" - d = microdom.parseString(s, beExtremelyLenient=1) - self.assertIdentical(d.documentElement, - d.documentElement.firstChild().parentNode) - - - def testUnEntities(self): - s = """ - <HTML> - This HTML goes between Stupid <=CrAzY!=> Dumb. - </HTML> - """ - d = microdom.parseString(s, beExtremelyLenient=1) - n = domhelpers.gatherTextNodes(d) - self.assertNotEquals(n.find('>'), -1) - - def testEmptyError(self): - self.assertRaises(sux.ParseError, microdom.parseString, "") - - def testTameDocument(self): - s = """ - <test> - <it> - <is> - <a> - test - </a> - </is> - </it> - </test> - """ - d = microdom.parseString(s) - self.assertEquals( - domhelpers.gatherTextNodes(d.documentElement).strip() ,'test') - - def testAwfulTagSoup(self): - s = """ - <html> - <head><title> I send you this message to have your advice!!!!</titl e - </headd> - - <body bgcolor alink hlink vlink> - - <h1><BLINK>SALE</blINK> TWENTY MILLION EMAILS & FUR COAT NOW - FREE WITH `ENLARGER'</h1> - - YES THIS WONDERFUL AWFER IS NOW HERER!!! - - <script LANGUAGE="javascript"> -function give_answers() { -if (score < 70) { -alert("I hate you"); -}} - </script><a href=/foo.com/lalal name=foo>lalal</a> - </body> - </HTML> - """ - d = microdom.parseString(s, beExtremelyLenient=1) - l = domhelpers.findNodesNamed(d.documentElement, 'blink') - self.assertEquals(len(l), 1) - - def testScriptLeniency(self): - s = """ - <script>(foo < bar) and (bar > foo)</script> - <script language="javascript">foo </scrip bar </script> - <script src="foo"> - <script src="foo">baz</script> - <script /><script></script> - """ - d = microdom.parseString(s, beExtremelyLenient=1) - self.assertEquals(d.firstChild().firstChild().firstChild().data, - "(foo < bar) and (bar > foo)") - self.assertEquals( - d.firstChild().getElementsByTagName("script")[1].firstChild().data, - "foo </scrip bar ") - - def testScriptLeniencyIntelligence(self): - # if there is comment or CDATA in script, the autoquoting in bEL mode - # should not happen - s = """<script><!-- lalal --></script>""" - self.assertEquals( - microdom.parseString(s, beExtremelyLenient=1).firstChild().toxml(), s) - s = """<script><![CDATA[lalal]]></script>""" - self.assertEquals( - microdom.parseString(s, beExtremelyLenient=1).firstChild().toxml(), s) - s = """<script> // <![CDATA[ - lalal - //]]></script>""" - self.assertEquals( - microdom.parseString(s, beExtremelyLenient=1).firstChild().toxml(), s) - - def testPreserveCase(self): - s = '<eNcApSuLaTe><sUxor></sUxor><bOrk><w00T>TeXt</W00t></BoRk></EnCaPsUlAtE>' - s2 = s.lower().replace('text', 'TeXt') - # these are the only two option permutations that *can* parse the above - d = microdom.parseString(s, caseInsensitive=1, preserveCase=1) - d2 = microdom.parseString(s, caseInsensitive=1, preserveCase=0) - # caseInsensitive=0 preserveCase=0 is not valid, it's converted to - # caseInsensitive=0 preserveCase=1 - d3 = microdom.parseString(s2, caseInsensitive=0, preserveCase=1) - d4 = microdom.parseString(s2, caseInsensitive=1, preserveCase=0) - d5 = microdom.parseString(s2, caseInsensitive=1, preserveCase=1) - # this is slightly contrived, toxml() doesn't need to be identical - # for the documents to be equivalent (i.e. <b></b> to <b/>), - # however this assertion tests preserving case for start and - # end tags while still matching stuff like <bOrk></BoRk> - self.assertEquals(d.documentElement.toxml(), s) - self.assert_(d.isEqualToDocument(d2), "%r != %r" % (d.toxml(), d2.toxml())) - self.assert_(d2.isEqualToDocument(d3), "%r != %r" % (d2.toxml(), d3.toxml())) - # caseInsensitive=0 on the left, NOT perserveCase=1 on the right - ## XXX THIS TEST IS TURNED OFF UNTIL SOMEONE WHO CARES ABOUT FIXING IT DOES - #self.failIf(d3.isEqualToDocument(d2), "%r == %r" % (d3.toxml(), d2.toxml())) - self.assert_(d3.isEqualToDocument(d4), "%r != %r" % (d3.toxml(), d4.toxml())) - self.assert_(d4.isEqualToDocument(d5), "%r != %r" % (d4.toxml(), d5.toxml())) - - def testDifferentQuotes(self): - s = '<test a="a" b=\'b\' />' - d = microdom.parseString(s) - e = d.documentElement - self.assertEquals(e.getAttribute('a'), 'a') - self.assertEquals(e.getAttribute('b'), 'b') - - def testLinebreaks(self): - s = '<test \na="a"\n\tb="#b" />' - d = microdom.parseString(s) - e = d.documentElement - self.assertEquals(e.getAttribute('a'), 'a') - self.assertEquals(e.getAttribute('b'), '#b') - - def testMismatchedTags(self): - for s in '<test>', '<test> </tset>', '</test>': - self.assertRaises(microdom.MismatchedTags, microdom.parseString, s) - - def testComment(self): - s = "<bar><!--<foo />--></bar>" - d = microdom.parseString(s) - e = d.documentElement - self.assertEquals(e.nodeName, "bar") - c = e.childNodes[0] - self.assert_(isinstance(c, microdom.Comment)) - self.assertEquals(c.value, "<foo />") - c2 = c.cloneNode() - self.assert_(c is not c2) - self.assertEquals(c2.toxml(), "<!--<foo />-->") - - def testText(self): - d = microdom.parseString("<bar>xxxx</bar>").documentElement - text = d.childNodes[0] - self.assert_(isinstance(text, microdom.Text)) - self.assertEquals(text.value, "xxxx") - clone = text.cloneNode() - self.assert_(clone is not text) - self.assertEquals(clone.toxml(), "xxxx") - - def testEntities(self): - nodes = microdom.parseString("<b>&AB;</b>").documentElement.childNodes - self.assertEquals(len(nodes), 2) - self.assertEquals(nodes[0].data, "&") - self.assertEquals(nodes[1].data, "AB;") - self.assertEquals(nodes[0].cloneNode().toxml(), "&") - for n in nodes: - self.assert_(isinstance(n, microdom.EntityReference)) - - def testCData(self): - s = '<x><![CDATA[</x>\r\n & foo]]></x>' - cdata = microdom.parseString(s).documentElement.childNodes[0] - self.assert_(isinstance(cdata, microdom.CDATASection)) - self.assertEquals(cdata.data, "</x>\r\n & foo") - self.assertEquals(cdata.cloneNode().toxml(), "<![CDATA[</x>\r\n & foo]]>") - - def testSingletons(self): - s = "<foo><b/><b /><b\n/></foo>" - s2 = "<foo><b/><b/><b/></foo>" - nodes = microdom.parseString(s).documentElement.childNodes - nodes2 = microdom.parseString(s2).documentElement.childNodes - self.assertEquals(len(nodes), 3) - for (n, n2) in zip(nodes, nodes2): - self.assert_(isinstance(n, microdom.Element)) - self.assertEquals(n.nodeName, "b") - self.assert_(n.isEqualToNode(n2)) - - def testAttributes(self): - s = '<foo a="b" />' - node = microdom.parseString(s).documentElement - - self.assertEquals(node.getAttribute("a"), "b") - self.assertEquals(node.getAttribute("c"), None) - self.assert_(node.hasAttribute("a")) - self.assert_(not node.hasAttribute("c")) - a = node.getAttributeNode("a") - self.assertEquals(a.value, "b") - - node.setAttribute("foo", "bar") - self.assertEquals(node.getAttribute("foo"), "bar") - - def testChildren(self): - s = "<foo><bar /><baz /><bax>foo</bax></foo>" - d = microdom.parseString(s).documentElement - self.assertEquals([n.nodeName for n in d.childNodes], ["bar", "baz", "bax"]) - self.assertEquals(d.lastChild().nodeName, "bax") - self.assertEquals(d.firstChild().nodeName, "bar") - self.assert_(d.hasChildNodes()) - self.assert_(not d.firstChild().hasChildNodes()) - - def testMutate(self): - s = "<foo />" - s1 = '<foo a="b"><bar/><foo/></foo>' - s2 = '<foo a="b">foo</foo>' - d = microdom.parseString(s).documentElement - d1 = microdom.parseString(s1).documentElement - d2 = microdom.parseString(s2).documentElement - - d.appendChild(d.cloneNode()) - d.setAttribute("a", "b") - child = d.childNodes[0] - self.assertEquals(child.getAttribute("a"), None) - self.assertEquals(child.nodeName, "foo") - - d.insertBefore(microdom.Element("bar"), child) - self.assertEquals(d.childNodes[0].nodeName, "bar") - self.assertEquals(d.childNodes[1], child) - for n in d.childNodes: - self.assertEquals(n.parentNode, d) - self.assert_(d.isEqualToNode(d1)) - - d.removeChild(child) - self.assertEquals(len(d.childNodes), 1) - self.assertEquals(d.childNodes[0].nodeName, "bar") - - t = microdom.Text("foo") - d.replaceChild(t, d.firstChild()) - self.assertEquals(d.firstChild(), t) - self.assert_(d.isEqualToNode(d2)) - - def testSearch(self): - s = "<foo><bar id='me' /><baz><foo /></baz></foo>" - s2 = "<fOo><bAr id='me' /><bAz><fOO /></bAz></fOo>" - d = microdom.parseString(s) - d2 = microdom.parseString(s2, caseInsensitive=0, preserveCase=1) - d3 = microdom.parseString(s2, caseInsensitive=1, preserveCase=1) - - root = d.documentElement - self.assertEquals(root.firstChild(), d.getElementById('me')) - self.assertEquals(d.getElementsByTagName("foo"), - [root, root.lastChild().firstChild()]) - - root = d2.documentElement - self.assertEquals(root.firstChild(), d2.getElementById('me')) - self.assertEquals(d2.getElementsByTagName('fOo'), [root]) - self.assertEquals(d2.getElementsByTagName('fOO'), - [root.lastChild().firstChild()]) - self.assertEquals(d2.getElementsByTagName('foo'), []) - - root = d3.documentElement - self.assertEquals(root.firstChild(), d3.getElementById('me')) - self.assertEquals(d3.getElementsByTagName('FOO'), - [root, root.lastChild().firstChild()]) - self.assertEquals(d3.getElementsByTagName('fOo'), - [root, root.lastChild().firstChild()]) - - def testDoctype(self): - s = ('<?xml version="1.0"?>' - '<!DOCTYPE foo PUBLIC "baz" "http://www.example.com/example.dtd">' - '<foo></foo>') - s2 = '<foo/>' - d = microdom.parseString(s) - d2 = microdom.parseString(s2) - self.assertEquals(d.doctype, - 'foo PUBLIC "baz" "http://www.example.com/example.dtd"') - self.assertEquals(d.toxml(), s) - self.failIf(d.isEqualToDocument(d2)) - self.failUnless(d.documentElement.isEqualToNode(d2.documentElement)) - - samples = [("<img/>", "<img />"), - ("<foo A='b'>x</foo>", '<foo A="b">x</foo>'), - ("<foo><BAR /></foo>", "<foo><BAR></BAR></foo>"), - ("<foo>hello there & yoyoy</foo>", - "<foo>hello there & yoyoy</foo>"), - ] - - def testOutput(self): - for s, out in self.samples: - d = microdom.parseString(s, caseInsensitive=0) - d2 = microdom.parseString(out, caseInsensitive=0) - testOut = d.documentElement.toxml() - self.assertEquals(out, testOut) - self.assert_(d.isEqualToDocument(d2)) - - def testErrors(self): - for s in ["<foo>&am</foo>", "<foo", "<f>&</f>", "<() />"]: - self.assertRaises(Exception, microdom.parseString, s) - - def testCaseInsensitive(self): - s = "<foo a='b'><BAx>x</bax></FOO>" - s2 = '<foo a="b"><bax>x</bax></foo>' - s3 = "<FOO a='b'><BAx>x</BAx></FOO>" - s4 = "<foo A='b'>x</foo>" - d = microdom.parseString(s) - d2 = microdom.parseString(s2) - d3 = microdom.parseString(s3, caseInsensitive=1) - d4 = microdom.parseString(s4, caseInsensitive=1, preserveCase=1) - d5 = microdom.parseString(s4, caseInsensitive=1, preserveCase=0) - d6 = microdom.parseString(s4, caseInsensitive=0, preserveCase=0) - out = microdom.parseString(s).documentElement.toxml() - self.assertRaises(microdom.MismatchedTags, microdom.parseString, - s, caseInsensitive=0) - self.assertEquals(out, s2) - self.failUnless(d.isEqualToDocument(d2)) - self.failUnless(d.isEqualToDocument(d3)) - self.failUnless(d4.documentElement.hasAttribute('a')) - self.failIf(d6.documentElement.hasAttribute('a')) - self.assertEquals(d4.documentElement.toxml(), '<foo A="b">x</foo>') - self.assertEquals(d5.documentElement.toxml(), '<foo a="b">x</foo>') - def testEatingWhitespace(self): - s = """<hello> - </hello>""" - d = microdom.parseString(s) - self.failUnless(not d.documentElement.hasChildNodes(), - d.documentElement.childNodes) - self.failUnless(d.isEqualToDocument(microdom.parseString('<hello></hello>'))) - - def testLenientAmpersand(self): - prefix = "<?xml version='1.0'?>" - # we use <pre> so space will be preserved - for i, o in [("&", "&"), - ("& ", "& "), - ("&", "&"), - ("&hello monkey", "&hello monkey")]: - d = microdom.parseString("%s<pre>%s</pre>" - % (prefix, i), beExtremelyLenient=1) - self.assertEquals(d.documentElement.toxml(), "<pre>%s</pre>" % o) - # non-space preserving - d = microdom.parseString("<t>hello & there</t>", beExtremelyLenient=1) - self.assertEquals(d.documentElement.toxml(), "<t>hello & there</t>") - - def testInsensitiveLenient(self): - # testing issue #537 - d = microdom.parseString( - "<?xml version='1.0'?><bar><xA><y>c</Xa> <foo></bar>", - beExtremelyLenient=1) - self.assertEquals(d.documentElement.firstChild().toxml(), "<xa><y>c</y></xa>") - - def testSpacing(self): - # testing issue #414 - s = "<?xml version='1.0'?><p><q>smart</q> <code>HairDryer</code></p>" - d = microdom.parseString(s, beExtremelyLenient=1) - expected = "<p><q>smart</q> <code>HairDryer</code></p>" - actual = d.documentElement.toxml() - self.assertEquals(expected, actual) - - testSpacing.todo = "AAARGH white space swallowing screws this up" - - def testLaterCloserSimple(self): - s = "<ul><li>foo<li>bar<li>baz</ul>" - d = microdom.parseString(s, beExtremelyLenient=1) - expected = "<ul><li>foo</li><li>bar</li><li>baz</li></ul>" - actual = d.documentElement.toxml() - self.assertEquals(expected, actual) - - def testLaterCloserCaseInsensitive(self): - s = "<DL><p><DT>foo<DD>bar</DL>" - d = microdom.parseString(s, beExtremelyLenient=1) - expected = "<dl><p></p><dt>foo</dt><dd>bar</dd></dl>" - actual = d.documentElement.toxml() - self.assertEquals(expected, actual) - - def testLaterCloserTable(self): - s = ("<table>" - "<tr><th>name<th>value<th>comment" - "<tr><th>this<td>tag<td>soup" - "<tr><th>must<td>be<td>handled" - "</table>") - expected = ("<table>" - "<tr><th>name</th><th>value</th><th>comment</th></tr>" - "<tr><th>this</th><td>tag</td><td>soup</td></tr>" - "<tr><th>must</th><td>be</td><td>handled</td></tr>" - "</table>") - d = microdom.parseString(s, beExtremelyLenient=1) - actual = d.documentElement.toxml() - self.assertEquals(expected, actual) - testLaterCloserTable.todo = "Table parsing needs to be fixed." - - def testLaterCloserDL(self): - s = ("<dl>" - "<dt>word<dd>definition" - "<dt>word<dt>word<dd>definition<dd>definition" - "</dl>") - expected = ("<dl>" - "<dt>word</dt><dd>definition</dd>" - "<dt>word</dt><dt>word</dt><dd>definition</dd><dd>definition</dd>" - "</dl>") - d = microdom.parseString(s, beExtremelyLenient=1) - actual = d.documentElement.toxml() - self.assertEquals(expected, actual) - - def testLaterCloserDL2(self): - s = ("<dl>" - "<dt>word<dd>definition<p>more definition" - "<dt>word" - "</dl>") - expected = ("<dl>" - "<dt>word</dt><dd>definition<p>more definition</p></dd>" - "<dt>word</dt>" - "</dl>") - d = microdom.parseString(s, beExtremelyLenient=1) - actual = d.documentElement.toxml() - self.assertEquals(expected, actual) - - testLaterCloserDL2.todo = "unclosed <p> messes it up." - - def testUnicodeTolerance(self): - import struct - s = '<foo><bar><baz /></bar></foo>' - j =(u'<?xml version="1.0" encoding="UCS-2" ?>\r\n<JAPANESE>\r\n' - u'<TITLE>\u5c02\u9580\u5bb6\u30ea\u30b9\u30c8 </TITLE></JAPANESE>') - j2=('\xff\xfe<\x00?\x00x\x00m\x00l\x00 \x00v\x00e\x00r\x00s\x00i\x00o' - '\x00n\x00=\x00"\x001\x00.\x000\x00"\x00 \x00e\x00n\x00c\x00o\x00d' - '\x00i\x00n\x00g\x00=\x00"\x00U\x00C\x00S\x00-\x002\x00"\x00 \x00?' - '\x00>\x00\r\x00\n\x00<\x00J\x00A\x00P\x00A\x00N\x00E\x00S\x00E' - '\x00>\x00\r\x00\n\x00<\x00T\x00I\x00T\x00L\x00E\x00>\x00\x02\\' - '\x80\x95\xb6[\xea0\xb90\xc80 \x00<\x00/\x00T\x00I\x00T\x00L\x00E' - '\x00>\x00<\x00/\x00J\x00A\x00P\x00A\x00N\x00E\x00S\x00E\x00>\x00') - def reverseBytes(s): - fmt = str(len(s) / 2) + 'H' - return struct.pack('<' + fmt, *struct.unpack('>' + fmt, s)) - urd = microdom.parseString(reverseBytes(s.encode('UTF-16'))) - ud = microdom.parseString(s.encode('UTF-16')) - sd = microdom.parseString(s) - self.assert_(ud.isEqualToDocument(sd)) - self.assert_(ud.isEqualToDocument(urd)) - ud = microdom.parseString(j) - urd = microdom.parseString(reverseBytes(j2)) - sd = microdom.parseString(j2) - self.assert_(ud.isEqualToDocument(sd)) - self.assert_(ud.isEqualToDocument(urd)) - - # test that raw text still gets encoded - # test that comments get encoded - j3=microdom.parseString(u'<foo/>') - hdr='<?xml version="1.0"?>' - div=microdom.lmx().text(u'\u221a', raw=1).node - de=j3.documentElement - de.appendChild(div) - de.appendChild(j3.createComment(u'\u221a')) - self.assertEquals(j3.toxml(), hdr+ - u'<foo><div>\u221a</div><!--\u221a--></foo>'.encode('utf8')) - - def testNamedChildren(self): - tests = {"<foo><bar /><bar unf='1' /><bar>asdfadsf</bar>" - "<bam/></foo>" : 3, - '<foo>asdf</foo>' : 0, - '<foo><bar><bar></bar></bar></foo>' : 1, - } - for t in tests.keys(): - node = microdom.parseString(t).documentElement - result = domhelpers.namedChildren(node, 'bar') - self.assertEquals(len(result), tests[t]) - if result: - self.assert_(hasattr(result[0], 'tagName')) - - def testCloneNode(self): - s = '<foo a="b"><bax>x</bax></foo>' - node = microdom.parseString(s).documentElement - clone = node.cloneNode(deep=1) - self.failIfEquals(node, clone) - self.assertEquals(len(node.childNodes), len(clone.childNodes)) - c1, c2 = node.firstChild(), clone.firstChild() - self.failIfEquals(c1, c2) - self.assertEquals(len(c1.childNodes), len(c2.childNodes)) - self.failIfEquals(c1.firstChild(), c2.firstChild()) - self.assertEquals(s, clone.toxml()) - self.assertEquals(node.namespace, clone.namespace) - - def testCloneDocument(self): - s = ('<?xml version="1.0"?>' - '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"' - '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><foo></foo>') - - node = microdom.parseString(s) - clone = node.cloneNode(deep=1) - self.failIfEquals(node, clone) - self.assertEquals(len(node.childNodes), len(clone.childNodes)) - self.assertEquals(s, clone.toxml()) - - self.failUnless(clone.isEqualToDocument(node)) - self.failUnless(node.isEqualToDocument(clone)) - - - def testLMX(self): - n = microdom.Element("p") - lmx = microdom.lmx(n) - lmx.text("foo") - b = lmx.b(a="c") - b.foo()["z"] = "foo" - b.foo() - b.add("bar", c="y") - - s = '<p>foo<b a="c"><foo z="foo"></foo><foo></foo><bar c="y"></bar></b></p>' - self.assertEquals(s, n.toxml()) - - def testDict(self): - n = microdom.Element("p") - d = {n : 1} # will fail if Element is unhashable - - def testEscaping(self): - # issue 590 - raw = "&'some \"stuff\"', <what up?>" - cooked = "&'some "stuff"', <what up?>" - esc1 = microdom.escape(raw) - self.assertEquals(esc1, cooked) - self.assertEquals(microdom.unescape(esc1), raw) - - def testNamespaces(self): - s = ''' - <x xmlns="base"> - <y /> - <y q="1" x:q="2" y:q="3" /> - <y:y xml:space="1">here is some space </y:y> - <y:y /> - <x:y /> - </x> - ''' - d = microdom.parseString(s) - # at least make sure it doesn't traceback - s2 = d.toprettyxml() - self.assertEquals(d.documentElement.namespace, - "base") - self.assertEquals(d.documentElement.getElementsByTagName("y")[0].namespace, - "base") - self.assertEquals( - d.documentElement.getElementsByTagName("y")[1].getAttributeNS('base','q'), - '1') - - d2 = microdom.parseString(s2) - self.assertEquals(d2.documentElement.namespace, - "base") - self.assertEquals(d2.documentElement.getElementsByTagName("y")[0].namespace, - "base") - self.assertEquals( - d2.documentElement.getElementsByTagName("y")[1].getAttributeNS('base','q'), - '1') - - def testNamespaceDelete(self): - """ - Test that C{toxml} can support xml structures that remove namespaces. - """ - s1 = ('<?xml version="1.0"?><html xmlns="http://www.w3.org/TR/REC-html40">' - '<body xmlns=""></body></html>') - s2 = microdom.parseString(s1).toxml() - self.assertEquals(s1, s2) - - def testNamespaceInheritance(self): - """ - Check that unspecified namespace is a thing separate from undefined - namespace. This test added after discovering some weirdness in Lore. - """ - # will only work if childNodes is mutated. not sure why. - child = microdom.Element('ol') - parent = microdom.Element('div', namespace='http://www.w3.org/1999/xhtml') - parent.childNodes = [child] - self.assertEquals(parent.toxml(), - '<div xmlns="http://www.w3.org/1999/xhtml"><ol></ol></div>') - - -class TestBrokenHTML(TestCase): - """ - Tests for when microdom encounters very bad HTML and C{beExtremelyLenient} - is enabled. These tests are inspired by some HTML generated in by a mailer, - which breaks up very long lines by splitting them with '!\n '. The expected - behaviour is loosely modelled on the way Firefox treats very bad HTML. - """ - - def checkParsed(self, input, expected, beExtremelyLenient=1): - """ - Check that C{input}, when parsed, produces a DOM where the XML - of the document element is equal to C{expected}. - """ - output = microdom.parseString(input, - beExtremelyLenient=beExtremelyLenient) - self.assertEquals(output.documentElement.toxml(), expected) - - - def test_brokenAttributeName(self): - """ - Check that microdom does its best to handle broken attribute names. - The important thing is that it doesn't raise an exception. - """ - input = '<body><h1><div al!\n ign="center">Foo</div></h1></body>' - expected = ('<body><h1><div ign="center" al="True">' - 'Foo</div></h1></body>') - self.checkParsed(input, expected) - - - def test_brokenAttributeValue(self): - """ - Check that microdom encompasses broken attribute values. - """ - input = '<body><h1><div align="cen!\n ter">Foo</div></h1></body>' - expected = '<body><h1><div align="cen!\n ter">Foo</div></h1></body>' - self.checkParsed(input, expected) - - - def test_brokenOpeningTag(self): - """ - Check that microdom does its best to handle broken opening tags. - The important thing is that it doesn't raise an exception. - """ - input = '<body><h1><sp!\n an>Hello World!</span></h1></body>' - expected = '<body><h1><sp an="True">Hello World!</sp></h1></body>' - self.checkParsed(input, expected) - - - def test_brokenSelfClosingTag(self): - """ - Check that microdom does its best to handle broken self-closing tags - The important thing is that it doesn't raise an exception. - """ - self.checkParsed('<body><span /!\n></body>', - '<body><span></span></body>') - self.checkParsed('<span!\n />', '<span></span>') - - - def test_brokenClosingTag(self): - """ - Check that microdom does its best to handle broken closing tags. - The important thing is that it doesn't raise an exception. - """ - input = '<body><h1><span>Hello World!</sp!\nan></h1></body>' - expected = '<body><h1><span>Hello World!</span></h1></body>' - self.checkParsed(input, expected) - input = '<body><h1><span>Hello World!</!\nspan></h1></body>' - self.checkParsed(input, expected) - input = '<body><h1><span>Hello World!</span!\n></h1></body>' - self.checkParsed(input, expected) - input = '<body><h1><span>Hello World!<!\n/span></h1></body>' - expected = '<body><h1><span>Hello World!<!></!></span></h1></body>' - self.checkParsed(input, expected) - diff --git a/tools/buildbot/pylibs/twisted/web/test/test_xmlrpc.py b/tools/buildbot/pylibs/twisted/web/test/test_xmlrpc.py deleted file mode 100644 index c34430a..0000000 --- a/tools/buildbot/pylibs/twisted/web/test/test_xmlrpc.py +++ /dev/null @@ -1,452 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_xmlrpc -*- -# -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Test XML-RPC support. -""" - -try: - import xmlrpclib -except ImportError: - xmlrpclib = None - class XMLRPC: pass -else: - from twisted.web import xmlrpc - from twisted.web.xmlrpc import XMLRPC, addIntrospection, _QueryFactory - -from twisted.trial import unittest -from twisted.web import server, static, client, error, http -from twisted.internet import reactor, defer -from twisted.internet.error import ConnectionDone -from twisted.python import failure - - -class TestRuntimeError(RuntimeError): - pass - -class TestValueError(ValueError): - pass - - - -class Test(XMLRPC): - - FAILURE = 666 - NOT_FOUND = 23 - SESSION_EXPIRED = 42 - - # the doc string is part of the test - def xmlrpc_add(self, a, b): - """ - This function add two numbers. - """ - return a + b - - xmlrpc_add.signature = [['int', 'int', 'int'], - ['double', 'double', 'double']] - - # the doc string is part of the test - def xmlrpc_pair(self, string, num): - """ - This function puts the two arguments in an array. - """ - return [string, num] - - xmlrpc_pair.signature = [['array', 'string', 'int']] - - # the doc string is part of the test - def xmlrpc_defer(self, x): - """Help for defer.""" - return defer.succeed(x) - - def xmlrpc_deferFail(self): - return defer.fail(TestValueError()) - - # don't add a doc string, it's part of the test - def xmlrpc_fail(self): - raise TestRuntimeError - - def xmlrpc_fault(self): - return xmlrpc.Fault(12, "hello") - - def xmlrpc_deferFault(self): - return defer.fail(xmlrpc.Fault(17, "hi")) - - def xmlrpc_complex(self): - return {"a": ["b", "c", 12, []], "D": "foo"} - - def xmlrpc_dict(self, map, key): - return map[key] - - def _getFunction(self, functionPath): - try: - return XMLRPC._getFunction(self, functionPath) - except xmlrpc.NoSuchFunction: - if functionPath.startswith("SESSION"): - raise xmlrpc.Fault(self.SESSION_EXPIRED, - "Session non-existant/expired.") - else: - raise - - xmlrpc_dict.help = 'Help for dict.' - -class TestAuthHeader(Test): - """ - This is used to get the header info so that we can test - authentication. - """ - def __init__(self): - Test.__init__(self) - self.request = None - - def render(self, request): - self.request = request - return Test.render(self, request) - - def xmlrpc_authinfo(self): - return self.request.getUser(), self.request.getPassword() - - -class TestQueryProtocol(xmlrpc.QueryProtocol): - """ - QueryProtocol for tests that saves headers received inside the factory. - """ - def handleHeader(self, key, val): - self.factory.headers[key.lower()] = val - - -class TestQueryFactory(xmlrpc._QueryFactory): - """ - QueryFactory using L{TestQueryProtocol} for saving headers. - """ - protocol = TestQueryProtocol - - def __init__(self, *args, **kwargs): - self.headers = {} - xmlrpc._QueryFactory.__init__(self, *args, **kwargs) - - -class XMLRPCTestCase(unittest.TestCase): - - def setUp(self): - self.p = reactor.listenTCP(0, server.Site(Test()), - interface="127.0.0.1") - self.port = self.p.getHost().port - self.factories = [] - - def tearDown(self): - self.factories = [] - return self.p.stopListening() - - def queryFactory(self, *args, **kwargs): - """ - Specific queryFactory for proxy that uses our custom - L{TestQueryFactory}, and save factories. - """ - factory = TestQueryFactory(*args, **kwargs) - self.factories.append(factory) - return factory - - def proxy(self): - p = xmlrpc.Proxy("http://127.0.0.1:%d/" % self.port) - p.queryFactory = self.queryFactory - return p - - def test_results(self): - inputOutput = [ - ("add", (2, 3), 5), - ("defer", ("a",), "a"), - ("dict", ({"a": 1}, "a"), 1), - ("pair", ("a", 1), ["a", 1]), - ("complex", (), {"a": ["b", "c", 12, []], "D": "foo"})] - - dl = [] - for meth, args, outp in inputOutput: - d = self.proxy().callRemote(meth, *args) - d.addCallback(self.assertEquals, outp) - dl.append(d) - return defer.DeferredList(dl, fireOnOneErrback=True) - - def test_errors(self): - """ - Verify that for each way a method exposed via XML-RPC can fail, the - correct 'Content-type' header is set in the response and that the - client-side Deferred is errbacked with an appropriate C{Fault} - instance. - """ - dl = [] - for code, methodName in [(666, "fail"), (666, "deferFail"), - (12, "fault"), (23, "noSuchMethod"), - (17, "deferFault"), (42, "SESSION_TEST")]: - d = self.proxy().callRemote(methodName) - d = self.assertFailure(d, xmlrpc.Fault) - d.addCallback(lambda exc, code=code: - self.assertEquals(exc.faultCode, code)) - dl.append(d) - d = defer.DeferredList(dl, fireOnOneErrback=True) - def cb(ign): - for factory in self.factories: - self.assertEquals(factory.headers['content-type'], - 'text/xml') - self.flushLoggedErrors(TestRuntimeError, TestValueError) - d.addCallback(cb) - return d - - def test_errorGet(self): - """ - A classic GET on the xml server should return a NOT_ALLOWED. - """ - d = client.getPage("http://127.0.0.1:%d/" % (self.port,)) - d = self.assertFailure(d, error.Error) - d.addCallback( - lambda exc: self.assertEquals(int(exc.args[0]), http.NOT_ALLOWED)) - return d - - def test_errorXMLContent(self): - """ - Test that an invalid XML input returns an L{xmlrpc.Fault}. - """ - d = client.getPage("http://127.0.0.1:%d/" % (self.port,), - method="POST", postdata="foo") - def cb(result): - self.assertRaises(xmlrpc.Fault, xmlrpclib.loads, result) - d.addCallback(cb) - return d - - -class XMLRPCTestCase2(XMLRPCTestCase): - """ - Test with proxy that doesn't add a slash. - """ - - def proxy(self): - p = xmlrpc.Proxy("http://127.0.0.1:%d" % self.port) - p.queryFactory = self.queryFactory - return p - - - -class XMLRPCAllowNoneTestCase(unittest.TestCase): - """ - Test with allowNone set to True. - - These are not meant to be exhaustive serialization tests, since - L{xmlrpclib} does all of the actual serialization work. They are just - meant to exercise a few codepaths to make sure we are calling into - xmlrpclib correctly. - """ - - def setUp(self): - self.p = reactor.listenTCP( - 0, server.Site(Test(allowNone=True)), interface="127.0.0.1") - self.port = self.p.getHost().port - - - def tearDown(self): - return self.p.stopListening() - - - def proxy(self): - return xmlrpc.Proxy("http://127.0.0.1:%d" % (self.port,), - allowNone=True) - - - def test_deferredNone(self): - """ - Test that passing a C{None} as an argument to a remote method and - returning a L{Deferred} which fires with C{None} properly passes - </nil> over the network if allowNone is set to True. - """ - d = self.proxy().callRemote('defer', None) - d.addCallback(self.assertEquals, None) - return d - - - def test_dictWithNoneValue(self): - """ - Test that return a C{dict} with C{None} as a value works properly. - """ - d = self.proxy().callRemote('defer', {'a': None}) - d.addCallback(self.assertEquals, {'a': None}) - return d - - - -class XMLRPCTestAuthenticated(XMLRPCTestCase): - """ - Test with authenticated proxy. We run this with the same inout/ouput as - above. - """ - user = "username" - password = "asecret" - - def setUp(self): - self.p = reactor.listenTCP(0, server.Site(TestAuthHeader()), - interface="127.0.0.1") - self.port = self.p.getHost().port - self.factories = [] - - - def test_authInfoInURL(self): - p = xmlrpc.Proxy("http://%s:%s@127.0.0.1:%d/" % ( - self.user, self.password, self.port)) - d = p.callRemote("authinfo") - d.addCallback(self.assertEquals, [self.user, self.password]) - return d - - - def test_explicitAuthInfo(self): - p = xmlrpc.Proxy("http://127.0.0.1:%d/" % ( - self.port,), self.user, self.password) - d = p.callRemote("authinfo") - d.addCallback(self.assertEquals, [self.user, self.password]) - return d - - - def test_explicitAuthInfoOverride(self): - p = xmlrpc.Proxy("http://wrong:info@127.0.0.1:%d/" % ( - self.port,), self.user, self.password) - d = p.callRemote("authinfo") - d.addCallback(self.assertEquals, [self.user, self.password]) - return d - - -class XMLRPCTestIntrospection(XMLRPCTestCase): - - def setUp(self): - xmlrpc = Test() - addIntrospection(xmlrpc) - self.p = reactor.listenTCP(0, server.Site(xmlrpc),interface="127.0.0.1") - self.port = self.p.getHost().port - self.factories = [] - - def test_listMethods(self): - - def cbMethods(meths): - meths.sort() - self.failUnlessEqual( - meths, - ['add', 'complex', 'defer', 'deferFail', - 'deferFault', 'dict', 'fail', 'fault', - 'pair', 'system.listMethods', - 'system.methodHelp', - 'system.methodSignature']) - - d = self.proxy().callRemote("system.listMethods") - d.addCallback(cbMethods) - return d - - def test_methodHelp(self): - inputOutputs = [ - ("defer", "Help for defer."), - ("fail", ""), - ("dict", "Help for dict.")] - - dl = [] - for meth, expected in inputOutputs: - d = self.proxy().callRemote("system.methodHelp", meth) - d.addCallback(self.assertEquals, expected) - dl.append(d) - return defer.DeferredList(dl, fireOnOneErrback=True) - - def test_methodSignature(self): - inputOutputs = [ - ("defer", ""), - ("add", [['int', 'int', 'int'], - ['double', 'double', 'double']]), - ("pair", [['array', 'string', 'int']])] - - dl = [] - for meth, expected in inputOutputs: - d = self.proxy().callRemote("system.methodSignature", meth) - d.addCallback(self.assertEquals, expected) - dl.append(d) - return defer.DeferredList(dl, fireOnOneErrback=True) - - -class XMLRPCClientErrorHandling(unittest.TestCase): - """ - Test error handling on the xmlrpc client. - """ - def setUp(self): - self.resource = static.File(__file__) - self.resource.isLeaf = True - self.port = reactor.listenTCP(0, server.Site(self.resource), - interface='127.0.0.1') - - def tearDown(self): - return self.port.stopListening() - - def test_erroneousResponse(self): - """ - Test that calling the xmlrpc client on a static http server raises - an exception. - """ - proxy = xmlrpc.Proxy("http://127.0.0.1:%d/" % - (self.port.getHost().port,)) - return self.assertFailure(proxy.callRemote("someMethod"), Exception) - - - -class TestQueryFactoryParseResponse(unittest.TestCase): - """ - Test the behaviour of L{_QueryFactory.parseResponse}. - """ - - def setUp(self): - # The _QueryFactory that we are testing. We don't care about any - # of the constructor parameters. - self.queryFactory = _QueryFactory( - path=None, host=None, method='POST', user=None, password=None, - allowNone=False, args=()) - # An XML-RPC response that will parse without raising an error. - self.goodContents = xmlrpclib.dumps(('',)) - # An 'XML-RPC response' that will raise a parsing error. - self.badContents = 'invalid xml' - # A dummy 'reason' to pass to clientConnectionLost. We don't care - # what it is. - self.reason = failure.Failure(ConnectionDone()) - - - def test_parseResponseCallbackSafety(self): - """ - We can safely call L{_QueryFactory.clientConnectionLost} as a callback - of L{_QueryFactory.parseResponse}. - """ - d = self.queryFactory.deferred - # The failure mode is that this callback raises an AlreadyCalled - # error. We have to add it now so that it gets called synchronously - # and triggers the race condition. - d.addCallback(self.queryFactory.clientConnectionLost, self.reason) - self.queryFactory.parseResponse(self.goodContents) - return d - - - def test_parseResponseErrbackSafety(self): - """ - We can safely call L{_QueryFactory.clientConnectionLost} as an errback - of L{_QueryFactory.parseResponse}. - """ - d = self.queryFactory.deferred - # The failure mode is that this callback raises an AlreadyCalled - # error. We have to add it now so that it gets called synchronously - # and triggers the race condition. - d.addErrback(self.queryFactory.clientConnectionLost, self.reason) - self.queryFactory.parseResponse(self.badContents) - return d - - - def test_badStatusErrbackSafety(self): - """ - We can safely call L{_QueryFactory.clientConnectionLost} as an errback - of L{_QueryFactory.badStatus}. - """ - d = self.queryFactory.deferred - # The failure mode is that this callback raises an AlreadyCalled - # error. We have to add it now so that it gets called synchronously - # and triggers the race condition. - d.addErrback(self.queryFactory.clientConnectionLost, self.reason) - self.queryFactory.badStatus('status', 'message') - return d diff --git a/tools/buildbot/pylibs/twisted/web/topfiles/NEWS b/tools/buildbot/pylibs/twisted/web/topfiles/NEWS deleted file mode 100644 index 5168065a..0000000 --- a/tools/buildbot/pylibs/twisted/web/topfiles/NEWS +++ /dev/null @@ -1,107 +0,0 @@ -8.1.0 (2008-05-18) -================== - -Fixes ------ - - - Fixed an XMLRPC bug whereby sometimes a callRemote Deferred would - accidentally be fired twice when a connection was lost during the handling of - a response (#3152) - - Fixed a bug in the "Using Twisted Web" document which prevented an example - resource from being renderable (#3147) - - The deprecated mktap API is no longer used (#3127) - - -8.0.0 (2008-03-17) -================== - -Features --------- - - Add support to twisted.web.client.getPage for the HTTP HEAD method. (#2750) - -Fixes ------ - - Set content-type in xmlrpc responses to "text/xml" (#2430) - - Add more error checking in the xmlrpc.XMLRPC render method, and enforce - POST requests. (#2505) - - Reject unicode input to twisted.web.client._parse to reject invalid - unicode URLs early. (#2628) - - Correctly re-quote URL path segments when generating an URL string to - return from Request.prePathURL. (#2934) - - Make twisted.web.proxy.ProxyClientFactory close the connection when - reporting a 501 error. (#1089) - - Fix twisted.web.proxy.ReverseProxyResource to specify the port in the - host header if different from 80. (#1117) - - Change twisted.web.proxy.ReverseProxyResource so that it correctly encodes - the request URI it sends on to the server for which it is a proxy. (#3013) - - Make "twistd web --personal" use PBServerFactory (#2681) - -Misc ----- - - #1996, #2382, #2211, #2633, #2634, #2640, #2752, #238, #2905 - - -0.7.0 (2007-01-02) -================== - -Features --------- - - Python 2.5 is now supported (#1867) - - twisted.web.xmlrpc now supports the <nil/> xml-rpc extension type - in both the server and the client (#469) - -Fixes ------ - - Microdom and SUX now manages certain malformed XML more resiliently - (#1984, #2225, #2298) - - twisted.web.client.getPage can now deal with an URL of the form - "http://example.com" (no trailing slash) (#1080) - - The HTTP server now allows (invalid) URLs with multiple question - marks (#1550) - - '=' can now be in the value of a cookie (#1051) - - Microdom now correctly handles xmlns="" (#2184) - -Deprecations and Removals -------------------------- - - websetroot was removed, because it wasn't working anyway (#945) - - woven.guard no longer supports the old twisted.cred API (#1440) - -Other ------ -The following changes are minor or closely related to other changes. - - - #1636, #1637, #1638, #1936, #1883, #447 - - -0.6.0 (2006-05-21) -================== - -Features --------- - - Basic auth support for the XMLRPC client (#1474). - -Fixes ------ - - More correct datetime parsing. - - Efficiency improvements (#974) - - Handle popular non-RFC compliant formats for If-Modified-Since - headers (#976). - - Improve support for certain buggy CGI scripts. - - CONTENT_LENGTH is now available to CGI scripts. - - Support for even worse HTML in microdom (#1358). - - Trying to view a user's home page when the user doesn't have a - ~/public_html no longer displays a traceback (#551). - - Misc: #543, #1011, #1005, #1287, #1337, #1383, #1079, #1492, #1189, - #737, #872. - - -0.5.0 -===== - - Client properly reports timeouts as error - - "Socially deprecate" woven - - Fix memory leak in _c_urlarg library - - Stop using _c_urlarg library - - Fix 'gzip' and 'bzip2' content-encodings - - Escape log entries so remote user cannot corrupt the log - - Commented out range support because it's broken - - Fix HEAD responses without content-length diff --git a/tools/buildbot/pylibs/twisted/web/topfiles/README b/tools/buildbot/pylibs/twisted/web/topfiles/README deleted file mode 100644 index fb8ecc1..0000000 --- a/tools/buildbot/pylibs/twisted/web/topfiles/README +++ /dev/null @@ -1 +0,0 @@ -Twisted Web 8.1.0 diff --git a/tools/buildbot/pylibs/twisted/web/topfiles/setup.py b/tools/buildbot/pylibs/twisted/web/topfiles/setup.py deleted file mode 100644 index f1450bf..0000000 --- a/tools/buildbot/pylibs/twisted/web/topfiles/setup.py +++ /dev/null @@ -1,28 +0,0 @@ -import sys - -try: - from twisted.python import dist -except ImportError: - raise SystemExit("twisted.python.dist module not found. Make sure you " - "have installed the Twisted core package before " - "attempting to install any other Twisted projects.") - -if __name__ == '__main__': - dist.setup( - twisted_subproject="web", - scripts=dist.getScripts("web"), - # metadata - name="Twisted Web", - description="Twisted web server, programmable in Python.", - author="Twisted Matrix Laboratories", - author_email="twisted-python@twistedmatrix.com", - maintainer="James Knight", - maintainer_email="foom@fuhm.net", - url="http://twistedmatrix.com/trac/wiki/TwistedWeb", - license="MIT", - long_description="""\ -Twisted Web is a complete web server, aimed at hosting web -applications using Twisted and Python, but fully able to serve static -pages, also. -""", - ) diff --git a/tools/buildbot/pylibs/twisted/web/trp.py b/tools/buildbot/pylibs/twisted/web/trp.py deleted file mode 100644 index e2be8d6..0000000 --- a/tools/buildbot/pylibs/twisted/web/trp.py +++ /dev/null @@ -1,15 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -I contain ResourceUnpickler, which will unpickle any python object -named with the file extension .trp. -""" -from pickle import Unpickler - -def ResourceUnpickler(path, registry = None): - fl = open(path) - result = Unpickler(fl).load() - return result diff --git a/tools/buildbot/pylibs/twisted/web/twcgi.py b/tools/buildbot/pylibs/twisted/web/twcgi.py deleted file mode 100644 index 187df92..0000000 --- a/tools/buildbot/pylibs/twisted/web/twcgi.py +++ /dev/null @@ -1,256 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_cgi -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""I hold resource classes and helper classes that deal with CGI scripts. -""" - -# System Imports -import string -import os -import sys -import urllib - -# Twisted Imports -from twisted.web import http -from twisted.internet import reactor, protocol -from twisted.spread import pb -from twisted.python import log, filepath - -# Sibling Imports -import server -import error -import html -import resource -import static -from server import NOT_DONE_YET - -class CGIDirectory(resource.Resource, filepath.FilePath): - def __init__(self, pathname): - resource.Resource.__init__(self) - filepath.FilePath.__init__(self, pathname) - - def getChild(self, path, request): - fnp = self.child(path) - if not fnp.exists(): - return static.File.childNotFound - elif fnp.isdir(): - return CGIDirectory(fnp.path) - else: - return CGIScript(fnp.path) - return error.NoResource() - - def render(self, request): - return error.NoResource("CGI directories do not support directory listing.").render(request) - -class CGIScript(resource.Resource): - """I represent a CGI script. - - My implementation is complex due to the fact that it requires asynchronous - IPC with an external process with an unpleasant protocol. - """ - isLeaf = 1 - def __init__(self, filename, registry=None): - """Initialize, with the name of a CGI script file. - """ - self.filename = filename - - def render(self, request): - """Do various things to conform to the CGI specification. - - I will set up the usual slew of environment variables, then spin off a - process. - """ - script_name = "/"+string.join(request.prepath, '/') - python_path = string.join(sys.path, os.pathsep) - serverName = string.split(request.getRequestHostname(), ':')[0] - env = {"SERVER_SOFTWARE": server.version, - "SERVER_NAME": serverName, - "GATEWAY_INTERFACE": "CGI/1.1", - "SERVER_PROTOCOL": request.clientproto, - "SERVER_PORT": str(request.getHost().port), - "REQUEST_METHOD": request.method, - "SCRIPT_NAME": script_name, # XXX - "SCRIPT_FILENAME": self.filename, - "REQUEST_URI": request.uri, - } - - client = request.getClient() - if client is not None: - env['REMOTE_HOST'] = client - ip = request.getClientIP() - if ip is not None: - env['REMOTE_ADDR'] = ip - pp = request.postpath - if pp: - env["PATH_INFO"] = "/"+string.join(pp, '/') - - if hasattr(request, "content"): - # request.content is either a StringIO or a TemporaryFile, and - # the file pointer is sitting at the beginning (seek(0,0)) - request.content.seek(0,2) - length = request.content.tell() - request.content.seek(0,0) - env['CONTENT_LENGTH'] = str(length) - - qindex = string.find(request.uri, '?') - if qindex != -1: - qs = env['QUERY_STRING'] = request.uri[qindex+1:] - if '=' in qs: - qargs = [] - else: - qargs = [urllib.unquote(x) for x in qs.split('+')] - else: - env['QUERY_STRING'] = '' - qargs = [] - - # Propogate HTTP headers - for title, header in request.getAllHeaders().items(): - envname = string.upper(string.replace(title, '-', '_')) - if title not in ('content-type', 'content-length'): - envname = "HTTP_" + envname - env[envname] = header - # Propogate our environment - for key, value in os.environ.items(): - if not env.has_key(key): - env[key] = value - # And they're off! - self.runProcess(env, request, qargs) - return NOT_DONE_YET - - def runProcess(self, env, request, qargs=[]): - p = CGIProcessProtocol(request) - reactor.spawnProcess(p, self.filename, [self.filename]+qargs, env, os.path.dirname(self.filename)) - - -class FilteredScript(CGIScript): - """I am a special version of a CGI script, that uses a specific executable. - - This is useful for interfacing with other scripting languages that adhere - to the CGI standard (cf. PHPScript). My 'filter' attribute specifies what - executable to run, and my 'filename' init parameter describes which script - to pass to the first argument of that script. - """ - - filter = '/usr/bin/cat' - - def runProcess(self, env, request, qargs=[]): - p = CGIProcessProtocol(request) - reactor.spawnProcess(p, self.filter, [self.filter, self.filename]+qargs, env, os.path.dirname(self.filename)) - - -class PHP3Script(FilteredScript): - """I am a FilteredScript that uses the default PHP3 command on most systems. - """ - - filter = '/usr/bin/php3' - - -class PHPScript(FilteredScript): - """I am a FilteredScript that uses the PHP command on most systems. - Sometimes, php wants the path to itself as argv[0]. This is that time. - """ - - filter = '/usr/bin/php4' - - -class CGIProcessProtocol(protocol.ProcessProtocol, pb.Viewable): - handling_headers = 1 - headers_written = 0 - headertext = '' - errortext = '' - - # Remotely relay producer interface. - - def view_resumeProducing(self, issuer): - self.resumeProducing() - - def view_pauseProducing(self, issuer): - self.pauseProducing() - - def view_stopProducing(self, issuer): - self.stopProducing() - - def resumeProducing(self): - self.transport.resumeProducing() - - def pauseProducing(self): - self.transport.pauseProducing() - - def stopProducing(self): - self.transport.loseConnection() - - def __init__(self, request): - self.request = request - - def connectionMade(self): - self.request.registerProducer(self, 1) - self.request.content.seek(0, 0) - content = self.request.content.read() - if content: - self.transport.write(content) - self.transport.closeStdin() - - def errReceived(self, error): - self.errortext = self.errortext + error - - def outReceived(self, output): - """ - Handle a chunk of input - """ - # First, make sure that the headers from the script are sorted - # out (we'll want to do some parsing on these later.) - if self.handling_headers: - text = self.headertext + output - headerEnds = [] - for delimiter in '\n\n','\r\n\r\n','\r\r', '\n\r\n': - headerend = string.find(text,delimiter) - if headerend != -1: - headerEnds.append((headerend, delimiter)) - if headerEnds: - headerEnds.sort() - headerend, delimiter = headerEnds[0] - self.headertext = text[:headerend] - # This is a final version of the header text. - linebreak = delimiter[:len(delimiter)/2] - headers = string.split(self.headertext, linebreak) - for header in headers: - br = string.find(header,': ') - if br == -1: - log.msg( 'ignoring malformed CGI header: %s' % header ) - else: - headerName = string.lower(header[:br]) - headerText = header[br+2:] - if headerName == 'location': - self.request.setResponseCode(http.FOUND) - if headerName == 'status': - try: - statusNum = int(headerText[:3]) #"XXX <description>" sometimes happens. - except: - log.msg( "malformed status header" ) - else: - self.request.setResponseCode(statusNum) - else: - self.request.setHeader(headerName,headerText) - output = text[headerend+len(delimiter):] - self.handling_headers = 0 - if self.handling_headers: - self.headertext = text - if not self.handling_headers: - self.request.write(output) - - def processEnded(self, reason): - if reason.value.exitCode != 0: - log.msg("CGI %s exited with exit code %s" % - (self.request.uri, reason.value.exitCode)) - if self.errortext: - log.msg("Errors from CGI %s: %s" % (self.request.uri, self.errortext)) - if self.handling_headers: - log.msg("Premature end of headers in %s: %s" % (self.request.uri, self.headertext)) - self.request.write( - error.ErrorPage(http.INTERNAL_SERVER_ERROR, - "CGI Script Error", - "Premature end of script headers.").render(self.request)) - self.request.unregisterProducer() - self.request.finish() diff --git a/tools/buildbot/pylibs/twisted/web/util.py b/tools/buildbot/pylibs/twisted/web/util.py deleted file mode 100644 index 0a50de6..0000000 --- a/tools/buildbot/pylibs/twisted/web/util.py +++ /dev/null @@ -1,390 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_web -*- - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from cStringIO import StringIO - -from twisted.python import failure - -import html -import resource - - -import linecache -import string, re -import types - - -def redirectTo(URL, request): - request.redirect(URL) - return """ -<html> - <head> - <meta http-equiv=\"refresh\" content=\"0;URL=%(url)s\"> - </head> - <body bgcolor=\"#FFFFFF\" text=\"#000000\"> - <a href=\"%(url)s\">click here</a> - </body> -</html> -""" % {'url': URL} - -class Redirect(resource.Resource): - - isLeaf = 1 - - def __init__(self, url): - resource.Resource.__init__(self) - self.url = url - - def render(self, request): - return redirectTo(self.url, request) - - def getChild(self, name, request): - return self - -class ChildRedirector(Redirect): - isLeaf = 0 - def __init__(self, url): - # XXX is this enough? - if ((url.find('://') == -1) - and (not url.startswith('..')) - and (not url.startswith('/'))): - raise ValueError("It seems you've given me a redirect (%s) that is a child of myself! That's not good, it'll cause an infinite redirect." % url) - Redirect.__init__(self, url) - - def getChild(self, name, request): - newUrl = self.url - if not newUrl.endswith('/'): - newUrl += '/' - newUrl += name - return ChildRedirector(newUrl) - - -from twisted.python import urlpath - -class ParentRedirect(resource.Resource): - """ - I redirect to URLPath.here(). - """ - isLeaf = 1 - def render(self, request): - return redirectTo(urlpath.URLPath.fromRequest(request).here(), request) - - def getChild(self, request): - return self - - -class DeferredResource(resource.Resource): - """ - I wrap up a Deferred that will eventually result in a Resource - object. - """ - isLeaf = 1 - - def __init__(self, d): - resource.Resource.__init__(self) - self.d = d - - def getChild(self, name, request): - return self - - def render(self, request): - self.d.addCallback(self._cbChild, request).addErrback( - self._ebChild,request) - from twisted.web.server import NOT_DONE_YET - return NOT_DONE_YET - - def _cbChild(self, child, request): - result = resource.getChildForRequest(child, request).render(request) - from twisted.web.server import NOT_DONE_YET - if result == NOT_DONE_YET: - return - else: - request.write(result) - request.finish() - - def _ebChild(self, reason, request): - request.processingFailed(reason) - return reason - - -stylesheet = """ -<style type="text/css"> - p.error { - color: red; - font-family: Verdana, Arial, helvetica, sans-serif; - font-weight: bold; - } - - div { - font-family: Verdana, Arial, helvetica, sans-serif; - } - - div.stackTrace { - } - - div.frame { - padding: 1em; - background: white; - border-bottom: thin black dashed; - } - - div.firstFrame { - padding: 1em; - background: white; - border-top: thin black dashed; - border-bottom: thin black dashed; - } - - div.location { - } - - div.snippet { - margin-bottom: 0.5em; - margin-left: 1em; - background: #FFFFDD; - } - - div.snippetHighlightLine { - color: red; - } - - span.code { - font-family: "Courier New", courier, monotype; - } - - span.function { - font-weight: bold; - font-family: "Courier New", courier, monotype; - } - - table.variables { - border-collapse: collapse; - margin-left: 1em; - } - - td.varName { - vertical-align: top; - font-weight: bold; - padding-left: 0.5em; - padding-right: 0.5em; - } - - td.varValue { - padding-left: 0.5em; - padding-right: 0.5em; - } - - div.variables { - margin-bottom: 0.5em; - } - - span.heading { - font-weight: bold; - } - - div.dict { - background: #cccc99; - padding: 2px; - float: left; - } - - td.dictKey { - background: #ffff99; - font-weight: bold; - } - - td.dictValue { - background: #ffff99; - } - - div.list { - background: #7777cc; - padding: 2px; - float: left; - } - - div.listItem { - background: #9999ff; - } - - div.instance { - background: #cc7777; - padding: 2px; - float: left; - } - - span.instanceName { - font-weight: bold; - display: block; - } - - span.instanceRepr { - background: #ff9999; - font-family: "Courier New", courier, monotype; - } - - div.function { - background: orange; - font-weight: bold; - float: left; - } -</style> -""" - - -def htmlrepr(x): - return htmlReprTypes.get(type(x), htmlUnknown)(x) - -def saferepr(x): - try: - rx = repr(x) - except: - rx = "<repr failed! %s instance at %s>" % (x.__class__, id(x)) - return rx - -def htmlUnknown(x): - return '<code>'+html.escape(saferepr(x))+'</code>' - -def htmlDict(d): - io = StringIO() - w = io.write - w('<div class="dict"><span class="heading">Dictionary instance @ %s</span>' % hex(id(d))) - w('<table class="dict">') - for k, v in d.items(): - - if k == '__builtins__': - v = 'builtin dictionary' - w('<tr><td class="dictKey">%s</td><td class="dictValue">%s</td></tr>' % (htmlrepr(k), htmlrepr(v))) - w('</table></div>') - return io.getvalue() - -def htmlList(l): - io = StringIO() - w = io.write - w('<div class="list"><span class="heading">List instance @ %s</span>' % hex(id(l))) - for i in l: - w('<div class="listItem">%s</div>' % htmlrepr(i)) - w('</div>') - return io.getvalue() - -def htmlInst(i): - if hasattr(i, "__html__"): - s = i.__html__() - else: - s = html.escape(saferepr(i)) - return '''<div class="instance"><span class="instanceName">%s instance @ %s</span> - <span class="instanceRepr">%s</span></div> - ''' % (i.__class__, hex(id(i)), s) - -def htmlString(s): - return html.escape(saferepr(s)) - -def htmlFunc(f): - return ('<div class="function">' + - html.escape("function %s in file %s at line %s" % - (f.__name__, f.func_code.co_filename, - f.func_code.co_firstlineno))+ - '</div>') - -htmlReprTypes = {types.DictType: htmlDict, - types.ListType: htmlList, - types.InstanceType: htmlInst, - types.StringType: htmlString, - types.FunctionType: htmlFunc} - - - -def htmlIndent(snippetLine): - ret = string.replace(string.replace(html.escape(string.rstrip(snippetLine)), - ' ', ' '), - '\t', ' ') - return ret - -def formatFailure(myFailure): - - exceptionHTML = """ -<p class="error">%s: %s</p> -""" - - frameHTML = """ -<div class="location">%s, line %s in <span class="function">%s</span></div> -""" - - snippetLineHTML = """ -<div class="snippetLine"><span class="lineno">%s</span><span class="code">%s</span></div> -""" - - snippetHighlightLineHTML = """ -<div class="snippetHighlightLine"><span class="lineno">%s</span><span class="code">%s</span></div> -""" - - variableHTML = """ -<tr class="varRow"><td class="varName">%s</td><td class="varValue">%s</td></tr> -""" - - if not isinstance(myFailure, failure.Failure): - return html.PRE(str(myFailure)) - io = StringIO() - w = io.write - w(stylesheet) - w('<a href="#tbend">') - w(exceptionHTML % (html.escape(str(myFailure.type)), - html.escape(str(myFailure.value)))) - w('</a>') - w('<div class="stackTrace">') - first = 1 - for method, filename, lineno, localVars, globalVars in myFailure.frames: - if filename == '<string>': - continue - if first: - w('<div class="firstFrame">') - first = 0 - else: - w('<div class="frame">') - w(frameHTML % (filename, lineno, method)) - - w('<div class="snippet">') - textSnippet = '' - for snipLineNo in range(lineno-2, lineno+2): - snipLine = linecache.getline(filename, snipLineNo) - textSnippet += snipLine - snipLine = htmlIndent(snipLine) - if snipLineNo == lineno: - w(snippetHighlightLineHTML % (snipLineNo, snipLine)) - else: - w(snippetLineHTML % (snipLineNo, snipLine)) - w('</div>') - - # Instance variables - for name, var in localVars: - if name == 'self' and hasattr(var, '__dict__'): - usedVars = [ (key, value) for (key, value) in var.__dict__.items() - if re.search(r'\W'+'self.'+key+r'\W', textSnippet) ] - if usedVars: - w('<div class="variables"><b>Self</b>') - w('<table class="variables">') - for key, value in usedVars: - w(variableHTML % (key, htmlrepr(value))) - w('</table></div>') - break - - # Local and global vars - for nm, varList in ('Locals', localVars), ('Globals', globalVars): - usedVars = [ (name, var) for (name, var) in varList - if re.search(r'\W'+name+r'\W', textSnippet) ] - if usedVars: - w('<div class="variables"><b>%s</b><table class="variables">' % nm) - for name, var in usedVars: - w(variableHTML % (name, htmlrepr(var))) - w('</table></div>') - - w('</div>') # frame - w('</div>') # stacktrace - w('<a name="tbend"> </a>') - w(exceptionHTML % (html.escape(str(myFailure.type)), - html.escape(str(myFailure.value)))) - - return io.getvalue() diff --git a/tools/buildbot/pylibs/twisted/web/vhost.py b/tools/buildbot/pylibs/twisted/web/vhost.py deleted file mode 100644 index 433c4b3..0000000 --- a/tools/buildbot/pylibs/twisted/web/vhost.py +++ /dev/null @@ -1,141 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""I am a virtual hosts implementation. -""" - -# System Imports -import string - -# Twisted Imports -from twisted.python import roots - -# Sibling Imports -import resource -import error - -class VirtualHostCollection(roots.Homogenous): - """Wrapper for virtual hosts collection. - - This exists for configuration purposes. - """ - entityType = resource.Resource - - def __init__(self, nvh): - self.nvh = nvh - - def listStaticEntities(self): - return self.nvh.hosts.items() - - def getStaticEntity(self, name): - return self.nvh.hosts.get(self) - - def reallyPutEntity(self, name, entity): - self.nvh.addHost(name, entity) - - def delEntity(self, name): - self.nvh.removeHost(name) - - -class NameVirtualHost(resource.Resource): - """I am a resource which represents named virtual hosts. - """ - - default = None - - def __init__(self): - """Initialize. - """ - resource.Resource.__init__(self) - self.hosts = {} - - def listStaticEntities(self): - return resource.Resource.listStaticEntities(self) + [("Virtual Hosts", VirtualHostCollection(self))] - - def getStaticEntity(self, name): - if name == "Virtual Hosts": - return VirtualHostCollection(self) - else: - return resource.Resource.getStaticEntity(self, name) - - def addHost(self, name, resrc): - """Add a host to this virtual host. - - This will take a host named `name', and map it to a resource - `resrc'. For example, a setup for our virtual hosts would be:: - - nvh.addHost('divunal.com', divunalDirectory) - nvh.addHost('www.divunal.com', divunalDirectory) - nvh.addHost('twistedmatrix.com', twistedMatrixDirectory) - nvh.addHost('www.twistedmatrix.com', twistedMatrixDirectory) - """ - self.hosts[name] = resrc - - def removeHost(self, name): - """Remove a host.""" - del self.hosts[name] - - def _getResourceForRequest(self, request): - """(Internal) Get the appropriate resource for the given host. - """ - hostHeader = request.getHeader('host') - if hostHeader == None: - return self.default or error.NoResource() - else: - host = string.split(string.lower(hostHeader),':')[0] - return (self.hosts.get(host, self.default) - or error.NoResource("host %s not in vhost map" % repr(host))) - - def render(self, request): - """Implementation of resource.Resource's render method. - """ - resrc = self._getResourceForRequest(request) - return resrc.render(request) - - def getChild(self, path, request): - """Implementation of resource.Resource's getChild method. - """ - resrc = self._getResourceForRequest(request) - if resrc.isLeaf: - request.postpath.insert(0,request.prepath.pop(-1)) - return resrc - else: - return resrc.getChildWithDefault(path, request) - -class _HostResource(resource.Resource): - - def getChild(self, path, request): - if ':' in path: - host, port = path.split(':', 1) - port = int(port) - else: - host, port = path, 80 - request.setHost(host, port) - prefixLen = 3+request.isSecure()+4+len(path)+len(request.prepath[-3]) - request.path = '/'+'/'.join(request.postpath) - request.uri = request.uri[prefixLen:] - del request.prepath[:3] - return request.site.getResourceFor(request) - - -class VHostMonsterResource(resource.Resource): - - """ - Use this to be able to record the hostname and method (http vs. https) - in the URL without disturbing your web site. If you put this resource - in a URL http://foo.com/bar then requests to - http://foo.com/bar/http/baz.com/something will be equivalent to - http://foo.com/something, except that the hostname the request will - appear to be accessing will be "baz.com". So if "baz.com" is redirecting - all requests for to foo.com, while foo.com is inaccessible from the outside, - then redirect and url generation will work correctly - """ - def getChild(self, path, request): - if path == 'http': - request.isSecure = lambda: 0 - elif path == 'https': - request.isSecure = lambda: 1 - return _HostResource() - diff --git a/tools/buildbot/pylibs/twisted/web/widgets.py b/tools/buildbot/pylibs/twisted/web/widgets.py deleted file mode 100644 index de2af70..0000000 --- a/tools/buildbot/pylibs/twisted/web/widgets.py +++ /dev/null @@ -1,1050 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_web -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""A twisted web component framework. - -This module is DEPRECATED. -""" - -import warnings -warnings.warn("This module is deprecated, please use Woven instead.", DeprecationWarning) - -# System Imports -import string, time, types, traceback, pprint, sys, os -import linecache -import re -from cStringIO import StringIO - -# Twisted Imports -from twisted.python import failure, log, rebuild, reflect, util -from twisted.internet import defer -from twisted.web import http - -# Sibling Imports -import html, resource, error -import util as webutil - -#backwards compatibility -from util import formatFailure, htmlrepr, htmlUnknown, htmlDict, htmlList,\ - htmlInst, htmlString, htmlReprTypes - - - -from server import NOT_DONE_YET - -True = (1==1) -False = not True - - -# magic value that sez a widget needs to take over the whole page. - -FORGET_IT = 99 - -def listify(x): - return [x] -def _ellipsize(x): - y = repr(x) - if len(y) > 1024: - return y[:1024]+"..." - return y - - -class Widget: - """A component of a web page. - """ - title = None - def getTitle(self, request): - return self.title or reflect.qual(self.__class__) - - def display(self, request): - """Implement me to represent your widget. - - I must return a list of strings and twisted.internet.defer.Deferred - instances. - """ - raise NotImplementedError("%s.display" % reflect.qual(self.__class__)) - -class StreamWidget(Widget): - """A 'streamable' component of a webpage. - """ - - def stream(self, write, request): - """Call 'write' multiple times with a string argument to represent this widget. - """ - raise NotImplementedError("%s.stream" % reflect.qual(self.__class__)) - - def display(self, request): - """Produce a list containing a single string. - """ - l = [] - try: - result = self.stream(l.append, request) - if result is not None: - return result - return l - except: - return [webutil.formatFailure(failure.Failure())] - -class WidgetMixin(Widget): - """A mix-in wrapper for a Widget. - - This mixin can be used to wrap functionality in any other widget with a - method of your choosing. It is designed to be used for mix-in classes that - can be mixed in to Form, StreamWidget, Presentation, etc, to augment the - data available to the 'display' methods of those classes, usually by adding - it to a Session. - """ - - def display(self): - raise NotImplementedError("%s.display" % self.__class__) - - def displayMixedWidget(self, request): - for base in reflect.allYourBase(self.__class__): - if issubclass(base, Widget) and not issubclass(base, WidgetMixin): - return base.display(self, request) - -class Presentation(Widget): - """I am a widget which formats a template with interspersed python expressions. - """ - template = ''' - Hello, %%%%world%%%%. - ''' - world = "you didn't assign to the 'template' attribute" - def __init__(self, template=None, filename=None): - if filename: - self.template = open(filename).read() - elif template: - self.template = template - self.variables = {} - self.tmpl = string.split(self.template, "%%%%") - - def addClassVars(self, namespace, Class): - for base in Class.__bases__: - # Traverse only superclasses that know about Presentation. - if issubclass(base, Presentation) and base is not Presentation: - self.addClassVars(namespace, base) - # 'lower' classes in the class heirarchy take precedence. - for k in Class.__dict__.keys(): - namespace[k] = getattr(self, k) - - def addVariables(self, namespace, request): - self.addClassVars(namespace, self.__class__) - - def prePresent(self, request): - """Perform any tasks which must be done before presenting the page. - """ - - def formatTraceback(self, tb): - return [html.PRE(tb)] - - def streamCall(self, call, *args, **kw): - """Utility: Call a method like StreamWidget's 'stream'. - """ - io = StringIO() - apply(call, (io.write,) + args, kw) - return io.getvalue() - - def display(self, request): - tm = [] - flip = 0 - namespace = {} - self.prePresent(request) - self.addVariables(namespace, request) - # This variable may not be obscured... - namespace['request'] = request - namespace['self'] = self - for elem in self.tmpl: - flip = not flip - if flip: - if elem: - tm.append(elem) - else: - try: - x = eval(elem, namespace, namespace) - except: - log.deferr() - tm.append(webutil.formatFailure(failure.Failure())) - else: - if isinstance(x, types.ListType): - tm.extend(x) - elif isinstance(x, Widget): - val = x.display(request) - if not isinstance(val, types.ListType): - raise Exception("%s.display did not return a list, it returned %s!" % (x.__class__, repr(val))) - tm.extend(val) - else: - # Only two allowed types here should be deferred and - # string. - tm.append(x) - return tm - - -def htmlFor_hidden(write, name, value): - write('<INPUT TYPE="hidden" NAME="%s" VALUE="%s" />' % (name, value)) - -def htmlFor_file(write, name, value): - write('<INPUT SIZE="60" TYPE="file" NAME="%s" />' % name) - -def htmlFor_string(write, name, value): - write('<INPUT SIZE="60" TYPE="text" NAME="%s" VALUE="%s" />' % (name, value)) - -def htmlFor_password(write, name, value): - write('<INPUT SIZE="60" TYPE="password" NAME="%s" />' % name) - -def htmlFor_text(write, name, value): - write('<textarea COLS="60" ROWS="10" NAME="%s" WRAP="virtual">%s</textarea>' % (name, value)) - -def htmlFor_menu(write, name, value, allowMultiple=False): - "Value of the format [(optionName, displayName[, selected]), ...]" - - write(' <select NAME="%s"%s>\n' % - (name, (allowMultiple and " multiple") or '')) - - for v in value: - optionName, displayName, selected = util.padTo(3, v) - selected = (selected and " selected") or '' - write(' <option VALUE="%s"%s>%s</option>\n' % - (optionName, selected, displayName)) - if not value: - write(' <option VALUE=""></option>\n') - write(" </select>\n") - -def htmlFor_multimenu(write, name, value): - "Value of the format [(optionName, displayName[, selected]), ...]" - return htmlFor_menu(write, name, value, True) - -def htmlFor_checkbox(write, name, value): - "A checkbox." - if value: - value = 'checked = "1"' - else: - value = '' - write('<INPUT TYPE="checkbox" NAME="__checkboxes__" VALUE="%s" %s />\n' % (name, value)) - -def htmlFor_checkgroup(write, name, value): - "A check-group." - for optionName, displayName, checked in value: - checked = (checked and 'checked = "1"') or '' - write('<INPUT TYPE="checkbox" NAME="%s" VALUE="%s" %s />%s<br />\n' % (name, optionName, checked, displayName)) - -def htmlFor_radio(write, name, value): - "A radio button group." - for optionName, displayName, checked in value: - checked = (checked and 'checked = "1"') or '' - write('<INPUT TYPE="radio" NAME="%s" VALUE="%s" %s />%s<br />\n' % (name, optionName, checked, displayName)) - -class FormInputError(Exception): - pass - -class Form(Widget): - """I am a web form. - - In order to use me, you probably want to set self.formFields (or override - 'getFormFields') and override 'process'. In order to demonstrate how this - is done, here is a small sample Form subclass:: - - | from twisted.web import widgets - | class HelloForm(widgets.Form): - | formFields = [ - | ['string', 'Who to greet?', 'whoToGreet', 'World', - | 'This is for choosing who to greet.'], - | ['menu', 'How to greet?', 'how', [('cheerfully', 'with a smile'), - | ('sullenly', 'without enthusiasm'), - | ('spontaneously', 'on the spur of the moment')]] - | 'This is for choosing how to greet them.'] - | def process(self, write, request, submit, whoToGreet, how): - | write('The web wakes up and %s says, \"Hello, %s!\"' % (how, whoToGreet)) - - If you load this widget, you will see that it displays a form with 2 inputs - derived from data in formFields. Note the argument names to 'process': - after 'write' and 'request', they are the same as the 3rd elements ('Input - Name' parameters) of the formFields list. - """ - - formGen = { - 'hidden': htmlFor_hidden, - 'file': htmlFor_file, - 'string': htmlFor_string, - 'int': htmlFor_string, - 'float': htmlFor_string, - 'text': htmlFor_text, - 'menu': htmlFor_menu, - 'multimenu': htmlFor_multimenu, - 'password': htmlFor_password, - 'checkbox': htmlFor_checkbox, - 'checkgroup': htmlFor_checkgroup, - 'radio': htmlFor_radio, - } - - formParse = { - 'int': int, - 'float': float, - } - - formFields = [ - ] - - # do we raise an error when we get extra args or not? - formAcceptExtraArgs = 0 - - def getFormFields(self, request, fieldSet = None): - """I return a list of lists describing this form, or a Deferred. - - This information is used both to display the form and to process it. - The list is in the following format:: - - | [['Input Type', 'Display Name', 'Input Name', 'Input Value', 'Description'], - | ['Input Type 2', 'Display Name 2', 'Input Name 2', 'Input Value 2', 'Description 2'] - | ...] - - Valid values for 'Input Type' are: - - - 'hidden': a hidden field that contains a string that the user won't change - - - 'string': a short string - - - 'int': an integer, e.g. 1, 0, 25 or -23 - - - 'float': a float, e.g. 1.0, 2, -3.45, or 28.4324231 - - - 'text': a longer text field, suitable for entering paragraphs - - - 'menu': an HTML SELECT input, a list of choices - - - 'multimenu': an HTML SELECT input allowing multiple choices - - - 'checkgroup': a group of checkboxes - - - 'radio': a group of radio buttons - - - 'password': a 'string' field where the contents are not visible as the user types - - - 'file': a file-upload form (EXPERIMENTAL) - - 'Display Name' is a descriptive string that will be used to - identify the field to the user. - - The 'Input Name' must be a legal Python identifier that describes both - the value's name on the HTML form and the name of an argument to - 'self.process()'. - - The 'Input Value' is usually a string, but its value can depend on the - 'Input Type'. 'int' it is an integer, 'menu' it is a list of pairs of - strings, representing (value, name) pairs for the menu options. Input - value for 'checkgroup' and 'radio' should be a list of ('inputName', - 'Display Name', 'checked') triplets. - - The 'Description' field is an (optional) string which describes the form - item to the user. - - If this result is statically determined for your Form subclass, you can - assign it to FormSubclass.formFields; if you need to determine it - dynamically, you can override this method. - - Note: In many cases it is desirable to use user input for defaults in - the form rather than those supplied by your calculations, which is what - this method will do to self.formFields. If this is the case for you, - but you still need to dynamically calculate some fields, pass your - results back through this method by doing:: - - | def getFormFields(self, request): - | myFormFields = [self.myFieldCalculator()] - | return widgets.Form.getFormFields(self, request, myFormFields) - - """ - fields = [] - if fieldSet is None: - fieldSet = self.formFields - if not self.shouldProcess(request): - return fieldSet - - for field in fieldSet: - if len(field)==5: - inputType, displayName, inputName, inputValue, description = field - else: - inputType, displayName, inputName, inputValue = field - description = "" - - if inputType == 'checkbox': - if request.args.has_key('__checkboxes__'): - if inputName in request.args['__checkboxes__']: - inputValue = 1 - else: - inputValue = 0 - else: - inputValue = 0 - elif inputType in ('checkgroup', 'radio'): - if request.args.has_key(inputName): - keys = request.args[inputName] - else: - keys = [] - iv = inputValue - inputValue = [] - for optionName, optionDisplayName, checked in iv: - checked = optionName in keys - inputValue.append([optionName, optionDisplayName, checked]) - elif request.args.has_key(inputName): - iv = request.args[inputName][0] - if inputType in ['menu', 'multimenu']: - if iv in inputValue: - inputValue.remove(iv) - inputValue.insert(0, iv) - else: - inputValue = iv - fields.append([inputType, displayName, inputName, inputValue, description]) - return fields - - submitNames = ['Submit'] - actionURI = '' - - def format(self, form, write, request): - """I display an HTML FORM according to the result of self.getFormFields. - """ - write('<form ENCTYPE="multipart/form-data" METHOD="post" ACTION="%s">\n' - '<table BORDER="0">\n' % (self.actionURI or request.uri)) - - for field in form: - if len(field) == 5: - inputType, displayName, inputName, inputValue, description = field - else: - inputType, displayName, inputName, inputValue = field - description = "" - write('<tr>\n<td ALIGN="right" VALIGN="top"><B>%s</B></td>\n' - '<td VALIGN="%s">\n' % - (displayName, ((inputType == 'text') and 'top') or 'middle')) - self.formGen[inputType](write, inputName, inputValue) - write('\n<br />\n<font size="-1">%s</font></td>\n</tr>\n' % description) - - - write('<tr><td></td><td ALIGN="left"><hr />\n') - for submitName in self.submitNames: - write('<INPUT TYPE="submit" NAME="submit" VALUE="%s" />\n' % submitName) - write('</td></tr>\n</table>\n' - '<INPUT TYPE="hidden" NAME="__formtype__" VALUE="%s" />\n' - % (reflect.qual(self.__class__))) - fid = self.getFormID() - if fid: - write('<INPUT TYPE="hidden" NAME="__formid__" VALUE="%s" />\n' % fid) - write("</form>\n") - - def getFormID(self): - """Override me: I disambiguate between multiple forms of the same type. - - In order to determine which form an HTTP POST request is for, you must - have some unique identifier which distinguishes your form from other - forms of the same class. An example of such a unique identifier would - be: on a page with multiple FrobConf forms, each FrobConf form refers - to a particular Frobnitz instance, which has a unique id(). The - FrobConf form's getFormID would probably look like this:: - - | def getFormID(self): - | return str(id(self.frobnitz)) - - By default, this method will return None, since distinct Form instances - may be identical as far as the application is concerned. - """ - - def process(self, write, request, submit, **kw): - """Override me: I process a form. - - I will only be called when the correct form input data to process this - form has been received. - - I take a variable number of arguments, beginning with 'write', - 'request', and 'submit'. 'write' is a callable object that will append - a string to the response, 'request' is a twisted.web.request.Request - instance, and 'submit' is the name of the submit action taken. - - The remainder of my arguments must be correctly named. They will each be named after one of the - - """ - write("<pre>Submit: %s <br /> %s</pre>" % (submit, html.PRE(pprint.PrettyPrinter().pformat(kw)))) - - def _doProcess(self, form, write, request): - """(internal) Prepare arguments for self.process. - """ - args = request.args.copy() - kw = {} - for field in form: - inputType, displayName, inputName, inputValue = field[:4] - if inputType == 'checkbox': - if request.args.has_key('__checkboxes__'): - if inputName in request.args['__checkboxes__']: - formData = 1 - else: - formData = 0 - else: - formData = 0 - elif inputType in ['checkgroup', 'radio', 'multimenu']: - if args.has_key(inputName): - formData = args[inputName] - del args[inputName] - else: - formData = [] - else: - if not args.has_key(inputName): - raise FormInputError("missing field %s." % repr(inputName)) - formData = args[inputName] - del args[inputName] - if not len(formData) == 1: - raise FormInputError("multiple values for field %s." %repr(inputName)) - formData = formData[0] - method = self.formParse.get(inputType) - if method: - try: - formData = method(formData) - except: - raise FormInputError("%s: %s" % (displayName, "error")) - kw[inputName] = formData - submitAction = args.get('submit') - if submitAction: - submitAction = submitAction[0] - for field in ['submit', '__formtype__', '__checkboxes__']: - if args.has_key(field): - del args[field] - if args and not self.formAcceptExtraArgs: - raise FormInputError("unknown fields: %s" % repr(args)) - return apply(self.process, (write, request, submitAction), kw) - - def formatError(self,error): - """Format an error message. - - By default, this will make the message appear in red, bold italics. - """ - return '<font color="#f00"><b><i>%s</i></b></font><br />\n' % error - - def shouldProcess(self, request): - args = request.args - fid = self.getFormID() - return (args and # there are arguments to the request - args.has_key('__formtype__') and # this is a widgets.Form request - args['__formtype__'][0] == reflect.qual(self.__class__) and # it is for a form of my type - ((not fid) or # I am only allowed one form per page - (args.has_key('__formid__') and # if I distinguish myself from others, the request must too - args['__formid__'][0] == fid))) # I am in fact the same - - def tryAgain(self, err, req): - """Utility method for re-drawing the form with an error message. - - This is handy in forms that process Deferred results. Normally you can - just raise a FormInputError() and this will happen by default. - - """ - l = [] - w = l.append - w(self.formatError(err)) - self.format(self.getFormFields(req), w, req) - return l - - def display(self, request): - """Display the form.""" - form = self.getFormFields(request) - if isinstance(form, defer.Deferred): - if self.shouldProcess(request): - form.addCallback(lambda form, f=self._displayProcess, r=request: f(r, form)) - else: - form.addCallback(lambda form, f=self._displayFormat, r=request: f(r, form)) - return [form] - else: - if self.shouldProcess(request): - return self._displayProcess(request, form) - else: - return self._displayFormat(request, form) - - def _displayProcess(self, request, form): - l = [] - write = l.append - try: - val = self._doProcess(form, write, request) - if val: - l.extend(val) - except FormInputError, fie: - write(self.formatError(str(fie))) - return l - - def _displayFormat(self, request, form): - l = [] - self.format(form, l.append, request) - return l - - - -class DataWidget(Widget): - def __init__(self, data): - self.data = data - def display(self, request): - return [self.data] - -class Time(Widget): - def display(self, request): - return [time.ctime(time.time())] - -class Container(Widget): - def __init__(self, *widgets): - self.widgets = widgets - - def display(self, request): - value = [] - for widget in self.widgets: - d = widget.display(request) - value.extend(d) - return value - -class _RequestDeferral: - def __init__(self): - self.deferred = defer.Deferred() - self.io = StringIO() - self.write = self.io.write - - def finish(self): - self.deferred.callback([self.io.getvalue()]) - -def possiblyDeferWidget(widget, request): - # web in my head get it out get it out - try: - disp = widget.display(request) - # if this widget wants to defer anything -- well, I guess we've got to - # defer it. - for elem in disp: - if isinstance(elem, defer.Deferred): - req = _RequestDeferral() - RenderSession(disp, req) - return req.deferred - return string.join(disp, '') - except: - io = StringIO() - traceback.print_exc(file=io) - return html.PRE(io.getvalue()) - -class RenderSession: - """I handle rendering of a list of deferreds, outputting their - results in correct order.""" - - class Sentinel: - pass - - def __init__(self, lst, request): - self.lst = lst - self.request = request - self.needsHeaders = 0 - self.beforeBody = 1 - self.forgotten = 0 - self.pauseList = [] - for i in range(len(self.lst)): - item = self.lst[i] - if isinstance(item, defer.Deferred): - self._addDeferred(item, self.lst, i) - self.keepRendering() - - def _addDeferred(self, deferred, lst, idx): - sentinel = self.Sentinel() - if hasattr(deferred, 'needsHeader'): - # You might want to set a header from a deferred, in which - # case you have to set an attribute -- needsHeader. - self.needsHeaders = self.needsHeaders + 1 - args = (sentinel, 1) - else: - args = (sentinel, 0) - lst[idx] = sentinel, deferred - deferred.pause() - self.pauseList.append(deferred) - deferred.addCallbacks(self.callback, self.callback, - callbackArgs=args, errbackArgs=args) - - - def callback(self, result, sentinel, decNeedsHeaders): - if self.forgotten: - return - if result != FORGET_IT: - self.needsHeaders = self.needsHeaders - decNeedsHeaders - else: - result = [FORGET_IT] - - # Make sure result is a sequence, - if not type(result) in (types.ListType, types.TupleType): - result = [result] - - # If the deferred does not wish to produce its result all at - # once, it can give us a partial result as - # (NOT_DONE_YET, partial_result) - ## XXX: How would a deferred go about producing the result in multiple - ## stages?? --glyph - if result[0] is NOT_DONE_YET: - done = 0 - result = result[1] - if not type(result) in (types.ListType, types.TupleType): - result = [result] - else: - done = 1 - - for i in xrange(len(result)): - item = result[i] - if isinstance(item, defer.Deferred): - self._addDeferred(item, result, i) - - for position in range(len(self.lst)): - item = self.lst[position] - if type(item) is types.TupleType and len(item) > 0: - if item[0] is sentinel: - break - else: - raise AssertionError('Sentinel for Deferred not found!') - - if done: - self.lst[position:position+1] = result - else: - self.lst[position:position] = result - - self.keepRendering() - - - def keepRendering(self): - while self.pauseList: - pl = self.pauseList - self.pauseList = [] - for deferred in pl: - deferred.unpause() - return - - if self.needsHeaders: - # short circuit actual rendering process until we're sure no - # more deferreds need to set headers... - return - - assert self.lst is not None, "This shouldn't happen." - while 1: - item = self.lst[0] - if self.beforeBody and FORGET_IT in self.lst: - # If I haven't moved yet, and the widget wants to take - # over the page, let it do so! - self.forgotten = 1 - return - - if isinstance(item, types.StringType): - self.beforeBody = 0 - self.request.write(item) - elif type(item) is types.TupleType and len(item) > 0: - if isinstance(item[0], self.Sentinel): - return - elif isinstance(item, failure.Failure): - self.request.write(webutil.formatFailure(item)) - else: - self.beforeBody = 0 - unknown = html.PRE(repr(item)) - self.request.write("RENDERING UNKNOWN: %s" % unknown) - - del self.lst[0] - if len(self.lst) == 0: - self.lst = None - self.request.finish() - return - - -## XXX: is this needed? -class WidgetResource(resource.Resource): - def __init__(self, widget): - self.widget = widget - resource.Resource.__init__(self) - - def render(self, request): - RenderSession(self.widget.display(request), request) - return NOT_DONE_YET - - -class Page(resource.Resource, Presentation): - - def __init__(self): - resource.Resource.__init__(self) - Presentation.__init__(self) - - def render(self, request): - displayed = self.display(request) - RenderSession(displayed, request) - return NOT_DONE_YET - - -class WidgetPage(Page): - """ - I am a Page that takes a Widget in its constructor, and displays that - Widget wrapped up in a simple HTML template. - """ - stylesheet = ''' - a - { - font-family: Lucida, Verdana, Helvetica, Arial, sans-serif; - color: #369; - text-decoration: none; - } - - th - { - font-family: Lucida, Verdana, Helvetica, Arial, sans-serif; - font-weight: bold; - text-decoration: none; - text-align: left; - } - - pre, code - { - font-family: "Courier New", Courier, monospace; - } - - p, body, td, ol, ul, menu, blockquote, div - { - font-family: Lucida, Verdana, Helvetica, Arial, sans-serif; - color: #000; - } - ''' - - template = '''<html> - <head> - <title>%%%%self.title%%%%</title> - <style> - %%%%self.stylesheet%%%% - </style> - <base href="%%%%request.prePathURL()%%%%"> - </head> - - <body> - <h1>%%%%self.title%%%%</h1> - %%%%self.widget%%%% - </body> - </html> - ''' - - title = 'No Title' - widget = 'No Widget' - - def __init__(self, widget): - Page.__init__(self) - self.widget = widget - if hasattr(widget, 'stylesheet'): - self.stylesheet = widget.stylesheet - - def prePresent(self, request): - self.title = self.widget.getTitle(request) - - def render(self, request): - displayed = self.display(request) - RenderSession(displayed, request) - return NOT_DONE_YET - -class Gadget(resource.Resource): - """I am a collection of Widgets, to be rendered through a Page Factory. - self.pageFactory should be a Resource that takes a Widget in its - constructor. The default is twisted.web.widgets.WidgetPage. - """ - - isLeaf = 0 - - def __init__(self): - resource.Resource.__init__(self) - self.widgets = {} - self.files = [] - self.modules = [] - self.paths = {} - - def render(self, request): - #Redirect to view this entity as a collection. - request.setResponseCode(http.FOUND) - # TODO who says it's not https? - request.setHeader("location","http%s://%s%s/" % ( - request.isSecure() and 's' or '', - request.getHeader("host"), - (string.split(request.uri,'?')[0]))) - return "NO DICE!" - - def putWidget(self, path, widget): - """ - Gadget.putWidget(path, widget) - Add a Widget to this Gadget. It will be rendered through the - pageFactory associated with this Gadget, whenever 'path' is requested. - """ - self.widgets[path] = widget - - #this is an obsolete function - def addFile(self, path): - """ - Gadget.addFile(path) - Add a static path to this Gadget. This method is obsolete, use - Gadget.putPath instead. - """ - - log.msg("Gadget.addFile() is deprecated.") - self.paths[path] = path - - def putPath(self, path, pathname): - """ - Gadget.putPath(path, pathname) - Add a static path to this Gadget. Whenever 'path' is requested, - twisted.web.static.File(pathname) is sent. - """ - self.paths[path] = pathname - - def getWidget(self, path, request): - return self.widgets.get(path) - - def pageFactory(self, *args, **kwargs): - """ - Gadget.pageFactory(*args, **kwargs) -> Resource - By default, this method returns self.page(*args, **kwargs). It - is only for backwards-compatibility -- you should set the 'pageFactory' - attribute on your Gadget inside of its __init__ method. - """ - #XXX: delete this after a while. - if hasattr(self, "page"): - log.msg("Gadget.page is deprecated, use Gadget.pageFactory instead") - return apply(self.page, args, kwargs) - else: - return apply(WidgetPage, args, kwargs) - - def getChild(self, path, request): - if path == '': - # ZOOP! - if isinstance(self, Widget): - return self.pageFactory(self) - widget = self.getWidget(path, request) - if widget: - if isinstance(widget, resource.Resource): - return widget - else: - p = self.pageFactory(widget) - p.isLeaf = getattr(widget,'isLeaf',0) - return p - elif self.paths.has_key(path): - prefix = getattr(sys.modules[self.__module__], '__file__', '') - if prefix: - prefix = os.path.abspath(os.path.dirname(prefix)) - return static.File(os.path.join(prefix, self.paths[path])) - - elif path == '__reload__': - return self.pageFactory(Reloader(map(reflect.namedModule, [self.__module__] + self.modules))) - else: - return error.NoResource("No such child resource in gadget.") - - -class TitleBox(Presentation): - - template = '''\ -<table %%%%self.widthOption%%%% cellpadding="1" cellspacing="0" border="0"><tr>\ -<td bgcolor="%%%%self.borderColor%%%%"><center><font color="%%%%self.titleTextColor%%%%">%%%%self.title%%%%</font></center>\ -<table width="100%" cellpadding="3" cellspacing="0" border="0"><tr>\ -<td bgcolor="%%%%self.boxColor%%%%"><font color="%%%%self.boxTextColor%%%%">%%%%self.widget%%%%</font></td>\ -</tr></table></td></tr></table>\ -''' - - borderColor = '#000000' - titleTextColor = '#ffffff' - boxTextColor = '#000000' - boxColor = '#ffffff' - widthOption = 'width="100%"' - - title = 'No Title' - widget = 'No Widget' - - def __init__(self, title, widget): - """Wrap a widget with a given title. - """ - self.widget = widget - self.title = title - Presentation.__init__(self) - - -class Reloader(Presentation): - template = ''' - Reloading... - <ul> - %%%%reload(request)%%%% - </ul> ... reloaded! - ''' - def __init__(self, modules): - Presentation.__init__(self) - self.modules = modules - - def reload(self, request): - request.redirect("..") - x = [] - write = x.append - for module in self.modules: - rebuild.rebuild(module) - write('<li>reloaded %s<br />' % module.__name__) - return x - -class Sidebar(StreamWidget): - bar = [ - ['Twisted', - ['mirror', 'http://coopweb.org/ssd/twisted/'], - ['mailing list', 'cgi-bin/mailman/listinfo/twisted-python'] - ] - ] - - headingColor = 'ffffff' - headingTextColor = '000000' - activeHeadingColor = '000000' - activeHeadingTextColor = 'ffffff' - sectionColor = '000088' - sectionTextColor = '008888' - activeSectionColor = '0000ff' - activeSectionTextColor = '00ffff' - - def __init__(self, highlightHeading, highlightSection): - self.highlightHeading = highlightHeading - self.highlightSection = highlightSection - - def getList(self): - return self.bar - - def stream(self, write, request): - write("<table width=120 cellspacing=1 cellpadding=1 border=0>") - for each in self.getList(): - if each[0] == self.highlightHeading: - headingColor = self.activeHeadingColor - headingTextColor = self.activeHeadingTextColor - canHighlight = 1 - else: - headingColor = self.headingColor - headingTextColor = self.headingTextColor - canHighlight = 0 - write('<tr><td colspan=2 bgcolor="#%s"><font color="%s">' - '<strong>%s</strong>' - '</font></td></td></tr>\n' % (headingColor, headingTextColor, each[0])) - for name, link in each[1:]: - if canHighlight and (name == self.highlightSection): - sectionColor = self.activeSectionColor - sectionTextColor = self.activeSectionTextColor - else: - sectionColor = self.sectionColor - sectionTextColor = self.sectionTextColor - write('<tr><td align=right bgcolor="#%s" width=6>-</td>' - '<td bgcolor="#%s"><a href="%s"><font color="#%s">%s' - '</font></a></td></tr>' - % (sectionColor, sectionColor, request.sibLink(link), sectionTextColor, name)) - write("</table>") - -# moved from template.py -from twisted.web.woven import template -from twisted.python import components - -class WebWidgetNodeMutator(template.NodeMutator): - """A WebWidgetNodeMutator replaces the node that is passed in to generate - with the result of generating the twisted.web.widget instance it adapts. - """ - def generate(self, request, node): - widget = self.data - displayed = widget.display(request) - try: - html = string.join(displayed) - except: - pr = Presentation() - pr.tmpl = displayed - #strList = pr.display(request) - html = string.join(displayed) - stringMutator = template.StringNodeMutator(html) - return stringMutator.generate(request, node) - -components.registerAdapter(WebWidgetNodeMutator, Widget, template.INodeMutator) - -import static diff --git a/tools/buildbot/pylibs/twisted/web/woven/FlashConduit.fla b/tools/buildbot/pylibs/twisted/web/woven/FlashConduit.fla Binary files differdeleted file mode 100644 index 7406364..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/FlashConduit.fla +++ /dev/null diff --git a/tools/buildbot/pylibs/twisted/web/woven/FlashConduit.swf b/tools/buildbot/pylibs/twisted/web/woven/FlashConduit.swf Binary files differdeleted file mode 100644 index 6e0c6cd..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/FlashConduit.swf +++ /dev/null diff --git a/tools/buildbot/pylibs/twisted/web/woven/FlashConduitGlue.html b/tools/buildbot/pylibs/twisted/web/woven/FlashConduitGlue.html deleted file mode 100644 index 1dc6367..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/FlashConduitGlue.html +++ /dev/null @@ -1,25 +0,0 @@ -<div> - <script language="javascript" src="WebConduit2_js"> - . - </script> - <iframe style="width: 0; height: 0" id="woven_inputConduit" src="input_html"> - . - </iframe> -<!-- <iframe style="width: 100%" id="woven_outputConduit" src="?woven_hookupOutputConduitToThisFrame=1"> - </iframe>--> -<OBJECT classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" - codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0" - WIDTH="0" HEIGHT="0" id="FlashConduit_swf" ALIGN=""> - <PARAM NAME="movie" value="FlashConduit_swf" view="woven_flashConduitSessionView" /> - <PARAM NAME="quality" VALUE="high" /> - <PARAM NAME="bgcolor" VALUE="#FFFFFF" /> - <EMBED view="woven_flashConduitSessionView" src="FlashConduit_swf" name="FlashConduit_swf" swLiveConnect="true" - quality="high" bgcolor="#FFFFFF" WIDTH="0" HEIGHT="0" NAME="FlashConduit_swf" ALIGN="" - TYPE="application/x-shockwave-flash" PLUGINSPAGE="http://www.macromedia.com/go/getflashplayer"> - <!-- if neither object nor embed works, this should... --> -<!-- <iframe style="width: 100%" id="woven_outputConduit" src="?woven_hookupOutputConduitToThisFrame=1"> - </iframe> ---> - </EMBED> -</OBJECT> -</div> diff --git a/tools/buildbot/pylibs/twisted/web/woven/WebConduit2_mozilla.js b/tools/buildbot/pylibs/twisted/web/woven/WebConduit2_mozilla.js deleted file mode 100644 index 97dc118..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/WebConduit2_mozilla.js +++ /dev/null @@ -1,82 +0,0 @@ -var woven_eventQueue = [] -woven_eventQueueBusy = 0 -woven_clientSideEventNum = 0 -woven_requestingEvent = 0 - -function woven_eventHandler(eventName, node) { - var eventTarget = node.getAttribute('id') - var additionalArguments = '' - for (i = 2; i<arguments.length; i++) { - additionalArguments += '&woven_clientSideEventArguments=' - additionalArguments += escape(eval(arguments[i])) - } - var source = '?woven_clientSideEventName=' + eventName + '&woven_clientSideEventTarget=' + eventTarget + additionalArguments + '&woven_clientSideEventNum=' + woven_clientSideEventNum - woven_clientSideEventNum += 1 - - woven_eventQueue.unshift(source) - if (!woven_eventQueueBusy) { - woven_sendTopEvent() - } - return false -} - -function woven_sendTopEvent() { - woven_eventQueueBusy = 1 - var url = woven_eventQueue.shift() - var input = document.getElementById('woven_inputConduit') - - input.src = url -} - -function woven_requestNextEvent() { - var output = document.getElementById('woven_outputConduit') - - if (output) { output.src = '?woven_hookupOutputConduitToThisFrame=1&woven_clientSideEventNum=' + woven_clientSideEventNum.toString()} -} - -function woven_clientToServerEventComplete() { - woven_requestNextEvent() - - if (woven_eventQueue.length) { - woven_sendTopEvent() - } else { - woven_eventQueueBusy = 0 - } - var focus = document.getElementById('woven_firstResponder') - focus.focus() -} - -function woven_attemptFocus(theNode) { - // focus the first input element in the new node - if (theNode.tagName == 'INPUT') { - theNode.focus() - return 1 - } else { -/* for (i=0; i<theNode.childNodes.length; i++) { */ -/* if(woven_attemptFocus(theNode.childNodes[i])) { */ -/* return 1 */ -/* } */ -/* } */ - return 0 - } -} - -function woven_replaceElement(theId, htmlStr) { - - var oldNode = document.getElementById(theId) - var newNode = document.createElement('span') - newNode.innerHTML = htmlStr - oldNode.parentNode.replaceChild(newNode.firstChild, oldNode) - //woven_attemptFocus(newNode) - woven_requestNextEvent() - //alert('blah') -} - -function woven_appendChild(theId, htmlStr) { - woven_requestNextEvent() - - var container = document.getElementById(theId) - var newNode = document.createElement('span') - newNode.innerHTML = htmlStr - container.appendChild(newNode.firstChild) -} diff --git a/tools/buildbot/pylibs/twisted/web/woven/WebConduit2_msie.js b/tools/buildbot/pylibs/twisted/web/woven/WebConduit2_msie.js deleted file mode 100644 index 9d281bb..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/WebConduit2_msie.js +++ /dev/null @@ -1,105 +0,0 @@ -var InternetExplorer = navigator.appName.indexOf('Microsoft') != 1 -function FlashConduit_swf_DoFSCommand(command, args) { - eval(args) -} - -if (InternetExplorer) { - if (navigator.userAgent.indexOf('Windows') != -1) { - document.write('<SCRIPT LANGUAGE=VBScript\>\n') - document.write('on error resume next\n') - document.write('Sub FlashConduit_swf_FSCommand(ByVal command, ByVal args)\n') - document.write('call FlashConduit_swf_DoFSCommand(command, args)\n') - document.write('end sub\n') - document.write('</SCRIPT\>\n') - } - -} - -var woven_eventQueue = [] -woven_eventQueueBusy = 0 -woven_clientSideEventNum = 0 - -function woven_eventHandler(eventName, node) { - var eventTarget = node.getAttribute('id') - var additionalArguments = '' - for (i = 2; i<arguments.length; i++) { - additionalArguments += '&woven_clientSideEventArguments=' - additionalArguments += escape(eval(arguments[i])) - } - var source = '?woven_clientSideEventName=' + eventName + '&woven_clientSideEventTarget=' + eventTarget + additionalArguments + '&woven_clientSideEventNum=' + woven_clientSideEventNum - woven_clientSideEventNum += 1 - - woven_eventQueue = woven_eventQueue.concat(source) - if (!woven_eventQueueBusy) { - woven_sendTopEvent() - } - return false -} - -function woven_sendTopEvent() { - woven_eventQueueBusy = 1 - var url = woven_eventQueue[0] - woven_eventQueue = woven_eventQueue.slice(1) - var input = document.getElementById('woven_inputConduit') - - input.src = url -} - -function woven_clientToServerEventComplete() { - if (this.woven_eventQueue.length) { - this.woven_sendTopEvent() - } else { - this.woven_eventQueueBusy = 0 - } - var focus = document.getElementById('woven_firstResponder') - if (focus) { - focus.focus() - if (focus.getAttribute('clearOnFocus')) { - focus.value='' - } - } - document.scrollTop = 999999999 -} - -function woven_attemptFocus(theNode) { - // focus the first input element in the new node - if (theNode.tagName == 'INPUT') { - theNode.focus() - return 1 - } else { -/* for (i=0; i<theNode.childNodes.length; i++) { */ -/* if(woven_attemptFocus(theNode.childNodes[i])) { */ -/* return 1 */ -/* } */ -/* } */ - return 0 - } -} - -function woven_replaceElement(theId, htmlStr) { - //alert(woven_eventQueue.length) - var oldNode = document.getElementById(theId) - if (oldNode) { - if (oldNode.parentNode) { - var created = document.createElement('span') - created.innerHTML = htmlStr - if (created.firstChild) { - oldNode.parentNode.replaceChild(created.firstChild, oldNode) - var newNode = document.getElementById(theId) - //woven_attemptFocus(newNode) - } - } - } -} - -function woven_appendChild(theId, htmlStr) { - var container = document.getElementById(theId) - var newNode = document.createElement('span') - newNode.innerHTML = htmlStr - container.appendChild(newNode.firstChild) -} - -function woven_removeChild(theId) { - var theElement = document.getElementById(theId) - theElement.parentNode.removeChild(theElement) -} diff --git a/tools/buildbot/pylibs/twisted/web/woven/WebConduitGlue.html b/tools/buildbot/pylibs/twisted/web/woven/WebConduitGlue.html deleted file mode 100644 index ba02e15..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/WebConduitGlue.html +++ /dev/null @@ -1,11 +0,0 @@ -<div> - <script language="javascript" src="WebConduit2_js"> - . - </script> - <iframe style="width: 0; height: 0" id="woven_inputConduit" src="input_html"> - . - </iframe> - <iframe style="width: 100%" id="woven_outputConduit" src="?woven_hookupOutputConduitToThisFrame=1"> - . - </iframe> -</div> diff --git a/tools/buildbot/pylibs/twisted/web/woven/__init__.py b/tools/buildbot/pylibs/twisted/web/woven/__init__.py deleted file mode 100644 index 51dfd75..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# __init__.py - -"""Woven, the Web Object Visualization Environment.""" diff --git a/tools/buildbot/pylibs/twisted/web/woven/controller.py b/tools/buildbot/pylibs/twisted/web/woven/controller.py deleted file mode 100644 index a7aca0c..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/controller.py +++ /dev/null @@ -1,436 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_woven -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from __future__ import nested_scopes - -__version__ = "$Revision: 1.67 $"[11:-2] - -import os -import cgi -import types - -from twisted.python import log -from twisted.python import components -from twisted.python import failure -from zope.interface import implements -from twisted.web import resource, server, static -from twisted.web.woven import interfaces, utils -from twisted.web import woven -from twisted.web import microdom -from twisted.web.static import redirectTo, addSlash - -import warnings -from time import time as now - -def controllerFactory(controllerClass): - return lambda request, node, model: controllerClass(model) - -def controllerMethod(controllerClass): - return lambda self, request, node, model: controllerClass(model) - - -class Controller(resource.Resource): - """ - A Controller which handles to events from the user. Such events - are `web request', `form submit', etc. - - I should be the IResource implementor for your Models (and - L{registerControllerForModel} makes this so). - """ - - implements(interfaces.IController) - setupStacks = 1 - addSlash = 1 # Should this controller add a slash to the url automatically? - controllerLibraries = [] - viewFactory = None - templateDirectory = "" - def __init__(self, m, inputhandlers=None, view=None, controllers=None, templateDirectory = None): - #self.start = now() - resource.Resource.__init__(self) - self.model = m - # It's the responsibility of the calling code to make sure setView is - # called on this controller before it's rendered. - self.view = None - self.subcontrollers = [] - if self.setupStacks: - self.setupControllerStack() - if inputhandlers is None and controllers is None: - self._inputhandlers = [] - elif inputhandlers: - print "The inputhandlers arg is deprecated, please use controllers instead" - self._inputhandlers = inputhandlers - else: - self._inputhandlers = controllers - if templateDirectory is not None: - self.templateDirectory = templateDirectory - self._valid = {} - self._invalid = {} - self._process = {} - self._parent = None - - def setupControllerStack(self): - self.controllerStack = utils.Stack([]) - from twisted.web.woven import input - if input not in self.controllerLibraries: - self.controllerLibraries.append(input) - for library in self.controllerLibraries: - self.importControllerLibrary(library) - self.controllerStack.push(self) - - def importControllerLibrary(self, namespace): - if not hasattr(namespace, 'getSubcontroller'): - namespace.getSubcontroller = utils.createGetFunction(namespace) - self.controllerStack.push(namespace) - - def getSubcontroller(self, request, node, model, controllerName): - controller = None - cm = getattr(self, 'wcfactory_' + - controllerName, None) - if cm is None: - cm = getattr(self, 'factory_' + - controllerName, None) - if cm is not None: - warnings.warn("factory_ methods are deprecated; please use " - "wcfactory_ instead", DeprecationWarning) - if cm: - if cm.func_code.co_argcount == 1 and not type(cm) == types.LambdaType: - warnings.warn("A Controller Factory takes " - "(request, node, model) " - "now instead of (model)", DeprecationWarning) - controller = controllerFactory(model) - else: - controller = cm(request, node, model) - return controller - - def setSubcontrollerFactory(self, name, factory, setup=None): - setattr(self, "wcfactory_" + name, lambda request, node, m: - factory(m)) - - def setView(self, view): - self.view = view - - def setNode(self, node): - self.node = node - - def setUp(self, request, *args): - """ - @type request: L{twisted.web.server.Request} - """ - pass - - def getChild(self, name, request): - """ - Look for a factory method to create the object to handle the - next segment of the URL. If a wchild_* method is found, it will - be called to produce the Resource object to handle the next - segment of the path. If a wchild_* method is not found, - getDynamicChild will be called with the name and request. - - @param name: The name of the child being requested. - @type name: string - @param request: The HTTP request being handled. - @type request: L{twisted.web.server.Request} - """ - if not name: - method = "index" - else: - method = name.replace('.', '_') - f = getattr(self, "wchild_%s" % method, None) - if f: - return f(request) - else: - child = self.getDynamicChild(name, request) - if child is None: - return resource.Resource.getChild(self, name, request) - else: - return child - - def getDynamicChild(self, name, request): - """ - This method is called when getChild cannot find a matching wchild_* - method in the Controller. Override me if you wish to have dynamic - handling of child pages. Should return a Resource if appropriate. - Return None to indicate no resource found. - - @param name: The name of the child being requested. - @type name: string - @param request: The HTTP request being handled. - @type request: L{twisted.web.server.Request} - """ - pass - - def wchild_index(self, request): - """By default, we return ourself as the index. - Override this to provide different behavior - for a URL that ends in a slash. - """ - self.addSlash = 0 - return self - - def render(self, request): - """ - Trigger any inputhandlers that were passed in to this Page, - then delegate to the View for traversing the DOM. Finally, - call gatheredControllers to deal with any InputHandlers that - were constructed from any controller= tags in the - DOM. gatheredControllers will render the page to the browser - when it is done. - """ - if self.addSlash and request.uri.split('?')[0][-1] != '/': - return redirectTo(addSlash(request), request) - # Handle any inputhandlers that were passed in to the controller first - for ih in self._inputhandlers: - ih._parent = self - ih.handle(request) - self._inputhandlers = [] - for key, value in self._valid.items(): - key.commit(request, None, value) - self._valid = {} - return self.renderView(request) - - def makeView(self, model, templateFile=None, parentCount=0): - if self.viewFactory is None: - self.viewFactory = self.__class__ - v = self.viewFactory(model, templateFile=templateFile, templateDirectory=self.templateDirectory) - v.parentCount = parentCount - v.tapestry = self - v.importViewLibrary(self) - return v - - def renderView(self, request): - if self.view is None: - if self.viewFactory is not None: - self.setView(self.makeView(self.model, None)) - else: - self.setView(interfaces.IView(self.model, None)) - self.view.setController(self) - return self.view.render(request, doneCallback=self.gatheredControllers) - - def gatheredControllers(self, v, d, request): - process = {} - request.args = {} - for key, value in self._valid.items(): - key.commit(request, None, value) - process[key.submodel] = value - self.process(request, **process) - #log.msg("Sending page!") - self.pageRenderComplete(request) - utils.doSendPage(v, d, request) - #v.unlinkViews() - - #print "Page time: ", now() - self.start - #return view.View.render(self, request, block=0) - - def aggregateValid(self, request, input, data): - self._valid[input] = data - - def aggregateInvalid(self, request, input, data): - self._invalid[input] = data - - def process(self, request, **kwargs): - if kwargs: - log.msg("Processing results: ", kwargs) - - def setSubmodel(self, submodel): - self.submodel = submodel - - def handle(self, request): - """ - By default, we don't do anything - """ - pass - - def exit(self, request): - """We are done handling the node to which this controller was attached. - """ - pass - - def domChanged(self, request, widget, node): - parent = getattr(self, '_parent', None) - if parent is not None: - parent.domChanged(request, widget, node) - - def pageRenderComplete(self, request): - """Override this to recieve notification when the view rendering - process is complete. - """ - pass - -WOVEN_PATH = os.path.split(woven.__file__)[0] - -class LiveController(Controller): - """A Controller that encapsulates logic that makes it possible for this - page to be "Live". A live page can have it's content updated after the - page has been sent to the browser, and can translate client-side - javascript events into server-side events. - """ - pageSession = None - def render(self, request): - """First, check to see if this request is attempting to hook up the - output conduit. If so, do it. Otherwise, unlink the current session's - View from the MVC notification infrastructure, then render the page - normally. - """ - # Check to see if we're hooking up an output conduit - sess = request.getSession(interfaces.IWovenLivePage) - #print "REQUEST.ARGS", request.args - if request.args.has_key('woven_hookupOutputConduitToThisFrame'): - sess.hookupOutputConduit(request) - return server.NOT_DONE_YET - if request.args.has_key('woven_clientSideEventName'): - try: - request.d = microdom.parseString('<xml/>', caseInsensitive=0, preserveCase=0) - eventName = request.args['woven_clientSideEventName'][0] - eventTarget = request.args['woven_clientSideEventTarget'][0] - eventArgs = request.args.get('woven_clientSideEventArguments', []) - #print "EVENT", eventName, eventTarget, eventArgs - return self.clientToServerEvent(request, eventName, eventTarget, eventArgs) - except: - fail = failure.Failure() - self.view.renderFailure(fail, request) - return server.NOT_DONE_YET - - # Unlink the current page in this user's session from MVC notifications - page = sess.getCurrentPage() - #request.currentId = getattr(sess, 'currentId', 0) - if page is not None: - page.view.unlinkViews() - sess.setCurrentPage(None) - #print "PAGE SESSION IS NONE" - self.pageSession = None - return Controller.render(self, request) - - def clientToServerEvent(self, request, eventName, eventTarget, eventArgs): - """The client sent an asynchronous event to the server. - Locate the View object targeted by this event and attempt - to call onEvent on it. - """ - sess = request.getSession(interfaces.IWovenLivePage) - self.view = sess.getCurrentPage().view - #request.d = self.view.d - print "clientToServerEvent", eventTarget - target = self.view.subviews[eventTarget] - print "target, parent", target, target.parent - #target.parent = self.view - #target.controller._parent = self - - ## From the time we call onEvent until it returns, we want all - ## calls to IWovenLivePage.sendScript to be appended to this - ## list so we can spit them out in the response, immediately - ## below. - scriptOutput = [] - orig = sess.sendScript - sess.sendScript = scriptOutput.append - target.onEvent(request, eventName, *eventArgs) - sess.sendScript = orig - - scriptOutput.append('parent.woven_clientToServerEventComplete()') - - #print "GATHERED JS", scriptOutput - - return '''<html> -<body> - <script language="javascript"> - %s - </script> - %s event sent to %s (%s) with arguments %s. -</body> -</html>''' % ('\n'.join(scriptOutput), eventName, cgi.escape(str(target)), eventTarget, eventArgs) - - def gatheredControllers(self, v, d, request): - Controller.gatheredControllers(self, v, d, request) - sess = request.getSession(interfaces.IWovenLivePage) - self.pageSession = sess - sess.setCurrentPage(self) - sess.currentId = request.currentId - - def domChanged(self, request, widget, node): - sess = request.getSession(interfaces.IWovenLivePage) - print "domchanged" - if sess is not None: - if not hasattr(node, 'getAttribute'): - return - page = sess.getCurrentPage() - if page is None: - return - nodeId = node.getAttribute('id') - #logger.warn("DOM for %r is changing to %s", nodeId, node.toprettyxml()) - nodeXML = node.toxml() - nodeXML = nodeXML.replace("\\", "\\\\") - nodeXML = nodeXML.replace("'", "\\'") - nodeXML = nodeXML.replace('"', '\\"') - nodeXML = nodeXML.replace('\n', '\\n') - nodeXML = nodeXML.replace('\r', ' ') - nodeXML = nodeXML.replace('\b', ' ') - nodeXML = nodeXML.replace('\t', ' ') - nodeXML = nodeXML.replace('\000', ' ') - nodeXML = nodeXML.replace('\v', ' ') - nodeXML = nodeXML.replace('\f', ' ') - - js = "parent.woven_replaceElement('%s', '%s')" % (nodeId, nodeXML) - #for key in widget.subviews.keys(): - # view.subviews[key].unlinkViews() - oldNode = page.view.subviews[nodeId] - for id, subview in oldNode.subviews.items(): - subview.unlinkViews() - topSubviews = page.view.subviews - #print "Widgetid, subviews", id(widget), widget.subviews - if widget.subviews: - def recurseSubviews(w): - #print "w.subviews", w.subviews - topSubviews.update(w.subviews) - for id, sv in w.subviews.items(): - recurseSubviews(sv) - #print "recursing" - recurseSubviews(widget) - #page.view.subviews.update(widget.subviews) - sess.sendScript(js) - - def wchild_WebConduit2_js(self, request): - #print "returning js file" - h = request.getHeader("user-agent") - if h.count("MSIE"): - fl = "WebConduit2_msie.js" - else: - fl = "WebConduit2_mozilla.js" - - return static.File(os.path.join(WOVEN_PATH, fl)) - - def wchild_FlashConduit_swf(self, request): - #print "returning flash file" - h = request.getHeader("user-agent") - if h.count("MSIE"): - fl = "FlashConduit.swf" - else: - fl = "FlashConduit.swf" - return static.File(os.path.join(WOVEN_PATH, fl)) - - def wchild_input_html(self, request): - return BlankPage() - - -class BlankPage(resource.Resource): - def render(self, request): - return "<html>This space intentionally left blank</html>" - - -WController = Controller - -def registerControllerForModel(controller, model): - """ - Registers `controller' as an adapter of `model' for IController, and - optionally registers it for IResource, if it implements it. - - @param controller: A class that implements L{interfaces.IController}, usually a - L{Controller} subclass. Optionally it can implement - L{resource.IResource}. - @param model: Any class, but probably a L{twisted.web.woven.model.Model} - subclass. - """ - components.registerAdapter(controller, model, interfaces.IController) - if resource.IResource.implementedBy(controller): - components.registerAdapter(controller, model, resource.IResource) - diff --git a/tools/buildbot/pylibs/twisted/web/woven/dirlist.py b/tools/buildbot/pylibs/twisted/web/woven/dirlist.py deleted file mode 100644 index 4889efe..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/dirlist.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""Directory listing.""" - -# system imports -from os.path import join as joinpath -import urllib, os - -# sibling imports -import page, model, widgets, view - -# twisted imports -from twisted.web.microdom import lmx -from twisted.web.domhelpers import RawText -from twisted.python.filepath import FilePath -from twisted.web.static import File, getTypeAndEncoding - - -class DirectoryLister(page.Page): - template = ''' - <html> - <head> - <title model="header"> </title> - <style> - .even-dir { background-color: #efe0ef } - .even { background-color: #eee } - .odd-dir {background-color: #f0d0ef } - .odd { background-color: #dedede } - .icon { text-align: center } - .listing { - margin-left: auto; - margin-right: auto; - width: 50%; - padding: 0.1em; - } - - body { border: 0; padding: 0; margin: 0; background-color: #efefef; } - h1 {padding: 0.1em; background-color: #777; color: white; border-bottom: thin white dashed;} - - </style> - </head> - - <body> - <h1 model="header"> </h1> - - <table view="List" model="listing"> - <tr pattern="listHeader"> - <th>Filename</th> - <th>Content type</th> - <th>Content encoding</th> - </tr> - <tr class="even" pattern="listItem"> - <td><a model="link" view="Link" /></td> - <td model="type" view="Text"></td> - <td model="encoding" view="Text"></td> - </tr> - <tr class="odd" pattern="listItem"> - <td><a model="link" view="Link" /></td> - <td model="type" view="Text"></td> - <td model="encoding" view="Text"></td> - </tr> - </table> - - </body> - </html> - ''' - - def __init__(self, pathname, dirs=None, - contentTypes=File.contentTypes, - contentEncodings=File.contentEncodings, - defaultType='text/html'): - self.contentTypes = contentTypes - self.contentEncodings = contentEncodings - self.defaultType = defaultType - # dirs allows usage of the File to specify what gets listed - self.dirs = dirs - self.path = pathname - page.Page.__init__(self) - - def wmfactory_listing(self, request): - if self.dirs is None: - directory = os.listdir(self.path) - directory.sort() - else: - directory = self.dirs - - files = []; dirs = [] - - for path in directory: - url = urllib.quote(path, "/") - if os.path.isdir(os.path.join(self.path, path)): - url = url + '/' - dirs.append({'link':{"text": path + "/", "href":url}, - 'type': '[Directory]', 'encoding': ''}) - else: - mimetype, encoding = getTypeAndEncoding(path, self.contentTypes, - self.contentEncodings, - self.defaultType) - files.append({ - 'link': {"text": path, "href": url}, - 'type': '[%s]' % mimetype, - 'encoding': (encoding and '[%s]' % encoding or '')}) - - return files + dirs - - def wmfactory_header(self, request): - return "Directory listing for %s" % urllib.unquote(request.uri) - - def __repr__(self): - return '<DirectoryLister of %r>' % self.path - - __str__ = __repr__ diff --git a/tools/buildbot/pylibs/twisted/web/woven/flashconduit.py b/tools/buildbot/pylibs/twisted/web/woven/flashconduit.py deleted file mode 100644 index 36e7920..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/flashconduit.py +++ /dev/null @@ -1,35 +0,0 @@ -from twisted.internet.protocol import Factory -from twisted.protocols.basic import LineReceiver -from twisted.python import log -from twisted.web.woven import interfaces - - -class FlashConduit(LineReceiver): - delimiter = '\0' - keepalive = 1 - def connectionMade(self): - print "connection with flash movie opened" - #self.transport.write("alert('helllllllo')\0") - - def connectionLost(self, reason): - print "connection lost" - #self.lp.unhookOutputConduit() - - def lineReceived(self, line): - session = self.factory.site.getSession(line) - self.lp = lp = session.getComponent(interfaces.IWovenLivePage) - lp.hookupOutputConduit(self) - - def writeScript(self, data): - #print "writing javascript", data - self.transport.write(data + '\0') - - def finish(self): - pass - - -class FlashConduitFactory(Factory): - protocol = FlashConduit - - def __init__(self, site): - self.site = site
\ No newline at end of file diff --git a/tools/buildbot/pylibs/twisted/web/woven/form.py b/tools/buildbot/pylibs/twisted/web/woven/form.py deleted file mode 100644 index 749d0d8..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/form.py +++ /dev/null @@ -1,575 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_woven -*- -# -# WORK IN PROGRESS: HARD HAT REQUIRED -# - -from __future__ import nested_scopes - -# Twisted Imports - -from twisted.python import formmethod, failure -from twisted.python.components import registerAdapter -from twisted.web import domhelpers, resource, util -from twisted.internet import defer - -# Sibling Imports -from twisted.web.woven import model, view, controller, widgets, input, interfaces - -from twisted.web.microdom import parseString, lmx, Element - - -#other imports -import math - -# map formmethod.Argument to functions that render them: -_renderers = {} - -def registerRenderer(argumentClass, renderer): - """Register a renderer for a given argument class. - - The renderer function should act in the same way - as the 'input_XXX' methods of C{FormFillerWidget}. - """ - assert callable(renderer) - global _renderers - _renderers[argumentClass] = renderer - - -class FormFillerWidget(widgets.Widget): - - SPANNING_TYPES = ["hidden", "submit"] - - def getValue(self, request, argument): - """Return value for form input.""" - if not self.model.alwaysDefault: - values = request.args.get(argument.name, None) - if values: - try: - return argument.coerce(values[0]) - except formmethod.InputError: - return values[0] - return argument.default - - def getValues(self, request, argument): - """Return values for form input.""" - if not self.model.alwaysDefault: - values = request.args.get(argument.name, None) - if values: - try: - return argument.coerce(values) - except formmethod.InputError: - return values - return argument.default - - def createShell(self, request, node, data): - """Create a `shell' node that will hold the additional form - elements, if one is required. - """ - return lmx(node).table(border="0") - - def input_single(self, request, content, model, templateAttributes={}): - """ - Returns a text input node built based upon the node model. - Optionally takes an already-coded DOM node merges that - information with the model's information. Returns a new (??) - lmx node. - """ - #in a text field, only the following options are allowed (well, more - #are, but they're not supported yet - can add them in later) - attribs = ['type', 'name', 'value', 'size', 'maxlength', - 'readonly'] #only MSIE recognizes readonly and disabled - - arguments = {} - for attrib in attribs: - #model hints and values override anything in the template - val = model.getHint(attrib, templateAttributes.get(attrib, None)) - if val: - arguments[attrib] = str(val) - - value = self.getValue(request, model) - if value: - arguments["value"] = str(value) - - arguments["type"] = "text" #these are default - arguments["name"] = model.name - - return content.input(**arguments) - - def input_string(self, request, content, model, templateAttributes={}): - if not templateAttributes.has_key("size"): - templateAttributes["size"] = '60' - return self.input_single(request, content, model, templateAttributes) - - input_integer = input_single - input_integerrange = input_single - input_float = input_single - - def input_text(self, request, content, model, templateAttributes={}): - r = content.textarea( - cols=str(model.getHint('cols', - templateAttributes.get('cols', '60'))), - rows=str(model.getHint('rows', - templateAttributes.get('rows', '10'))), - name=model.name, - wrap=str(model.getHint('wrap', - templateAttributes.get('wrap', "virtual")))) - r.text(str(self.getValue(request, model))) - return r - - def input_hidden(self, request, content, model, templateAttributes={}): - return content.input(type="hidden", - name=model.name, - value=str(self.getValue(request, model))) - - def input_submit(self, request, content, model, templateAttributes={}): - arguments = {} - val = model.getHint("onClick", templateAttributes.get("onClick", None)) - if val: - arguments["onClick"] = val - arguments["type"] = "submit" - arguments["name"] = model.name - div = content.div() - for tag, value, desc in model.choices: - args = arguments.copy() - args["value"] = tag - div.input(**args) - div.text(" ") - if model.reset: - div.input(type="reset") - return div - - def input_choice(self, request, content, model, templateAttributes={}): - # am I not evil? allow onChange js events - arguments = {} - val = model.getHint("onChange", templateAttributes.get("onChange", None)) - if val: - arguments["onChange"] = val - arguments["name"] = model.name - s = content.select(**arguments) - default = self.getValues(request, model) - for tag, value, desc in model.choices: - kw = {} - if value in default: - kw = {'selected' : '1'} - s.option(value=tag, **kw).text(desc) - return s - - def input_group(self, request, content, model, groupValues, inputType, - templateAttributes={}): - """ - Base code for a group of objects. Checkgroup will use this, as - well as radiogroup. In the attributes, rows means how many rows - the group should be arranged into, cols means how many cols the - group should be arranged into. Columns take precedence over - rows: if both are specified, the output will always generate the - correct number of columns. However, if the number of elements - in the group exceed (or is smaller than) rows*cols, then the - number of rows will be off. A cols attribute of 1 will mean that - all the elements will be listed one underneath another. The - default is a rows attribute of 1: everything listed next to each - other. - """ - rows = model.getHint('rows', templateAttributes.get('rows', None)) - cols = model.getHint('cols', templateAttributes.get('cols', None)) - if rows: - rows = int(rows) - if cols: - cols = int(cols) - - defaults = self.getValues(request, model) - if (rows and rows>1) or (cols and cols>1): #build a table - s = content.table(border="0") - if cols: - breakat = cols - else: - breakat = math.ceil(float(len(groupValues))/rows) - for i in range(0, len(groupValues), breakat): - tr = s.tr() - for j in range(0, breakat): - if i+j >= len(groupValues): - break - tag, value, desc = groupValues[i+j] - kw = {} - if value in defaults: - kw = {'checked' : '1'} - tr.td().input(type=inputType, name=model.name, - value=tag, **kw).text(desc) - - else: - s = content.div() - for tag, value, desc in groupValues: - kw = {} - if value in defaults: - kw = {'checked' : '1'} - s.input(type=inputType, name=model.name, - value=tag, **kw).text(desc) - if cols: - s.br() - - return s - - def input_checkgroup(self, request, content, model, templateAttributes={}): - return self.input_group(request, content, model, model.flags, - "checkbox", templateAttributes) - - def input_radiogroup(self, request, content, model, templateAttributes={}): - return self.input_group(request, content, model, model.choices, - "radio", templateAttributes) - - #I don't know why they're the same, but they were. So I removed the - #excess code. Maybe someone should look into removing it entirely. - input_flags = input_checkgroup - - def input_boolean(self, request, content, model, templateAttributes={}): - kw = {} - if self.getValue(request, model): - kw = {'checked' : '1'} - return content.input(type="checkbox", name=model.name, **kw) - - def input_file(self, request, content, model, templateAttributes={}): - kw = {} - for attrib in ['size', 'accept']: - val = model.getHint(attrib, templateAttributes.get(attrib, None)) - if val: - kw[attrib] = str(val) - return content.input(type="file", name=model.name, **kw) - - def input_date(self, request, content, model, templateAttributes={}): - breakLines = model.getHint('breaklines', 1) - date = self.getValues(request, model) - if date == None: - year, month, day = "", "", "" - else: - year, month, day = date - div = content.div() - div.text("Year: ") - div.input(type="text", size="4", maxlength="4", name=model.name, value=str(year)) - if breakLines: - div.br() - div.text("Month: ") - div.input(type="text", size="2", maxlength="2", name=model.name, value=str(month)) - if breakLines: - div.br() - div.text("Day: ") - div.input(type="text", size="2", maxlength="2", name=model.name, value=str(day)) - return div - - def input_password(self, request, content, model, templateAttributes={}): - return content.input( - type="password", - size=str(templateAttributes.get('size', "60")), - name=model.name) - - def input_verifiedpassword(self, request, content, model, templateAttributes={}): - breakLines = model.getHint('breaklines', 1) - values = self.getValues(request, model) - if isinstance(values, (str, unicode)): - values = (values, values) - if not values: - p1, p2 = "", "" - elif len(values) == 1: - p1, p2 = values, "" - elif len(values) == 2: - p1, p2 = values - else: - p1, p2 = "", "" - div = content.div() - div.text("Password: ") - div.input(type="password", size="20", name=model.name, value=str(p1)) - if breakLines: - div.br() - div.text("Verify: ") - div.input(type="password", size="20", name=model.name, value=str(p2)) - return div - - - def convergeInput(self, request, content, model, templateNode): - name = model.__class__.__name__.lower() - if _renderers.has_key(model.__class__): - imeth = _renderers[model.__class__] - else: - imeth = getattr(self,"input_"+name) - - return imeth(request, content, model, templateNode.attributes).node - - def createInput(self, request, shell, model, templateAttributes={}): - name = model.__class__.__name__.lower() - if _renderers.has_key(model.__class__): - imeth = _renderers[model.__class__] - else: - imeth = getattr(self,"input_"+name) - if name in self.SPANNING_TYPES: - td = shell.tr().td(valign="top", colspan="2") - return (imeth(request, td, model).node, shell.tr().td(colspan="2").node) - else: - if model.allowNone: - required = "" - else: - required = " *" - tr = shell.tr() - tr.td(align="right", valign="top").text(model.getShortDescription()+":"+required) - content = tr.td(valign="top") - return (imeth(request, content, model).node, - content.div(_class="formDescription"). # because class is a keyword - text(model.getLongDescription()).node) - - def setUp(self, request, node, data): - # node = widgets.Widget.generateDOM(self,request,node) - lmn = lmx(node) - if not node.hasAttribute('action'): - lmn['action'] = (request.prepath+request.postpath)[-1] - if not node.hasAttribute("method"): - lmn['method'] = 'post' - lmn['enctype'] = 'multipart/form-data' - self.errorNodes = errorNodes = {} # name: nodes which trap errors - self.inputNodes = inputNodes = {} - for errorNode in domhelpers.findElementsWithAttribute(node, 'errorFor'): - errorNodes[errorNode.getAttribute('errorFor')] = errorNode - argz={} - # list to figure out which nodes are in the template already and which aren't - hasSubmit = 0 - argList = self.model.fmethod.getArgs() - for arg in argList: - if isinstance(arg, formmethod.Submit): - hasSubmit = 1 - argz[arg.name] = arg - inNodes = domhelpers.findElements( - node, - lambda n: n.tagName.lower() in ('textarea', 'select', 'input', - 'div')) - for inNode in inNodes: - t = inNode.getAttribute("type") - if t and t.lower() == "submit": - hasSubmit = 1 - if not inNode.hasAttribute("name"): - continue - nName = inNode.getAttribute("name") - if argz.has_key(nName): - #send an empty content shell - we just want the node - inputNodes[nName] = self.convergeInput(request, lmx(), - argz[nName], inNode) - inNode.parentNode.replaceChild(inputNodes[nName], inNode) - del argz[nName] - # TODO: - # * some arg types should only have a single node (text, string, etc) - # * some should have multiple nodes (choice, checkgroup) - # * some have a bunch of ancillary nodes that are possible values (menu, radiogroup) - # these should all be taken into account when walking through the template - if argz: - shell = self.createShell(request, node, data) - # create inputs, in the same order they were passed to us: - for remArg in [arg for arg in argList if argz.has_key(arg.name)]: - inputNode, errorNode = self.createInput(request, shell, remArg) - errorNodes[remArg.name] = errorNode - inputNodes[remArg.name] = inputNode - - if not hasSubmit: - lmn.input(type="submit") - - -class FormErrorWidget(FormFillerWidget): - def setUp(self, request, node, data): - FormFillerWidget.setUp(self, request, node, data) - for k, f in self.model.err.items(): - en = self.errorNodes[k] - tn = self.inputNodes[k] - en.setAttribute('class', 'formError') - tn.setAttribute('class', 'formInputError') - en.childNodes[:]=[] # gurfle, CLEAR IT NOW!@# - if isinstance(f, failure.Failure): - f = f.getErrorMessage() - lmx(en).text(str(f)) - - -class FormDisplayModel(model.MethodModel): - def initialize(self, fmethod, alwaysDefault=False): - self.fmethod = fmethod - self.alwaysDefault = alwaysDefault - -class FormErrorModel(FormDisplayModel): - def initialize(self, fmethod, args, err): - FormDisplayModel.initialize(self, fmethod) - self.args = args - if isinstance(err, failure.Failure): - err = err.value - if isinstance(err, Exception): - self.err = getattr(err, "descriptions", {}) - self.desc = err - else: - self.err = err - self.desc = "Please try again" - - def wmfactory_description(self, request): - return str(self.desc) - -class _RequestHack(model.MethodModel): - def wmfactory_hack(self, request): - rv = [[str(a), repr(b)] for (a, b) - in request._outDict.items()] - #print 'hack', rv - return rv - -class FormProcessor(resource.Resource): - def __init__(self, formMethod, callback=None, errback=None): - resource.Resource.__init__(self) - self.formMethod = formMethod - if callback is None: - callback = self.viewFactory - self.callback = callback - if errback is None: - errback = self.errorViewFactory - self.errback = errback - - def getArgs(self, request): - """Return the formmethod.Arguments. - - Overridable hook to allow pre-processing, e.g. if we want to enable - on them depending on one of the inputs. - """ - return self.formMethod.getArgs() - - def render(self, request): - outDict = {} - errDict = {} - for methodArg in self.getArgs(request): - valmethod = getattr(self,"mangle_"+ - (methodArg.__class__.__name__.lower()), None) - tmpval = request.args.get(methodArg.name) - if valmethod: - # mangle the argument to a basic datatype that coerce will like - tmpval = valmethod(tmpval) - # coerce it - try: - cv = methodArg.coerce(tmpval) - outDict[methodArg.name] = cv - except: - errDict[methodArg.name] = failure.Failure() - if errDict: - # there were problems processing the form - return self.errback(self.errorModelFactory( - request.args, outDict, errDict)).render(request) - else: - try: - if self.formMethod.takesRequest: - outObj = self.formMethod.call(request=request, **outDict) - else: - outObj = self.formMethod.call(**outDict) - except formmethod.FormException, e: - err = request.errorInfo = self.errorModelFactory( - request.args, outDict, e) - return self.errback(err).render(request) - else: - request._outDict = outDict # CHOMP CHOMP! - # I wanted better default behavior for debugging, so I could - # see the arguments passed, but there is no channel for this in - # the existing callback structure. So, here it goes. - if isinstance(outObj, defer.Deferred): - def _ebModel(err): - if err.trap(formmethod.FormException): - mf = self.errorModelFactory(request.args, outDict, - err.value) - return self.errback(mf) - raise err - (outObj - .addCallback(self.modelFactory) - .addCallback(self.callback) - .addErrback(_ebModel)) - return util.DeferredResource(outObj).render(request) - else: - return self.callback(self.modelFactory(outObj)).render( - request) - - def errorModelFactory(self, args, out, err): - return FormErrorModel(self.formMethod, args, err) - - def errorViewFactory(self, m): - v = view.View(m) - v.template = ''' - <html> - <head> - <title> Form Error View </title> - <style> - .formDescription {color: green} - .formError {color: red; font-weight: bold} - .formInputError {color: #900} - </style> - </head> - <body> - Error: <span model="description" /> - <form model="."> - </form> - </body> - </html> - ''' - return v - - def modelFactory(self, outObj): - adapt = interfaces.IModel(outObj, outObj) - # print 'factorizing', adapt - return adapt - - def viewFactory(self, model): - # return interfaces.IView(model) - if model is None: - bodyStr = ''' - <table model="hack" style="background-color: #99f"> - <tr pattern="listItem" view="Widget"> - <td model="0" style="font-weight: bold"> - </td> - <td model="1"> - </td> - </tr> - </table> - ''' - model = _RequestHack() - else: - bodyStr = '<div model="." />' - v = view.View(model) - v.template = ''' - <html> - <head> - <title> Thank You </title> - </head> - <body> - <h1>Thank You for Using Woven</h1> - %s - </body> - </html> - ''' % bodyStr - return v - - # manglizers - - def mangle_single(self, args): - if args: - return args[0] - else: - return '' - - mangle_string = mangle_single - mangle_text = mangle_single - mangle_integer = mangle_single - mangle_password = mangle_single - mangle_integerrange = mangle_single - mangle_float = mangle_single - mangle_choice = mangle_single - mangle_boolean = mangle_single - mangle_hidden = mangle_single - mangle_submit = mangle_single - mangle_file = mangle_single - mangle_radiogroup = mangle_single - - def mangle_multi(self, args): - if args is None: - return [] - return args - - mangle_checkgroup = mangle_multi - mangle_flags = mangle_multi - -from twisted.python.formmethod import FormMethod - -view.registerViewForModel(FormFillerWidget, FormDisplayModel) -view.registerViewForModel(FormErrorWidget, FormErrorModel) -registerAdapter(FormDisplayModel, FormMethod, interfaces.IModel) - diff --git a/tools/buildbot/pylibs/twisted/web/woven/guard.py b/tools/buildbot/pylibs/twisted/web/woven/guard.py deleted file mode 100644 index ab5d56b..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/guard.py +++ /dev/null @@ -1,383 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_woven -*- - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -"""Resource protection for Woven. If you wish to use twisted.cred to protect -your Woven application, you are probably most interested in -L{UsernamePasswordWrapper}. -""" - -from __future__ import nested_scopes - -__version__ = "$Revision: 1.34 $"[11:-2] - -import random -import time -import md5 -import urllib - -# Twisted Imports - -from twisted.python import log, components -from twisted.web.resource import Resource, IResource -from twisted.web.util import redirectTo, Redirect, DeferredResource -from twisted.web.static import addSlash -from twisted.internet import reactor -from twisted.cred.error import LoginFailed, UnauthorizedLogin - -def _sessionCookie(): - return md5.new("%s_%s" % (str(random.random()) , str(time.time()))).hexdigest() - -class GuardSession(components.Componentized): - """A user's session with a system. - - This utility class contains no functionality, but is used to - represent a session. - """ - def __init__(self, guard, uid): - """Initialize a session with a unique ID for that session. - """ - components.Componentized.__init__(self) - self.guard = guard - self.uid = uid - self.expireCallbacks = [] - self.checkExpiredID = None - self.setLifetime(60) - self.services = {} - self.portals = {} - self.touch() - - def _getSelf(self, interface=None): - self.touch() - if interface is None: - return self - else: - return self.getComponent(interface) - - # Old Guard interfaces - - def clientForService(self, service): - x = self.services.get(service) - if x: - return x[1] - else: - return x - - def setClientForService(self, ident, perspective, client, service): - if self.services.has_key(service): - p, c, i = self.services[service] - p.detached(c, ident) - del self.services[service] - else: - self.services[service] = perspective, client, ident - perspective.attached(client, ident) - # this return value is useful for services that need to do asynchronous - # stuff. - return client - - # New Guard Interfaces - - def resourceForPortal(self, port): - return self.portals.get(port) - - def setResourceForPortal(self, rsrc, port, logout): - self.portalLogout(port) - self.portals[port] = rsrc, logout - return rsrc - - def portalLogout(self, port): - p = self.portals.get(port) - if p: - r, l = p - try: l() - except: log.err() - del self.portals[port] - - # timeouts and expiration - - def setLifetime(self, lifetime): - """Set the approximate lifetime of this session, in seconds. - - This is highly imprecise, but it allows you to set some general - parameters about when this session will expire. A callback will be - scheduled each 'lifetime' seconds, and if I have not been 'touch()'ed - in half a lifetime, I will be immediately expired. - """ - self.lifetime = lifetime - - def notifyOnExpire(self, callback): - """Call this callback when the session expires or logs out. - """ - self.expireCallbacks.append(callback) - - def expire(self): - """Expire/logout of the session. - """ - log.msg("expired session %s" % self.uid) - del self.guard.sessions[self.uid] - for c in self.expireCallbacks: - try: - c() - except: - log.err() - self.expireCallbacks = [] - if self.checkExpiredID: - self.checkExpiredID.cancel() - self.checkExpiredID = None - - def touch(self): - self.lastModified = time.time() - - def checkExpired(self): - self.checkExpiredID = None - # If I haven't been touched in 15 minutes: - if time.time() - self.lastModified > self.lifetime / 2: - if self.guard.sessions.has_key(self.uid): - self.expire() - else: - log.msg("no session to expire: %s" % self.uid) - else: - log.msg("session given the will to live for %s more seconds" % self.lifetime) - self.checkExpiredID = reactor.callLater(self.lifetime, - self.checkExpired) - def __getstate__(self): - d = self.__dict__.copy() - if d.has_key('checkExpiredID'): - del d['checkExpiredID'] - return d - - def __setstate__(self, d): - self.__dict__.update(d) - self.touch() - self.checkExpired() - -INIT_SESSION = 'session-init' - -def _setSession(wrap, req, cook): - req.session = wrap.sessions[cook] - req.getSession = req.session._getSelf - -def urlToChild(request, *ar, **kw): - pp = request.prepath.pop() - orig = request.prePathURL() - request.prepath.append(pp) - c = '/'.join(ar) - if orig[-1] == '/': - # this SHOULD only happen in the case where the URL is just the hostname - ret = orig + c - else: - ret = orig + '/' + c - args = request.args.copy() - args.update(kw) - if args: - ret += '?'+urllib.urlencode(args) - return ret - -def redirectToSession(request, garbage): - rd = Redirect(urlToChild(request, *request.postpath, **{garbage:1})) - rd.isLeaf = 1 - return rd - -SESSION_KEY='__session_key__' - -class SessionWrapper(Resource): - - sessionLifetime = 1800 - - def __init__(self, rsrc, cookieKey=None): - Resource.__init__(self) - self.resource = rsrc - if cookieKey is None: - cookieKey = "woven_session_" + _sessionCookie() - self.cookieKey = cookieKey - self.sessions = {} - - def render(self, request): - return redirectTo(addSlash(request), request) - - def getChild(self, path, request): - if not request.prepath: - return None - cookie = request.getCookie(self.cookieKey) - setupURL = urlToChild(request, INIT_SESSION, *([path]+request.postpath)) - request.setupSessionURL = setupURL - request.setupSession = lambda: Redirect(setupURL) - if path.startswith(SESSION_KEY): - key = path[len(SESSION_KEY):] - if key not in self.sessions: - return redirectToSession(request, '__start_session__') - self.sessions[key].setLifetime(self.sessionLifetime) - if cookie == key: - # /sessionized-url/${SESSION_KEY}aef9c34aecc3d9148/foo - # ^ - # we are this getChild - # with a matching cookie - return redirectToSession(request, '__session_just_started__') - else: - # We attempted to negotiate the session but failed (the user - # probably has cookies disabled): now we're going to return the - # resource we contain. In general the getChild shouldn't stop - # there. - # /sessionized-url/${SESSION_KEY}aef9c34aecc3d9148/foo - # ^ we are this getChild - # without a cookie (or with a mismatched cookie) - _setSession(self, request, key) - return self.resource - elif cookie in self.sessions: - # /sessionized-url/foo - # ^ we are this getChild - # with a session - _setSession(self, request, cookie) - return getResource(self.resource, path, request) - elif path == INIT_SESSION: - # initialize the session - # /sessionized-url/session-init - # ^ this getChild - # without a session - newCookie = _sessionCookie() - request.addCookie(self.cookieKey, newCookie, path="/") - sz = self.sessions[newCookie] = GuardSession(self, newCookie) - sz.checkExpired() - rd = Redirect(urlToChild(request, SESSION_KEY+newCookie, - *request.postpath)) - rd.isLeaf = 1 - return rd - else: - # /sessionized-url/foo - # ^ we are this getChild - # without a session - request.getSession = lambda interface=None: None - return getResource(self.resource, path, request) - -def getResource(resource, path, request): - if resource.isLeaf: - request.postpath.insert(0, request.prepath.pop()) - return resource - else: - return resource.getChildWithDefault(path, request) - -INIT_PERSPECTIVE = 'perspective-init' -DESTROY_PERSPECTIVE = 'perspective-destroy' - -from twisted.python import formmethod as fm -from twisted.web.woven import form - - -newLoginSignature = fm.MethodSignature( - fm.String("username", "", - "Username", "Your user name."), - fm.Password("password", "", - "Password", "Your password."), - fm.Submit("submit", choices=[("Login", "", "")], allowNone=1), - ) - -from twisted.cred.credentials import UsernamePassword, Anonymous - -class UsernamePasswordWrapper(Resource): - """I bring a C{twisted.cred} Portal to the web. Use me to provide different Resources - (usually entire pages) based on a user's authentication details. - - A C{UsernamePasswordWrapper} is a - L{Resource<twisted.web.resource.Resource>}, and is usually wrapped in a - L{SessionWrapper} before being inserted into the site tree. - - The L{Realm<twisted.cred.portal.IRealm>} associated with your - L{Portal<twisted.cred.portal.Portal>} should be prepared to accept a - request for an avatar that implements the L{twisted.web.resource.IResource} - interface. This avatar should probably be something like a Woven - L{Page<twisted.web.woven.page.Page>}. That is, it should represent a whole - web page. Once you return this avatar, requests for it's children do not go - through guard. - - If you want to determine what unauthenticated users see, make sure your - L{Portal<twisted.cred.portal.Portal>} has a checker associated that allows - anonymous access. (See L{twisted.cred.checkers.AllowAnonymousAccess}) - - """ - - def __init__(self, portal, callback=None, errback=None): - """Constructs a UsernamePasswordWrapper around the given portal. - - @param portal: A cred portal for your web application. The checkers - associated with this portal must be able to accept username/password - credentials. - @type portal: L{twisted.cred.portal.Portal} - - @param callback: Gets called after a successful login attempt. - A resource that redirects to "." will display the avatar resource. - If this parameter isn't provided, defaults to a standard Woven - "Thank You" page. - @type callback: A callable that accepts a Woven - L{model<twisted.web.woven.interfaces.IModel>} and returns a - L{IResource<twisted.web.resource.Resource>}. - - @param errback: Gets called after a failed login attempt. - If this parameter is not provided, defaults to a the standard Woven - form error (i.e. The original form on a page of its own, with - errors noted.) - @type errback: A callable that accepts a Woven - L{model<twisted.web.woven.interfaces.IModel>} and returns a - L{IResource<twisted.web.resource.Resource>}. - """ - Resource.__init__(self) - self.portal = portal - self.callback = callback - self.errback = errback - - def _ebFilter(self, f): - f.trap(LoginFailed, UnauthorizedLogin) - raise fm.FormException(password="Login failed, please enter correct username and password.") - - def getChild(self, path, request): - s = request.getSession() - if s is None: - return request.setupSession() - if path == INIT_PERSPECTIVE: - def loginSuccess(result): - interface, avatarAspect, logout = result - s.setResourceForPortal(avatarAspect, self.portal, logout) - - def triggerLogin(username, password, submit=None): - return self.portal.login( - UsernamePassword(username, password), - None, - IResource - ).addCallback( - loginSuccess - ).addErrback( - self._ebFilter - ) - - return form.FormProcessor( - newLoginSignature.method( - triggerLogin - ), - callback=self.callback, - errback=self.errback - ) - elif path == DESTROY_PERSPECTIVE: - s.portalLogout(self.portal) - return Redirect(".") - else: - r = s.resourceForPortal(self.portal) - if r: - ## Delegate our getChild to the resource our portal says is the right one. - return getResource(r[0], path, request) - else: - return DeferredResource( - self.portal.login(Anonymous(), None, IResource - ).addCallback( - lambda (interface, avatarAspect, logout): - getResource(s.setResourceForPortal(avatarAspect, - self.portal, logout), - path, request))) - - - -from twisted.web.woven import interfaces, utils -## Dumb hack until we have an ISession and use interface-to-interface adaption -components.registerAdapter(utils.WovenLivePage, GuardSession, interfaces.IWovenLivePage) - diff --git a/tools/buildbot/pylibs/twisted/web/woven/input.py b/tools/buildbot/pylibs/twisted/web/woven/input.py deleted file mode 100644 index 7d7d956..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/input.py +++ /dev/null @@ -1,347 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_woven -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -# dominput - -import os -import inspect - -from twisted.internet import defer -from twisted.python import log -from twisted.python.reflect import qual - -from twisted.web import domhelpers -from twisted.web.woven import template, controller, utils - -__version__ = "$Revision: 1.34 $"[11:-2] - -controllerFactory = controller.controllerFactory - - -class InputHandler(controller.Controller): - """ - An InputHandler is like a controller, but it operates on something - contained inside of C{self.model} instead of directly on C{self.model}. - For example, a Handler whose C{model} has been set to C{"foo"} will handle - C{self.model.foo}. - - The handler's job is to interpret the request and: - - 1. Check for valid input - 2. If the input is valid, update the model - 3. Use any special API of the view widget to change the view (other - than what the view updates automatically from the model) e.g. in the - case of an error, tell the view to report an error to the user - 4. Return a success value; by default these values are simply recorded - and the page is rendered, but these values could be used to determine - what page to display next, etc. - """ - invalidErrorText = "Error!" - setupStacks = 0 - def __init__(self, model=None, - parent=None, - name=None, - check=None, - commit = None, - invalidErrorText = None, - submodel=None, - controllerStack=None): - self.controllerStack = controllerStack - controller.Controller.__init__(self, model) - self._check = check - self._commit = commit - self._errback = None - self._parent = parent - if invalidErrorText is not None: - self.invalidErrorText = invalidErrorText - if submodel is not None: - self.submodel = submodel - if name is not None: - self.inputName = name - - def initialize(self): - pass - - def setNode(self, node): - self.node = node - - def getInput(self, request): - """ - Return the data associated with this handler from the request, if any. - """ - name = getattr(self, 'inputName', self.submodel) - input = request.args.get(name, None) - if input: - return input - - def handle(self, request): - self.initialize() - data = self.getInput(request) - success = self.check(request, data) - if isinstance(success, defer.Deferred): - success.addCallback(self.dispatchCheckResult, request, data) - success.addErrback(utils.renderFailure, request) - return success - self.dispatchCheckResult(success, request, data) - - def dispatchCheckResult(self, success, request, data): - if success is not None: - if success: - result = self.handleValid(request, data) - else: - result = self.handleInvalid(request, data) - if isinstance(result, defer.Deferred): - return result - - def check(self, request, data): - """ - Check whether the input in the request is valid for this handler - and return a boolean indicating validity. - """ - if self._check is None: - raise NotImplementedError(qual(self.__class__)+'.check') - # self._check is probably a bound method or simple function that - # doesn't have a reference to this InputHandler; pass it - return self._check(self, request, data) - - def handleValid(self, request, data): - """ - It has been determined that the input for this handler is valid; - however, that does not mean the entire form is valid. - """ - self._parent.aggregateValid(request, self, data) - - def aggregateValid(self, request, inputhandler, data): - """By default we just pass the method calls all the way up to the root - Controller. However, an intelligent InputHandler could override this - and implement a state machine that waits for all data to be collected - and then fires. - """ - self._parent.aggregateValid(request, inputhandler, data) - - def handleInvalid(self, request, data): - """ - Once it has been determined that the input is invalid, we should - tell our view to report this fact to the user. - """ - self._parent.aggregateInvalid(request, self, data) - self.view.setError(request, self.invalidErrorText) - - def aggregateInvalid(self, request, inputhandler, data): - """By default we just pass this method call all the way up to the root - Controller. - """ - self._parent.aggregateInvalid(request, inputhandler, data) - - def commit(self, request, node, data): - """ - It has been determined that the input for the entire form is completely - valid; it is now safe for all handlers to commit changes to the model. - """ - if self._commit is None: - data = str(data) - if data != self.view.getData(): - self.model.setData(data) - self.model.notify({'request': request, self.submodel: data}) - else: - func = self._commit - if hasattr(func, 'im_func'): - func = func.im_func - args, varargs, varkw, defaults = inspect.getargspec(func) - if args[1] == 'request': - self._commit(request, data) - else: - self._commit(data) - - -class DefaultHandler(InputHandler): - def handle(self, request): - """ - By default, we don't do anything - """ - pass - - -class SingleValue(InputHandler): - def getInput(self, request): - name = getattr(self, 'inputName', self.submodel) - input = request.args.get(name, None) - if input: - return input[0] - - -class Anything(SingleValue): - """ - Handle anything except for None - """ - def check(self, request, data): - if data is not None: - return 1 - return None - - -class Integer(SingleValue): - """ - Only allow a single integer - """ - def check(self, request, data): - if data is None: return None - try: - int(data) - return 1 - except (TypeError, ValueError): - return 0 - - def handleInvalid(self, request, data): - self.invalidErrorText = "%s is not an integer. Please enter an integer." % data - SingleValue.handleInvalid(self, request, data) - - -class Float(SingleValue): - """ - Only allow a single float - """ - def check(self, request, data): - if data is None: return None - try: - float(data) - return 1 - except (TypeError, ValueError): - return 0 - - def handleInvalid(self, request, data): - self.invalidErrorText = "%s is not an float. Please enter a float." % data - SingleValue.handleInvalid(self, request, data) - - -class List(InputHandler): - def check(self, request, data): - return None - - -class DictAggregator(Anything): - """An InputHandler for a <form> tag, for triggering a function - when all of the form's individual inputs have been validated. - Also for use gathering a dict of arguments to pass to a parent's - aggregateValid if no commit function is passed. - - Usage example:: - <form controller="theForm" action=""> - <input controller="Integer" - view="InputText" model="anInteger" /> - <input controller="Anything" - view="InputText" model="aString" /> - <input type="submit" /> - </form> - - def theCommitFunction(anInteger=None, aString=None): - '''Note how the keyword arguments match up with the leaf model - names above - ''' - print "Yay", anInteger, aString - - class CMyController(controller.Controller): - def wcfactory_theForm(self, request, node, m): - return input.FormAggregator(m, commit=theCommitFunction) - """ - def aggregateValid(self, request, inputhandler, data): - """Aggregate valid input from inputhandlers below us, into a dictionary. - """ - self._valid[inputhandler] = data - - def aggregateInvalid(self, request, inputhandler, data): - self._invalid[inputhandler] = data - - def exit(self, request): - """This is the node complete message - """ - if self._commit: - # Introspect the commit function to see what - # keyword arguments it takes - func = self._commit - if hasattr(func, 'im_func'): - func = func.im_func - args, varargs, varkw, defaults = inspect.getargspec( - func) - wantsRequest = len(args) > 1 and args[1] == 'request' - - if self._invalid: - # whoops error!!!1 - if self._errback: - self._errback(request, self._invalid) - elif self._valid: - # We've got all the input - # Gather it into a dict and call the commit function - results = {} - for item in self._valid: - results[item.model.name] = self._valid[item] - if self._commit: - if wantsRequest: - self._commit(request, **results) - else: - self._commit(**results) - else: - self._parent.aggregateValid(request, self, results) - return results - - -class ListAggregator(Anything): - def aggregateValid(self, request, inputhandler, data): - """Aggregate valid input from inputhandlers below us into a - list until we have all input from controllers below us to pass - to the commit function that was passed to the constructor or - our parent's aggregateValid. - """ - if not hasattr(self, '_validList'): - self._validList = [] - self._validList.append(data) - - def aggregateInvalid(self, request, inputhandler, data): - if not hasattr(self, '_invalidList'): - self._invalidList = [] - self._invalidList.append(data) - - def exit(self, request): - if self._commit: - # Introspect the commit function to see what - #arguments it takes - func = self._commit - if hasattr(func, 'im_func'): - func = func.im_func - args, varargs, varkw, defaults = inspect.getargspec(func) - self.numArgs = len(args) - wantsRequest = args[1] == 'request' - if wantsRequest: - numArgs -= 1 - else: - # Introspect the template to see if we still have - # controllers that will be giving us input - - # aggregateValid is called before the view renders the node, so - # we can count the number of controllers below us the first time - # we are called - if not hasattr(self, 'numArgs'): - self.numArgs = len(domhelpers.findElementsWithAttributeShallow( - self.view.node, "controller")) - - if self._invalidList: - self._parent.aggregateInvalid(request, self, self._invalidList) - else: - if self._commit: - if wantsRequest: - self._commit(request, *self._validList) - else: - self._commit(*self._validList) - self._parent.aggregateValid(request, self, self._invalidList) - - def commit(self, request, node, data): - """If we're using the ListAggregator, we don't want the list of items - to be rerendered - xxx Need to have a "node complete" message sent to the controller - so we can reset state, so controllers can be re-run or ignore input the second time - """ - pass - diff --git a/tools/buildbot/pylibs/twisted/web/woven/interfaces.py b/tools/buildbot/pylibs/twisted/web/woven/interfaces.py deleted file mode 100644 index 3c2c2ad..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/interfaces.py +++ /dev/null @@ -1,198 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_woven -*- - -__version__ = "$Revision: 1.13 $"[11:-2] - -from zope.interface import Interface - -class IModel(Interface): - """A MVC Model.""" - def addView(view): - """Add a view for the model to keep track of. - """ - - def removeView(view): - """Remove a view that the model no longer should keep track of. - """ - - def notify(changed=None): - """Notify all views that something was changed on me. - Passing a dictionary of {'attribute': 'new value'} in changed - will pass this dictionary to the view for increased performance. - If you don't want to do this, don't, and just use the traditional - MVC paradigm of querying the model for things you're interested - in. - """ - - def getData(): - """Return the raw data contained by this Model object, if it is a - wrapper. If not, return self. - """ - - def setData(request, data): - """Set the raw data referenced by this Model object, if it is a - wrapper. This is done by telling our Parent model to setSubmodel - the new data. If this object is not a wrapper, keep the data - around and return it for subsequent getData calls. - """ - - def lookupSubmodel(request, submodelPath): - """Return an IModel implementor for the given submodel path - string. This path may be any number of elements separated - by /. The default implementation splits on "/" and calls - getSubmodel until the path is exhausted. You will not normally - need to override this behavior. - """ - - def getSubmodel(request, submodelName): - """Return an IModel implementor for the submodel named - "submodelName". If this object contains simple data types, - they can be adapted to IModel using - model.adaptToIModel(m, parent, name) before returning. - """ - - def setSubmodel(request, submodelName, data): - """Set the given data as a submodel of this model. The data - need not implement IModel, since getSubmodel should adapt - the data to IModel before returning it. - """ - - -class IView(Interface): - """A MVC View""" - def __init__(model, controller=None): - """A view must be told what its model is, and may be told what its - controller is, but can also look up its controller if none specified. - """ - - def modelChanged(changed): - """Dispatch changed messages to any update_* methods which - may have been defined, then pass the update notification on - to the controller. - """ - - def controllerFactory(): - """Hook for subclasses to customize the controller that is associated - with the model associated with this view. - - Default behavior: Look up a component that implements IController - for the self.model instance. - """ - - def setController(controller): - """Set the controller that this view is related to.""" - - def importViewLibrary(moduleOrObject): - """Import the given object or module into this View's view namespace - stack. If the given object or module has a getSubview function or - method, it will be called when a node has a view="foo" attribute. - If no getSubview method is defined, a default one will be provided - which looks for the literal name in the namespace. - """ - - def getSubview(request, node, model, viewName): - """Look for a view named "viewName" to handle the node "node". - When a node <div view="foo" /> is present in the template, this - method will be called with viewName set to "foo". - - Return None if this View doesn't want to provide a Subview for - the given name. - """ - - def setSubviewFactory(name, factory, setup=None): - """Set the callable "factory", which takes a model and should - return a Widget, to be called by the default implementation of - getSubview when the viewName "name" is present in the template. - - This would generally be used like this: - - view.setSubviewFactory("foo", MyFancyWidgetClass) - - This is equivalent to:: - - def wvfactory_foo(self, request, node, m): - return MyFancyWidgetClass(m) - - Which will cause an instance of MyFancyWidgetClass to be - instanciated when template node <div view="foo" /> is encountered. - - If setup is passed, it will be passed to new instances returned - from this factory as a setup method. The setup method is called - each time the Widget is generated. Setup methods take (request, - widget, model) as arguments. - - This is equivalent to:: - - def wvupdate_foo(self, request, widget, model): - # whatever you want - """ - - def __adapt__(adaptable, default): - if hasattr(adaptable, 'original'): - return IView(adaptable.original, default) - return default - - -class IController(Interface): - """A MVC Controller""" - def setView(view): - """Set the view that this controller is related to. - """ - - def importControllerLibrary(moduleOrObject): - """Import the given object or module into this Controllers's - controller namespace stack. If the given object or module has a - getSubcontroller function or method, it will be called when a node - has a controller="foo" attribute. If no getSubcontroller method is - defined, a default one will be provided which looks for the literal - name in the namespace. - """ - - def getSubcontroller(request, node, model, controllerName): - """Look for a controller named "controllerName" to handle the node - "node". When a node <div controller="foo" /> is present in the - template, this method will be called with controllerName set to "foo". - - Return None if this Controller doesn't want to provide a Subcontroller - for the given name. - """ - - def setSubcontrollerFactory(name, factory): - """Set the callable "factory", which takes a model and should - return an InputHandler, to be called by the default implementation of - getSubview when the controllerName "name" is present in the template. - - This would generally be used like this:: - - view.setSubcontrollerFactory("foo", MyFancyInputHandlerClass) - - This is equivalent to:: - - def wcfactory_foo(self, request, node, m): - return MyFancyInputHandlerClass(m) - - Which will cause an instance of MyFancyInputHandlerClass to be - instanciated when template node <div controller="foo" /> is - encountered. - """ - - def __adapt__(adaptable, default): - if hasattr(adaptable, 'original'): - return IController(adaptable.original, default) - return default - - -class IWovenLivePage(Interface): - def getCurrentPage(): - """Return the current page object contained in this session. - """ - - def setCurrentPage(page): - """Set the current page object contained in this session. - """ - - def sendJavaScript(js): - """Send "js" to the live page's persistent output conduit for - execution in the browser. If there is no conduit connected yet, - save the js and write it as soon as the output conduit is - connected. - """ diff --git a/tools/buildbot/pylibs/twisted/web/woven/model.py b/tools/buildbot/pylibs/twisted/web/woven/model.py deleted file mode 100644 index 90153c2..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/model.py +++ /dev/null @@ -1,487 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_woven -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -__version__ = "$Revision: 1.53 $"[11:-2] - -import types -import weakref -import warnings - -from zope.interface import implements - -from twisted.python import components, reflect -from twisted.internet import defer - -from twisted.web.woven import interfaces - -class _Nothing: pass - -def adaptToIModel(m, parent=None, submodel=None): - adapted = interfaces.IModel(m, None) - if adapted is None: - adapted = Wrapper(m) - adapted.parent = parent - adapted.name = submodel - return adapted - - -class Model: - """ - A Model which keeps track of views which are looking at it in order - to notify them when the model changes. - """ - implements(interfaces.IModel) - - def __init__(self, *args, **kwargs): - if len(args): - self.original = args[0] - else: - self.original = self - self.name = '' - self.parent = None - self.views = [] - self.subviews = {} - self.submodels = {} - self._getter = kwargs.get('getter') - self._setter = kwargs.get('setter') - self.cachedFor = None - self.initialize(*args, **kwargs) - - def __getstate__(self): - self.views = [] - self.subviews = {} - self.submodels = {} - return self.__dict__ - - def invalidateCache(self): - """Invalidate the cache for this object, so the next time - getData is called, it's getter method is called again. - """ - self.cachedFor = None - - def initialize(self, *args, **kwargs): - """ - Hook for subclasses to initialize themselves without having to - mess with the __init__ chain. - """ - pass - - def addView(self, view): - """ - Add a view for the model to keep track of. - """ - if view not in [ref() for ref in self.views]: - self.views.append(weakref.ref(view)) - - def addSubview(self, name, subview): - subviewList = self.subviews.get(name, []) - subviewList.append(weakref.ref(subview)) - self.subviews[name] = subviewList - - def removeView(self, view): - """ - Remove a view that the model no longer should keep track of. - """ - # AM: loop on a _copy_ of the list, since we're changing it!!! - for weakref in list(self.views): - ref = weakref() - if ref is view or ref is None: - self.views.remove(weakref) - - def setGetter(self, getter): - self._getter = getter - - def setSetter(self, setter): - self._setter = setter - - def notify(self, changed=None): - """ - Notify all views that something was changed on me. - Passing a dictionary of {'attribute': 'new value'} in changed - will pass this dictionary to the view for increased performance. - If you don't want to do this, don't, and just use the traditional - MVC paradigm of querying the model for things you're interested - in. - """ - self.cachedFor = None - if changed is None: changed = {} - retVal = [] - # AM: loop on a _copy_ of the list, since we're changing it!!! - for view in list(self.views): - ref = view() - if ref is not None: - retVal.append((ref, ref.modelChanged(changed))) - else: - self.views.remove(view) - for key, value in self.subviews.items(): - if value.wantsAllNotifications or changed.has_key(key): - for item in list(value): - ref = item() - if ref is not None: - retVal.append((ref, ref.modelChanged(changed))) - else: - value.remove(item) - return retVal - - protected_names = ['initialize', 'addView', 'addSubview', 'removeView', 'notify', 'getSubmodel', 'setSubmodel', 'getData', 'setData'] - allowed_names = [] - - def lookupSubmodel(self, request, submodelName): - """ - Look up a full submodel name. I will split on `/' and call - L{getSubmodel} on each element in the 'path'. - - Override me if you don't want 'traversing'-style lookup, but - would rather like to look up a model based on the entire model - name specified. - - If you override me to return Deferreds, make sure I look up - values in a cache (created by L{setSubmodel}) before doing a - regular Deferred lookup. - - XXX: Move bits of this docstring to interfaces.py - """ - if not submodelName: - return None - - # Special case: If the first character is / - # Start at the bottom of the model stack - currentModel = self - if submodelName[0] == '/': - while currentModel.parent is not None: - currentModel = currentModel.parent - submodelName = submodelName[1:] - - submodelList = submodelName.split('/') #[:-1] -# print "submodelList", submodelList - for element in submodelList: - if element == '.' or element == '': - continue - elif element == '..': - currentModel = currentModel.parent - else: - currentModel = currentModel.getSubmodel(request, element) - if currentModel is None: - return None - return currentModel - - def submodelCheck(self, request, name): - """Check if a submodel name is allowed. Subclass me to implement a - name security policy. - """ - if self.allowed_names: - return (name in self.allowed_names) - else: - return (name and name[0] != '_' and name not in self.protected_names) - - - def submodelFactory(self, request, name): - warnings.warn("Warning: default Model lookup strategy is changing:" - "use either AttributeModel or MethodModel for now.", - DeprecationWarning) - if hasattr(self, name): - return getattr(self, name) - else: - return None - - def getSubmodel(self, request, name): - """ - Get the submodel `name' of this model. If I ever return a - Deferred, then I ought to check for cached values (created by - L{setSubmodel}) before doing a regular Deferred lookup. - """ - if self.submodels.has_key(name): - return self.submodels[name] - if not self.submodelCheck(request, name): - return None - m = self.submodelFactory(request, name) - if m is None: - return None - sm = adaptToIModel(m, self, name) - self.submodels[name] = sm - return sm - - def setSubmodel(self, request=None, name=None, value=None): - """ - Set a submodel on this model. If getSubmodel or lookupSubmodel - ever return a Deferred, I ought to set this in a place that - lookupSubmodel/getSubmodel know about, so they can use it as a - cache. - """ - if self.submodelCheck(request, name): - if self.submodels.has_key(name): - del self.submodels[name] - setattr(self, name, value) - - def dataWillChange(self): - pass - - def getData(self, request): - if self.cachedFor != id(request) and self._getter is not None: - self.cachedFor = id(request) - self.dataWillChange() - self.orig = self.original = self._getter(request) - return self.original - - def setData(self, request, data): - if self._setter is not None: - self.cachedFor = None - return self._setter(request, data) - else: - if hasattr(self, 'parent') and self.parent: - self.parent.setSubmodel(request, self.name, data) - self.orig = self.original = data - - -class MethodModel(Model): - """Look up submodels with wmfactory_* methods. - """ - - def submodelCheck(self, request, name): - """Allow any submodel for which I have a submodel. - """ - return hasattr(self, "wmfactory_"+name) - - def submodelFactory(self, request, name): - """Call a wmfactory_name method on this model. - """ - meth = getattr(self, "wmfactory_"+name) - return meth(request) - - def getSubmodel(self, request=None, name=None): - if name is None: - warnings.warn("Warning! getSubmodel should now take the request as the first argument") - name = request - request = None - - cached = self.submodels.has_key(name) - sm = Model.getSubmodel(self, request, name) - if sm is not None: - if not cached: - sm.cachedFor = id(request) - sm._getter = getattr(self, "wmfactory_"+name) - return sm - - -class AttributeModel(Model): - """Look up submodels as attributes with hosts.allow/deny-style security. - """ - def submodelFactory(self, request, name): - if hasattr(self, name): - return getattr(self, name) - else: - return None - - -#backwards compatibility -WModel = Model - - -class Wrapper(Model): - """ - I'm a generic wrapper to provide limited interaction with the - Woven models and submodels. - """ - parent = None - name = None - def __init__(self, orig): - Model.__init__(self) - self.orig = self.original = orig - - def dataWillChange(self): - pass - - def __repr__(self): - myLongName = reflect.qual(self.__class__) - return "<%s instance at 0x%x: wrapped data: %s>" % (myLongName, - id(self), self.original) - - -class ListModel(Wrapper): - """ - I wrap a Python list and allow it to interact with the Woven - models and submodels. - """ - def dataWillChange(self): - self.submodels = {} - - def getSubmodel(self, request=None, name=None): - if name is None and type(request) is type(""): - warnings.warn("Warning!") - name = request - request = None - if self.submodels.has_key(name): - return self.submodels[name] - orig = self.original - try: - i = int(name) - except: - return None - if i > len(orig): - return None - sm = adaptToIModel(orig[i], self, name) - self.submodels[name] = sm - return sm - - def setSubmodel(self, request=None, name=None, value=None): - if value is None: - warnings.warn("Warning!") - value = name - name = request - request = None - self.original[int(name)] = value - - def __len__(self): - return len(self.original) - - def __getitem__(self, name): - return self.getSubmodel(None, str(name)) - - def __setitem__(self, name, value): - self.setSubmodel(None, str(name), value) - - def __repr__(self): - myLongName = reflect.qual(self.__class__) - return "<%s instance at 0x%x: wrapped data: %s>" % (myLongName, - id(self), self.original) - - -class StringModel(ListModel): - - """ I wrap a Python string and allow it to interact with the Woven models - and submodels. """ - - def setSubmodel(self, request=None, name=None, value=None): - raise ValueError("Strings are immutable.") - - -# pyPgSQL returns "PgResultSet" instances instead of lists, which look, act -# and breathe just like lists. pyPgSQL really shouldn't do this, but this works -try: - from pyPgSQL import PgSQL - components.registerAdapter(ListModel, PgSQL.PgResultSet, interfaces.IModel) -except: - pass - -class DictionaryModel(Wrapper): - """ - I wrap a Python dictionary and allow it to interact with the Woven - models and submodels. - """ - def dataWillChange(self): - self.submodels = {} - - def getSubmodel(self, request=None, name=None): - if name is None and type(request) is type(""): - warnings.warn("getSubmodel must get a request argument now") - name = request - request = None - if self.submodels.has_key(name): - return self.submodels[name] - orig = self.original - if name not in orig: - return None - sm = adaptToIModel(orig[name], self, name) - self.submodels[name] = sm - return sm - - def setSubmodel(self, request=None, name=None, value=None): - if value is None: - warnings.warn("Warning!") - value = name - name = request - request = None - self.original[name] = value - - -class AttributeWrapper(Wrapper): - """ - I wrap an attribute named "name" of the given parent object. - """ - def __init__(self, parent, name): - self.original = None - parent = ObjectWrapper(parent) - Wrapper.__init__(self, parent.getSubmodel(None, name)) - self.parent = parent - self.name = name - - -class ObjectWrapper(Wrapper): - """ - I may wrap an object and allow it to interact with the Woven models - and submodels. By default, I am not registered for use with anything. - """ - def getSubmodel(self, request=None, name=None): - if name is None and type(request) is type(""): - warnings.warn("Warning!") - name = request - request = None - if self.submodels.has_key(name): - return self.submodels[name] - sm = adaptToIModel(getattr(self.original, name), self, name) - self.submodels[name] = sm - return sm - - def setSubmodel(self, request=None, name=None, value=None): - if value is None: - warnings.warn("Warning!") - value = name - name = request - request = None - setattr(self.original, name, value) - -class UnsafeObjectWrapper(ObjectWrapper): - """ - I may wrap an object and allow it to interact with the Woven models - and submodels. By default, I am not registered for use with anything. - I am unsafe because I allow methods to be called. In fact, I am - dangerously unsafe. Be wary or I will kill your security model! - """ - def getSubmodel(self, request=None, name=None): - if name is None and type(request) is type(""): - warnings.warn("Warning!") - name = request - request = None - if self.submodels.has_key(name): - return self.submodels[name] - value = getattr(self.original, name) - if callable(value): - return value() - sm = adaptToIModel(value, self, name) - self.submodels = sm - return sm - - -class DeferredWrapper(Wrapper): - def setData(self, request=None, data=_Nothing): - if data is _Nothing: - warnings.warn("setData should be called with request as first arg") - data = request - request = None - if isinstance(data, defer.Deferred): - self.original = data - else: - views, subviews = self.views, self.subviews - new = adaptToIModel(data, self.parent, self.name) - self.__class__ = new.__class__ - self.__dict__ = new.__dict__ - self.views, self.subviews = views, subviews - -class Link(AttributeModel): - def __init__(self, href, text): - AttributeModel.__init__(self) - self.href = href - self.text = text - -try: - components.registerAdapter(StringModel, types.StringType, interfaces.IModel) - components.registerAdapter(ListModel, types.ListType, interfaces.IModel) - components.registerAdapter(ListModel, types.TupleType, interfaces.IModel) - components.registerAdapter(DictionaryModel, types.DictionaryType, interfaces.IModel) - components.registerAdapter(DeferredWrapper, defer.Deferred, interfaces.IModel) - components.registerAdapter(DeferredWrapper, defer.DeferredList, interfaces.IModel) -except ValueError: - # The adapters were already registered - pass diff --git a/tools/buildbot/pylibs/twisted/web/woven/page.py b/tools/buildbot/pylibs/twisted/web/woven/page.py deleted file mode 100644 index 11e7485..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/page.py +++ /dev/null @@ -1,105 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_woven -*- -# -# page.py - -__version__ = "$Revision: 1.23 $"[11:-2] - -from twisted.python import reflect -from twisted.web import resource -from twisted.web.woven import model, view, controller, interfaces, template - -class Page(model.MethodModel, controller.Controller, view.View): - """ - @cvar appRoot: Set this to True if you want me to call - request.rememberRootURL() in my getChild, so you can later use - request.getRootURL() to get the URL to this "application"'s root - resource. (You don't have to worry if there will be multiple - instances of this Page involved in a single request; I'll only - call it for the upper-most instance). - """ - - appRoot = False - - def __init__(self, *args, **kwargs): - templateFile = kwargs.setdefault('templateFile', None) - inputhandlers = kwargs.setdefault('inputhandlers', None) - controllers = kwargs.setdefault('controllers', None) - templateDirectory = kwargs.setdefault('templateDirectory', None) - template = kwargs.setdefault('template', None) - - del kwargs['templateFile'] - del kwargs['inputhandlers'] - del kwargs['controllers'] - del kwargs['templateDirectory'] - del kwargs['template'] - - model.Model.__init__(self, *args, **kwargs) - if len(args): - self.model = args[0] - else: - self.model = self - - controller.Controller.__init__(self, self.model, - inputhandlers=inputhandlers, - controllers=controllers) - self.view = self - view.View.__init__(self, self.model, controller=self, - templateFile=templateFile, - templateDirectory = templateDirectory, - template = template) - self.controller = self - self.controllerRendered = 0 - - def getChild(self, name, request): - # Don't call the rememberURL if we already did once; That way - # we can support an idiom of setting appName as a class - # attribue *even if* the same class is used more than once in - # a hierarchy of Pages. - if self.appRoot and not request.getRootURL(): - request.rememberRootURL() - return controller.Controller.getChild(self, name, request) - - - def renderView(self, request): - return view.View.render(self, request, - doneCallback=self.gatheredControllers) - -class LivePage(model.MethodModel, controller.LiveController, view.LiveView): - - appRoot = False - - def __init__(self, m=None, templateFile=None, inputhandlers=None, - templateDirectory=None, controllers=None, *args, **kwargs): - template = kwargs.setdefault('template', None) - del kwargs['template'] - - model.Model.__init__(self, *args, **kwargs) - if m is None: - self.model = self - else: - self.model = m - - controller.LiveController.__init__(self, self.model, - inputhandlers=inputhandlers, - controllers=controllers) - self.view = self - view.View.__init__(self, self.model, controller=self, - templateFile=templateFile, - templateDirectory=templateDirectory, - template=template) - self.controller = self - self.controllerRendered = 0 - - - def getChild(self, name, request): - # Don't call the rememberPath if we already did once; That way - # we can support an idiom of setting appName as a class - # attribue *even if* the same class is used more than once in - # a hierarchy of Pages. - if self.appRoot and not request.getRootURL(): - request.rememberRootURL() - return controller.Controller.getChild(self, name, request) - - def renderView(self, request): - return view.View.render(self, request, - doneCallback=self.gatheredControllers) diff --git a/tools/buildbot/pylibs/twisted/web/woven/simpleguard.py b/tools/buildbot/pylibs/twisted/web/woven/simpleguard.py deleted file mode 100644 index 65c1ad4..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/simpleguard.py +++ /dev/null @@ -1,82 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -""" -A simple guard framework for implementing web sites that only need -'Anonymous' vs 'Logged on' distinction, but nothing more. - -If you need - - multiple levels of access, or - - multiple-interface applications, or - - anything else more complex than 'Logged on' and 'Not logged on' - -you need to use twisted.web.woven.guard directly. -""" - -from twisted.cred import portal, checkers as checkerslib -from twisted.web import resource, util -from twisted.web.woven import guard -from zope.interface import implements - - -class Authenticated: - - def __init__(self, name=None): - self.name = name - - def __nonzero__(self): - return bool(self.name) - - -class MarkAuthenticatedResource: - - implements(resource.IResource) - - isLeaf = False - - def __init__(self, resource, name): - self.authenticated = Authenticated(name) - self.resource = resource - - def render(self, request): - request.setComponent(Authenticated, self.authenticated) - return self.resource.render(request) - - def getChildWithDefault(self, path, request): - request.setComponent(Authenticated, self.authenticated) - return self.resource.getChildWithDefault(path, request) - - -class MarkingRealm: - - implements(portal.IRealm) - - def __init__(self, resource, nonauthenticated=None): - self.resource = resource - self.nonauthenticated = (nonauthenticated or - MarkAuthenticatedResource(resource, None)) - - def requestAvatar(self, avatarId, mind, *interfaces): - if resource.IResource not in interfaces: - raise NotImplementedError("no interface") - if avatarId: - return (resource.IResource, - MarkAuthenticatedResource(self.resource, avatarId), - lambda:None) - else: - return resource.IResource, self.nonauthenticated, lambda:None - - -def parentRedirect(_): - return util.ParentRedirect() - -def guardResource(resource, checkers, callback=parentRedirect, errback=None, - nonauthenticated=None): - myPortal = portal.Portal(MarkingRealm(resource, nonauthenticated)) - for checker in checkers+[checkerslib.AllowAnonymousAccess()]: - myPortal.registerChecker(checker) - un = guard.UsernamePasswordWrapper(myPortal, - callback=callback, errback=errback) - return guard.SessionWrapper(un) diff --git a/tools/buildbot/pylibs/twisted/web/woven/tapestry.py b/tools/buildbot/pylibs/twisted/web/woven/tapestry.py deleted file mode 100644 index 11b6042..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/tapestry.py +++ /dev/null @@ -1,170 +0,0 @@ - -""" -Woven object collections. - -THIS MODULE IS HIGHLY EXPERIMENTAL AND MAY BE DEPRECATED SOON. -""" - -from __future__ import nested_scopes - -__version__ = "$Revision: 1.13 $"[11:-2] - - -import warnings -warnings.warn("The tapestry module is deprecated. Use page instead.", DeprecationWarning, 1) - -# System Imports -import sys -import os - -# Twisted Imports - -from twisted.internet.defer import Deferred - -from twisted.web.resource import Resource, IResource -from twisted.web.static import redirectTo, addSlash, File, Data -from twisted.web.server import NOT_DONE_YET -from twisted.web import util - -from twisted.python.reflect import qual - -# Sibling Imports -from twisted.web.woven.view import View - -_ChildJuggler = util.DeferredResource - -class ModelLoader(Resource): - """Resource for loading models. (see loadModel) - """ - def __init__(self, parent, templateFile=None): - Resource.__init__(self) - self.parent = parent - self.templateFile = templateFile - - def modelClass(self, other): - return other - - def getChild(self, path, request): - d = self.loadModel(path, request) - templateFile = (self.templateFile or self.__class__.__name__+'.html') - d.addCallback( - lambda result: self.parent.makeView(self.modelClass(result), - templateFile, 1)) - return util.DeferredResource(d) - - def loadModelNow(self, path, request): - """Override this rather than loadModel if your model-loading is - synchronous. - """ - raise NotImplementedError("%s.loadModelNow" % (reflect.qual(self.__class__))) - - def loadModel(self, path, request): - """Load a model, for the given path and request. - - @rtype: L{Deferred} - """ - from twisted.internet.defer import execute - return execute(self.loadModelNow, path, request) - - -from twisted.web import microdom -from twisted.web import domhelpers - -class TapestryView(View): - tapestry = None - parentCount = 0 - def lookupTemplate(self, request): - fullFile = os.path.join(self.templateDirectory, self.templateFile) - document = microdom.parse(open(fullFile)) - if self.tapestry: - return self.tapestry.templateMutate(document, self.parentCount) - return document - -class Tapestry(Resource): - """ - I am a top-level aggregation of Woven objects: a full `site' or - `application'. - """ - viewFactory = TapestryView - def __init__(self, templateDirectory, viewFactory=None, metaTemplate=None): - """ - Create a tapestry with a specified template directory. - """ - Resource.__init__(self) - self.templateDirectory = templateDirectory - if viewFactory is not None: - self.viewFactory = viewFactory - if metaTemplate: - self.metaTemplate = microdom.parse(open( - os.path.join(templateDirectory, metaTemplate))) - else: - self.metaTemplate = None - - def templateMutate(self, document, parentCount=0): - if self.metaTemplate: - newDoc = self.metaTemplate.cloneNode(1) - if parentCount: - dotdot = parentCount * '../' - for ddname in 'href', 'src', 'action': - for node in domhelpers.findElementsWithAttribute(newDoc, ddname): - node.setAttribute(ddname, dotdot + node.getAttribute(ddname)) - ttl = domhelpers.findNodesNamed(newDoc, "title")[0] - ttl2 = domhelpers.findNodesNamed(document, "title")[0] - ttl.childNodes[:] = [] - for n in ttl2.childNodes: - ttl.appendChild(n) - body = domhelpers.findElementsWithAttribute(newDoc, "class", "__BODY__")[0] - body2 = domhelpers.findNodesNamed(document, "body")[0] - ndx = body.parentNode.childNodes.index(body) - body.parentNode.childNodes[ndx:ndx+1] = body2.childNodes - for n in body2.childNodes: - n.parentNode = body.parentNode - f = open("garbage.html", "wb") - f.write(newDoc.toprettyxml()) - return newDoc - return document - - def makeView(self, model, name, parentCount=0): - v = self.viewFactory(model, name) - v.parentCount = parentCount - v.templateDirectory = self.templateDirectory - v.tapestry = self - v.importViewLibrary(self) - return v - - def getSubview(self, request, node, model, viewName): - mod = sys.modules[self.__class__.__module__] - # print "I'm getting a subview", mod, viewName - - # try just the name - vm = getattr(mod, viewName, None) - if vm: - return vm(model) - - # try the name + a V - vn2 = "V"+viewName.capitalize() - vm = getattr(mod, vn2, None) - if vm: - return vm(model) - - vm = getattr(self, 'wvfactory_'+viewName, None) - if vm: - return vm(request, node, model) - - def render(self, request): - return redirectTo(addSlash(request), request) - - def getChild(self, path, request): - if path == '': path = 'index' - path = path.replace(".","_") - cm = getattr(self, "wchild_"+path, None) - if cm: - p = cm(request) - if isinstance(p, Deferred): - return util.DeferredResource(p) - adapter = IResource(p, None) - if adapter is not None: - return adapter - # maybe we want direct support for ModelLoader? - # cl = getattr(self, "wload_"+path, None) #??? - return Resource.getChild(self, path, request) diff --git a/tools/buildbot/pylibs/twisted/web/woven/template.py b/tools/buildbot/pylibs/twisted/web/woven/template.py deleted file mode 100644 index a25ab43..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/template.py +++ /dev/null @@ -1,374 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_woven -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -DOMTemplate - -Most templating systems provide commands that you embed -in the HTML to repeat elements, include fragments from other -files, etc. This works fairly well for simple constructs and people -tend to get a false sense of simplicity from this. However, in my -experience, as soon as the programmer wants to make the logic -even slightly more complicated, the templating system must be -bent and abused in ways it was never meant to be used. - -The theory behind DOMTemplate is that Python code instead -of template syntax in the HTML should be used to manipulate -the structure of the HTML. DOMTemplate uses the DOM, a w3c -standard tree-based representation of an HTML document that -provides an API that allows you to traverse nodes in the tree, -examine their attributes, move, add, and delete them. It is a -fairly low level API, meaning it takes quite a bit of code to get -a bit done, but it is standard -- learn the DOM once, you can -use it from ActionScript, JavaScript, Java, C++, whatever. - -A DOMTemplate subclass must do two things: indicate which -template it wants to use, and indicate which elements it is -interested in. - -A short example:: - - | class Test(DOMTemplate): - | template = ''' - | <html><head><title>Foo</title></head><body> - | - | <div view="Test"> - | This test node will be replaced - | </div> - | - | </body></html> - | ''' - | - | def factory_test(self, request, node): - | ''' - | The test method will be called with the request and the - | DOM node that the test method was associated with. - | ''' - | # self.d has been bound to the main DOM "document" object - | newNode = self.d.createTextNode("Testing, 1,2,3") - | - | # Replace the test node with our single new text node - | return newNode -""" - -import warnings - -try: - import cPickle as pickle -except ImportError: - import pickle - -import string, os, sys, stat, types -from twisted.web import microdom - -from twisted.python import components -from twisted.web import resource, html -from twisted.web.resource import Resource -from twisted.web.woven import controller, utils, interfaces - -from twisted.internet import defer -from twisted.python import failure -from twisted.internet import reactor, defer -from twisted.python import log -from zope.interface import implements, Interface - -from twisted.web.server import NOT_DONE_YET -STOP_RENDERING = 1 -RESTART_RENDERING = 2 - - - -class INodeMutator(Interface): - """A component that implements NodeMutator knows how to mutate - DOM based on the instructions in the object it wraps. - """ - def generate(request, node): - """The generate method should do the work of mutating the DOM - based on the object this adapter wraps. - """ - pass - - -class NodeMutator: - implements(INodeMutator) - def __init__(self, data): - self.data = data - -class NodeNodeMutator(NodeMutator): - """A NodeNodeMutator replaces the node that is passed in to generate - with the node it adapts. - """ - def __init__(self, data): - assert data is not None - NodeMutator.__init__(self, data) - - def generate(self, request, node): - if self.data is not node: - parent = node.parentNode - if parent: - parent.replaceChild(self.data, node) - else: - log.msg("Warning: There was no parent for node %s; node not mutated." % node) - return self.data - - -class NoneNodeMutator(NodeMutator): - def generate(self, request, node): - return node # do nothing - child = request.d.createTextNode("None") - node.parentNode.replaceChild(child, node) - - -class StringNodeMutator(NodeMutator): - """A StringNodeMutator replaces the node that is passed in to generate - with the string it adapts. - """ - def generate(self, request, node): - if self.data: - try: - child = microdom.parseString(self.data) - except Exception, e: - log.msg("Error parsing return value, probably invalid xml:", e) - child = request.d.createTextNode(self.data) - else: - child = request.d.createTextNode(self.data) - nodeMutator = NodeNodeMutator(child) - return nodeMutator.generate(request, node) - - -components.registerAdapter(NodeNodeMutator, microdom.Node, INodeMutator) -components.registerAdapter(NoneNodeMutator, type(None), INodeMutator) -components.registerAdapter(StringNodeMutator, type(""), INodeMutator) - - -class DOMTemplate(Resource): - """A resource that renders pages using DOM.""" - - isLeaf = 1 - templateFile = '' - templateDirectory = '' - template = '' - _cachedTemplate = None - - def __init__(self, templateFile = None): - """ - @param templateFile: The name of a file containing a template. - @type templateFile: String - """ - Resource.__init__(self) - if templateFile: - self.templateFile = templateFile - - self.outstandingCallbacks = 0 - self.failed = 0 - - def render(self, request): - template = self.getTemplate(request) - if template: - self.d = microdom.parseString(template) - else: - if not self.templateFile: - raise AttributeError, "%s does not define self.templateFile to operate on" % self.__class__ - self.d = self.lookupTemplate(request) - self.handleDocument(request, self.d) - return NOT_DONE_YET - - def getTemplate(self, request): - """ - Override this if you want to have your subclass look up its template - using a different method. - """ - return self.template - - def lookupTemplate(self, request): - """ - Use acquisition to look up the template named by self.templateFile, - located anywhere above this object in the heirarchy, and use it - as the template. The first time the template is used it is cached - for speed. - """ - if self.template: - return microdom.parseString(self.template) - if not self.templateDirectory: - mod = sys.modules[self.__module__] - if hasattr(mod, '__file__'): - self.templateDirectory = os.path.split(mod.__file__)[0] - # First see if templateDirectory + templateFile is a file - templatePath = os.path.join(self.templateDirectory, self.templateFile) - # Check to see if there is an already compiled copy of it - templateName = os.path.splitext(self.templateFile)[0] - compiledTemplateName = '.' + templateName + '.pxp' - compiledTemplatePath = os.path.join(self.templateDirectory, compiledTemplateName) - # No? Compile and save it - if (not os.path.exists(compiledTemplatePath) or - os.stat(compiledTemplatePath)[stat.ST_MTIME] < os.stat(templatePath)[stat.ST_MTIME]): - compiledTemplate = microdom.parse(templatePath) - pickle.dump(compiledTemplate, open(compiledTemplatePath, 'wb'), 1) - else: - compiledTemplate = pickle.load(open(compiledTemplatePath, "rb")) - return compiledTemplate - - def setUp(self, request, document): - pass - - def handleDocument(self, request, document): - """ - Handle the root node, and send the page if there are no - outstanding callbacks when it returns. - """ - try: - request.d = document - self.setUp(request, document) - # Don't let outstandingCallbacks get to 0 until the - # entire tree has been recursed - # If you don't do this, and any callback has already - # completed by the time the dispatchResultCallback - # is added in dispachResult, then sendPage will be - # called prematurely within dispatchResultCallback - # resulting in much gnashing of teeth. - self.outstandingCallbacks += 1 - for node in document.childNodes: - request.currentParent = node - self.handleNode(request, node) - self.outstandingCallbacks -= 1 - if not self.outstandingCallbacks: - return self.sendPage(request) - except: - self.renderFailure(None, request) - - def dispatchResult(self, request, node, result): - """ - Check a given result from handling a node and hand it to a process* - method which will convert the result into a node and insert it - into the DOM tree. Return the new node. - """ - if not isinstance(result, defer.Deferred): - adapter = INodeMutator(result, None) - if adapter is None: - raise NotImplementedError( - "Your factory method returned %s, but there is no " - "INodeMutator adapter registerred for %s." % - (result, getattr(result, "__class__", - None) or type(result))) - result = adapter.generate(request, node) - if isinstance(result, defer.Deferred): - self.outstandingCallbacks += 1 - result.addCallback(self.dispatchResultCallback, request, node) - result.addErrback(self.renderFailure, request) - # Got to wait until the callback comes in - return result - - def recurseChildren(self, request, node): - """ - If this node has children, handle them. - """ - request.currentParent = node - if not node: return - if type(node.childNodes) == type(""): return - if node.hasChildNodes(): - for child in node.childNodes: - self.handleNode(request, child) - - def dispatchResultCallback(self, result, request, node): - """ - Deal with a callback from a deferred, dispatching the result - and recursing children. - """ - self.outstandingCallbacks -= 1 - node = self.dispatchResult(request, node, result) - self.recurseChildren(request, node) - if not self.outstandingCallbacks: - return self.sendPage(request) - - def handleNode(self, request, node): - """ - Handle a single node by looking up a method for it, calling the method - and dispatching the result. - - Also, handle all childNodes of this node using recursion. - """ - if not hasattr(node, 'getAttribute'): # text node? - return node - - viewName = node.getAttribute('view') - if viewName: - method = getattr(self, "factory_" + viewName, None) - if not method: - raise NotImplementedError, "You specified view name %s on a node, but no factory_%s method was found." % (viewName, viewName) - - result = method(request, node) - node = self.dispatchResult(request, node, result) - - if not isinstance(node, defer.Deferred): - self.recurseChildren(request, node) - - def sendPage(self, request): - """ - Send the results of the DOM mutation to the browser. - """ - page = str(self.d.toxml()) - request.write(page) - request.finish() - return page - - def renderFailure(self, failure, request): - try: - xml = request.d.toxml() - except: - xml = "" -# if not hasattr(request, 'channel'): -# log.msg("The request got away from me before I could render an error page.") -# log.err(failure) -# return failure - if not self.failed: - self.failed = 1 - if failure: - request.write("<html><head><title>%s: %s</title></head><body>\n" % (html.escape(str(failure.type)), html.escape(str(failure.value)))) - else: - request.write("<html><head><title>Failure!</title></head><body>\n") - utils.renderFailure(failure, request) - request.write("<h3>Here is the partially processed DOM:</h3>") - request.write("\n<pre>\n") - request.write(html.escape(xml)) - request.write("\n</pre>\n") - request.write("</body></html>") - request.finish() - return failure - -########################################## -# Deprecation zone -# Wear a hard hat -########################################## - - -# DOMView is now deprecated since the functionality was merged into domtemplate -DOMView = DOMTemplate - -# DOMController is now renamed woven.controller.Controller -class DOMController(controller.Controller, Resource): - """ - A simple controller that automatically passes responsibility on to the view - class registered for the model. You can override render to perform - more advanced template lookup logic. - """ - - def __init__(self, *args, **kwargs): - log.msg("DeprecationWarning: DOMController is deprecated; it has been renamed twisted.web.woven.controller.Controller.\n") - controller.Controller.__init__(self, *args, **kwargs) - Resource.__init__(self) - - def setUp(self, request): - pass - - def render(self, request): - self.setUp(request) - self.view = interfaces.IView(self.model, None) - self.view.setController(self) - return self.view.render(request) - - def process(self, request, **kwargs): - log.msg("Processing results: ", kwargs) - return RESTART_RENDERING diff --git a/tools/buildbot/pylibs/twisted/web/woven/utils.py b/tools/buildbot/pylibs/twisted/web/woven/utils.py deleted file mode 100644 index 472ac51..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/utils.py +++ /dev/null @@ -1,198 +0,0 @@ -from __future__ import nested_scopes - -from types import ClassType - -from twisted.web import server -from twisted.web import util as webutil -from twisted.web.woven import interfaces -from twisted.python import failure, log, components -from zope.interface import implements - -def renderFailure(fail, request): - if not fail: - fail = failure.Failure() - log.err(fail) - request.write(webutil.formatFailure(fail)) - #request.finish() - - -def doSendPage(self, d, request): - page = str(d.toprettyxml()) - request.setHeader('content-length', str(len(page))) - request.write(page) - request.finish() - return page - - -class Script: - type="javascript1.2" - def __init__(self, script): - self.script = script - - -class WovenLivePage: - implements(interfaces.IWovenLivePage) - - currentPage = None - def __init__(self, session): - self.session = session - self.output = None - self.input = None - self.cached = [] - self.inputCache = [] - - def getCurrentPage(self): - """Return the current page object contained in this session. - """ - return self.currentPage - - def setCurrentPage(self, page): - """Set the current page object contained in this session. - """ - self.currentPage = page - - def write(self, text): - """Write "text" to the live page's persistent output conduit. - If there is no conduit connected yet, save the text and write it - as soon as the output conduit is connected. - """ - if self.output is None: - self.cached.append(text) - print "CACHING", `self.cached` - else: - if isinstance(text, Script): - if hasattr(self.output, 'writeScript'): - self.output.writeScript(text.script) - return - text = '<script language="%s">%s</script>\r\n' % (text.type, text.script) - print "WRITING", text - if text[-1] != '\n': - text += '\n' - self.output.write(text) - - def sendScript(self, js): - self.write(Script(js)) - if self.output is not None and not getattr(self.output, 'keepalive', None): - print "## woot, teh connection was open" - ## Close the connection; the javascript will have to open it again to get the next event. - self.output.finish() - self.output = None - - def hookupOutputConduit(self, request): - """Hook up the given request as the output conduit for this - session. - """ - print "TOOT! WE HOOKED UP OUTPUT!", `self.cached` - self.output = request - for text in self.cached: - self.write(text) - if self.cached: - self.cached = [] - if not getattr(self.output, 'keepalive', None): - ## Close the connection; the javascript will have to open it again to get the next event. - request.finish() - self.output = None - - def unhookOutputConduit(self): - self.output = None - - def hookupInputConduit(self, obj): - """Hook up the given object as the input conduit for this - session. - """ - print "HOOKING UP", self.inputCache - self.input = obj - for text in self.inputCache: - self.pushThroughInputConduit(text) - self.inputCache = [] - print "DONE HOOKING", self.inputCache - - def pushThroughInputConduit(self, inp): - """Push some text through the input conduit. - """ - print "PUSHING INPUT", inp - if self.input is None: - self.inputCache.append(inp) - else: - self.input(inp) - -class Stack: - def __init__(self, stack=None): - if stack is None: - self.stack = [] - else: - self.stack = stack - - def push(self, item): - self.stack.insert(0, item) - - def pop(self): - if self.stack: - return self.stack.pop(0) - - def peek(self): - for x in self.stack: - if x is not None: - return x - - def poke(self, item): - self.stack[0] = item - - def clone(self): - return Stack(self.stack[:]) - - def __len__(self): - return len(self.stack) - - def __getitem__(self, item): - return self.stack[item] - - -class GetFunction: - def __init__(self, namespace): - self.namespace = namespace - - def __call__(self, request, node, model, viewName): - """Get a name from my namespace. - """ - from twisted.web.woven import widgets - if viewName == "None": - return widgets.DefaultWidget(model) - - vc = getattr(self.namespace, viewName, None) - # don't call modules and random crap in the namespace, only widgets - if vc and isinstance(vc, (type, ClassType)) and issubclass(vc, widgets.Widget): - return vc(model) - - -def createGetFunction(namespace): - return GetFunction(namespace) - - -class SetId: - def __init__(self, theId): - self.theId = theId - - def __call__(self, request, wid, data): - id = wid.attributes.get('id', None) - if not id: - wid.setAttribute('id', self.theId) - else: - top = wid - while getattr(top, 'parent', None) is not None: - top = top.parent - if top.subviews.has_key(self.theId): - del top.subviews[self.theId] - top.subviews[id] = wid - if wid.parent.subviews.has_key(self.theId): - del wid.parent.subviews[self.theId] - wid.parent.subviews[id] = wid - - -def createSetIdFunction(theId): - return SetId(theId) - - - -components.registerAdapter(WovenLivePage, server.Session, interfaces.IWovenLivePage) - diff --git a/tools/buildbot/pylibs/twisted/web/woven/view.py b/tools/buildbot/pylibs/twisted/web/woven/view.py deleted file mode 100644 index d792fc7..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/view.py +++ /dev/null @@ -1,687 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_woven -*- -# -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from __future__ import nested_scopes - -__version__ = "$Revision: 1.91 $"[11:-2] - -# Sibling imports -import interfaces -import utils -import controller -from utils import doSendPage -import model - -# Twisted imports -from twisted.internet import defer -from twisted.python import components -from twisted.python import log -from twisted.web import resource, microdom, html, error -from twisted.web.server import NOT_DONE_YET -from zope.interface import implements - -try: - import cPickle as pickle -except ImportError: - import pickle - -import os -import sys -import stat -import warnings -import types - - -def peek(stack): - if stack is None: - return None - it = None - while it is None and stack is not None: - it, stack = stack - return it - - -def poke(stack, new): - it, stack = stack - return (new, stack) - - -def filterStack(stack): - returnVal = [] - while stack is not None: - it, stack = stack - if it is not None: - returnVal.append(it) - return returnVal - - -def viewFactory(viewClass): - return lambda request, node, model: viewClass(model) - -def viewMethod(viewClass): - return lambda self, request, node, model: viewClass(model) - - -templateCache = {} - - -class View: - implements(resource.IResource, interfaces.IView) - # wvfactory_xxx method signature: request, node, model; returns Widget - # wvupdate_xxx method signature: request, widget, data; mutates widget - # based on data (not necessarily an IModel; - # has been unwrapped at this point) - - wantsAllNotifications = 0 - templateFile = '' - templateDirectory = '' - template = '' - - isLeaf = 1 - - def getChild(self, path, request): - return error.NoResource("No such child resource.") - - def getChildWithDefault(self, path, request): - return self.getChild(path, request) - - viewLibraries = [] - setupStacks = 1 - livePage = 0 - doneCallback = None - templateNode = None - def __init__(self, m, templateFile=None, templateDirectory=None, template=None, controller=None, doneCallback=None, modelStack=None, viewStack=None, controllerStack=None): - """ - A view must be told what its model is, and may be told what its - controller is, but can also look up its controller if none specified. - """ - if not interfaces.IModel.providedBy(m): - m = model.adaptToIModel(m, None, None) - self.model = self.mainModel = m - # It's the responsibility of the calling code to make sure - # setController is called on this view before it's rendered. - self.controller = None - self.subviews = {} - if self.setupStacks: - self.modelStack = None - self.viewStack = None - self.controllerStack = None - if doneCallback is None and self.doneCallback is None: - self.doneCallback = doSendPage - else: - print "DoneCallback", doneCallback - self.doneCallback = doneCallback - if template is not None: - self.template = template - if templateFile is not None: - self.templateFile = templateFile - if templateDirectory is not None: - self.templateDirectory = templateDirectory - - self.outstandingCallbacks = 0 - self.outstandingNodes = [] - self.failed = 0 - self.setupMethods = [] - - def setupAllStacks(self): - self.modelStack = (self.model, None) - self.controllerStack = (self.controller, (input, None)) - self.setupViewStack() - - def setUp(self, request, d): - pass - - def setupViewStack(self): - self.viewStack = None - if widgets not in self.viewLibraries: - self.viewLibraries.append(widgets) - for library in self.viewLibraries: - if not hasattr(library, 'getSubview'): - library.getSubview = utils.createGetFunction(library) - self.viewStack = (library, self.viewStack) - self.viewStack = (self, self.viewStack) - - def importViewLibrary(self, namespace): - self.viewLibraries.append(namespace) - return self - - def render(self, request, doneCallback=None): - if not getattr(request, 'currentId', 0): - request.currentId = 0 - request.currentPage = self - if self.controller is None: - self.controller = controller.Controller(self.model) - if doneCallback is not None: - self.doneCallback = doneCallback - else: - self.doneCallback = doSendPage - self.setupAllStacks() - template = self.getTemplate(request) - if template: - self.d = microdom.parseString(template, caseInsensitive=0, preserveCase=0) - else: - if not self.templateFile: - raise AttributeError, "%s does not define self.templateFile to operate on" % self.__class__ - self.d = self.lookupTemplate(request) - request.d = self.d - self.handleDocument(request, self.d) - return NOT_DONE_YET - - def getTemplate(self, request): - """ - Override this if you want to have your subclass look up its template - using a different method. - """ - return self.template - - def lookupTemplate(self, request): - """ - Use acquisition to look up the template named by self.templateFile, - located anywhere above this object in the heirarchy, and use it - as the template. The first time the template is used it is cached - for speed. - """ - if self.template: - return microdom.parseString(self.template, caseInsensitive=0, preserveCase=0) - if not self.templateDirectory: - mod = sys.modules[self.__module__] - if hasattr(mod, '__file__'): - self.templateDirectory = os.path.split(mod.__file__)[0] - # First see if templateDirectory + templateFile is a file - templatePath = os.path.join(self.templateDirectory, self.templateFile) - if not os.path.exists(templatePath): - raise RuntimeError, "The template %r was not found." % templatePath - # Check to see if there is an already parsed copy of it - mtime = os.path.getmtime(templatePath) - cachedTemplate = templateCache.get(templatePath, None) - compiledTemplate = None - - if cachedTemplate is not None: - if cachedTemplate[0] == mtime: - compiledTemplate = templateCache[templatePath][1].cloneNode(deep=1) - - if compiledTemplate is None: - compiledTemplate = microdom.parse(templatePath, caseInsensitive=0, preserveCase=0) - templateCache[templatePath] = (mtime, compiledTemplate.cloneNode(deep=1)) - return compiledTemplate - - def handleDocument(self, request, document): - """Handle the root node, and send the page if there are no - outstanding callbacks when it returns. - """ - try: - request.d = document - self.setUp(request, document) - # Don't let outstandingCallbacks get to 0 until the - # entire tree has been recursed - # If you don't do this, and any callback has already - # completed by the time the dispatchResultCallback - # is added in dispachResult, then sendPage will be - # called prematurely within dispatchResultCallback - # resulting in much gnashing of teeth. - self.outstandingNodes = document.childNodes[:] + [1] - self.outstandingNodes.reverse() - - self.outstandingCallbacks += 1 - self.handleOutstanding(request) - self.outstandingCallbacks -= 1 - if not self.outstandingCallbacks: - return self.sendPage(request) - except: - self.renderFailure(None, request) - - def handleOutstanding(self, request): - while self.outstandingNodes: - node = self.outstandingNodes.pop() - if node is 1: - self.modelStack = self.modelStack[1] - self.viewStack = self.viewStack[1] - if self.controllerStack is not None: - controller, self.controllerStack = self.controllerStack - if controller is not None: - controller.exit(request) - attrs = getattr(node, 'attributes', None) - if (attrs is not None and - (attrs.get('model') or attrs.get('view') or attrs.get('controller'))): - self.outstandingNodes.append(1) - self.handleNode(request, node) - else: - if attrs is not None and (attrs.get('view') or attrs.get('controller')): - self.outstandingNodes.append(node) - if hasattr(node, 'childNodes') and node.childNodes: - self.recurseChildren(request, node) - - def recurseChildren(self, request, node): - """If this node has children, handle them. - """ - new = node.childNodes[:] - new.reverse() - self.outstandingNodes.extend(new) - - def dispatchResult(self, request, node, result): - """Check a given result from handling a node and look up a NodeMutator - adapter which will convert the result into a node and insert it - into the DOM tree. Return the new node. - """ - if not isinstance(result, defer.Deferred): - if node.parentNode is not None: - node.parentNode.replaceChild(result, node) - else: - raise RuntimeError, "We're dying here, please report this immediately" - else: - self.outstandingCallbacks += 1 - result.addCallback(self.dispatchResultCallback, request, node) - result.addErrback(self.renderFailure, request) - # Got to wait until the callback comes in - return result - - def modelChanged(self, changed): - """Rerender this view, because our model has changed. - """ - # arg. this needs to go away. - request = changed.get('request', None) - oldNode = self.node - #import pdb; pdb.set_trace() - newNode = self.generate(request, oldNode) - returnNode = self.dispatchResult(request, oldNode, newNode) - self.handleNewNode(request, returnNode) - self.handleOutstanding(request) - self.controller.domChanged(request, self, returnNode) - - def generate(self, request, node): - """Allow a view to be used like a widget. Will look up the template - file and return it in place of the incoming node. - """ - newNode = self.lookupTemplate(request).childNodes[0] - newNode.setAttribute('id', 'woven_id_%s' % id(self)) - self.node = newNode - return newNode - - def setController(self, controller): - self.controller = controller - self.controllerStack = (controller, self.controllerStack) - - def setNode(self, node): - if self.templateNode == None: - self.templateNode = node - self.node = node - - def setSubmodel(self, name): - self.submodel = name - - def getNodeModel(self, request, node, submodel): - """ - Get the model object associated with this node. If this node has a - model= attribute, call getSubmodel on the current model object. - If not, return the top of the model stack. - """ - parent = None - if submodel: - if submodel == '.': - m = peek(self.modelStack) - else: - modelStack = self.modelStack - while modelStack is not None: - parent, modelStack = modelStack - if parent is None: - continue - m = parent.lookupSubmodel(request, submodel) - if m is not None: - #print "model", m - break - else: - raise Exception("Node had a model=%s " - "attribute, but the submodel was not " - "found in %s." % (submodel, - filterStack(self.modelStack))) - else: - m = None - self.modelStack = (m, self.modelStack) - if m is not None: -# print "M NAME", m.name -# if parent is not m: -# m.parent = parent -# if not getattr(m, 'name', None): -# m.name = submodel - return m - #print `submodel`, self.getTopOfModelStack() - if submodel: - return peek(self.modelStack) - return None - - def getNodeController(self, request, node, submodel, model): - """ - Get a controller object to handle this node. If the node has no - controller= attribute, first check to see if there is an IController - adapter for our model. - """ - controllerName = node.attributes.get('controller') - controller = None - - if model is None: - model = peek(self.modelStack) - - # Look up a controller factory. - if controllerName: - #if not node.hasAttribute('name'): - # warnings.warn("POTENTIAL ERROR: %s had a controller, but not a " - # "'name' attribute." % node) - controllerStack = self.controllerStack - while controllerStack is not None: - namespace, controllerStack = controllerStack - if namespace is None: - continue - controller = namespace.getSubcontroller(request, node, model, controllerName) - if controller is not None: - break - else: - raise NotImplementedError("You specified controller name %s on " - "a node, but no wcfactory_%s method " - "was found in %s." % (controllerName, - controllerName, - filterStack(self.controllerStack) - )) - elif node.attributes.get("model"): - # If no "controller" attribute was specified on the node, see if - # there is a IController adapter registerred for the model. - controller = interfaces.IController( - model, - None) - - return controller - - - def getSubview(self, request, node, model, viewName): - """Get a sub-view from me. - - @returns: L{widgets.Widget} - """ - view = None - vm = getattr(self, 'wvfactory_' + viewName, None) - if vm is None: - vm = getattr(self, 'factory_' + viewName, None) - if vm is not None: - warnings.warn("factory_ methods are deprecated; please use " - "wvfactory_ instead", DeprecationWarning) - if vm: - if vm.func_code.co_argcount == 3 and not type(vm) == types.LambdaType: - warnings.warn("wvfactory_ methods take (request, node, " - "model) instead of (request, node) now. \n" - "Please instantiate your widgets with a " - "reference to model instead of self.model", - DeprecationWarning) - self.model = model - view = vm(request, node) - self.model = self.mainModel - else: - view = vm(request, node, model) - - setupMethod = getattr(self, 'wvupdate_' + viewName, None) - if setupMethod: - if view is None: - view = widgets.Widget(model) - view.setupMethods.append(setupMethod) - return view - - - def getNodeView(self, request, node, submodel, model): - view = None - viewName = node.attributes.get('view') - - if model is None: - model = peek(self.modelStack) - - # Look up a view factory. - if viewName: - viewStack = self.viewStack - while viewStack is not None: - namespace, viewStack = viewStack - if namespace is None: - continue - try: - view = namespace.getSubview(request, node, model, viewName) - except AttributeError: - # Was that from something in the viewStack that didn't - # have a getSubview? - if not hasattr(namespace, "getSubview"): - log.msg("Warning: There is no getSubview on %r" % - (namespace,)) - continue - else: - # No, something else is really broken. - raise - if view is not None: - break - else: - raise NotImplementedError( - "You specified view name %s on a node %s, but no " - "wvfactory_%s method was found in %s. (Or maybe they were " - "found but they returned None.)" % ( - viewName, node, viewName, - filterStack(self.viewStack))) - elif node.attributes.get("model"): - # If no "view" attribute was specified on the node, see if there - # is a IView adapter registerred for the model. - # First, see if the model is Componentized. - if isinstance(model, components.Componentized): - view = model.getAdapter(interfaces.IView) - if not view and hasattr(model, '__class__'): - view = interfaces.IView(model, None) - - return view - - def handleNode(self, request, node): - submodelName = node.attributes.get('model') - if submodelName is None: - submodelName = "" - model = self.getNodeModel(request, node, submodelName) - view = self.getNodeView(request, node, submodelName, model) - controller = self.getNodeController(request, node, submodelName, model) - if view or controller: - if model is None: - model = peek(self.modelStack) - if not view or not isinstance(view, View): - view = widgets.DefaultWidget(model) - - if not controller: - controller = input.DefaultHandler(model) - - prevView, stack = self.viewStack - while isinstance(prevView, widgets.DefaultWidget) and stack is not None: - prevView, stack = stack - if prevView is None: - prevMod = None - else: - prevMod = prevView.model - if model is not prevMod and not isinstance(view, widgets.DefaultWidget): - model.addView(view) - submodelList = [x.name for x in filterStack(self.modelStack) if x.name] - submodelList.reverse() - submodelName = '/'.join(submodelList) - if not getattr(view, 'submodel', None): - view.submodel = submodelName - - theId = node.attributes.get("id") - if self.livePage and not theId: - theId = "woven_id_%d" % id(view) - view.setupMethods.append(utils.createSetIdFunction(theId)) - view.outgoingId = theId - #print "SET AN ID", theId - self.subviews[theId] = view - view.parent = peek(self.viewStack) - view.parent.subviews[theId] = view - # If a Widget was constructed directly with a model that so far - # is not in modelspace, we should put it on the stack so other - # Widgets below this one can find it. - if view.model is not peek(self.modelStack): - self.modelStack = poke(self.modelStack, view.model) - - cParent = peek(self.controllerStack) - if controller._parent is None or cParent != controller: - controller._parent = cParent - - self.controllerStack = (controller, self.controllerStack) - self.viewStack = (view, self.viewStack) - - view.viewStack = self.viewStack - view.controllerStack = self.controllerStack - view.modelStack = self.modelStack - - view.setController(controller) - view.setNode(node) - - if not getattr(controller, 'submodel', None): - controller.setSubmodel(submodelName) - - controller.setView(view) - controller.setNode(node) - - controllerResult = controller.handle(request) - if controllerResult is not None: - ## It's a deferred - controller - self.outstandingCallbacks += 1 - controllerResult.addCallback( - self.handleControllerResults, - request, - node, - controller, - view) - controllerResult.addErrback(self.renderFailure, request) - else: - viewResult = view.generate(request, node) - returnNode = self.dispatchResult(request, node, viewResult) - self.handleNewNode(request, returnNode) - else: - self.controllerStack = (controller, self.controllerStack) - self.viewStack = (view, self.viewStack) - - def handleControllerResults(self, - controllerResult, request, node, controller, view): - """Handle a deferred from a controller. - """ - self.outstandingCallbacks -= 1 - if isinstance(controllerResult, defer.Deferred): - self.outstandingCallbacks += 1 - controllerResult.addCallback( - self.handleControllerResults, - request, - node, - controller, - view) - controllerResult.addErrback(self.renderFailure, request) - else: - viewResult = view.generate(request, node) - returnNode = self.dispatchResult(request, node, viewResult) - self.handleNewNode(request, returnNode) - return controllerResult - - def handleNewNode(self, request, returnNode): - if not isinstance(returnNode, defer.Deferred): - self.recurseChildren(request, returnNode) - else: - # TODO: Need to handle deferreds here? - pass - - def sendPage(self, request): - """ - Check to see if handlers recorded any errors before sending the page - """ - self.doneCallback(self, self.d, request) - - def setSubviewFactory(self, name, factory, setup=None, *args, **kwargs): - setattr(self, "wvfactory_" + name, lambda request, node, m: - factory(m, *args, **kwargs)) - if setup: - setattr(self, "wvupdate_" + name, setup) - - def __setitem__(self, key, value): - pass - - def unlinkViews(self): - #print "unlinking views" - self.model.removeView(self) - for key, value in self.subviews.items(): - value.unlinkViews() -# value.model.removeView(value) - - def dispatchResultCallback(self, result, request, node): - """Deal with a callback from a deferred, checking to see if it is - ok to send the page yet or not. - """ - self.outstandingCallbacks -= 1 - #node = self.dispatchResult(request, node, result) - #self.recurseChildren(request, node) - if not self.outstandingCallbacks: - self.sendPage(request) - return result - - def renderFailure(self, failure, request): - try: - xml = request.d.toprettyxml() - except: - xml = "" -# if not hasattr(request, 'channel'): -# log.msg("The request got away from me before I could render an error page.") -# log.err(failure) -# return failure - if not self.failed: - self.failed = 1 - if failure: - request.write("<html><head><title>%s: %s</title></head><body>\n" % (html.escape(str(failure.type)), html.escape(str(failure.value)))) - else: - request.write("<html><head><title>Failure!</title></head><body>\n") - utils.renderFailure(failure, request) - request.write("<h3>Here is the partially processed DOM:</h3>") - request.write("\n<pre>\n") - request.write(html.escape(xml)) - request.write("\n</pre>\n") - request.write("</body></html>") - request.finish() - return failure - -class LiveView(View): - livePage = 1 - def wvfactory_webConduitGlue(self, request, node, m): - if request.getHeader("user-agent").count("MSIE"): - return View(m, templateFile="FlashConduitGlue.html") - else: - return View(m, templateFile="WebConduitGlue.html") - - def wvupdate_woven_flashConduitSessionView(self, request, wid, mod): - #print "updating flash thingie" - uid = request.getSession().uid - n = wid.templateNode - if n.attributes.has_key('src'): - n.attributes['src'] = n.attributes.get('src') + '?twisted_session=' + str(uid) - else: - n.attributes['value'] = n.attributes.get('value') + '?twisted_session=' + str(uid) - #print wid.templateNode.toxml() - - -#backwards compatibility -WView = View - - -def registerViewForModel(view, model): - """ - Registers `view' as an adapter of `model' for L{interfaces.IView}. - """ - components.registerAdapter(view, model, interfaces.IView) -# adapter = resource.IResource(model, None) -# if adapter is None and resource.IResource.providedBy(view): -# components.registerAdapter(view, model, resource.IResource) - - - -#sibling imports:: - -# If no widget/handler was found in the container controller or view, these -# modules will be searched. - -import input -import widgets - diff --git a/tools/buildbot/pylibs/twisted/web/woven/widgets.py b/tools/buildbot/pylibs/twisted/web/woven/widgets.py deleted file mode 100644 index 6028338..0000000 --- a/tools/buildbot/pylibs/twisted/web/woven/widgets.py +++ /dev/null @@ -1,1036 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_woven -*- -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -# DOMWidgets - -from __future__ import nested_scopes - -import urllib -import warnings -from twisted.web.microdom import parseString, Element, Node -from twisted.web import domhelpers - - -#sibling imports -import model -import template -import view -import utils -import interfaces - -from twisted.python import components, failure -from twisted.python import reflect -from twisted.python import log -from twisted.internet import defer - -viewFactory = view.viewFactory -document = parseString("<xml />", caseInsensitive=0, preserveCase=0) - -missingPattern = Element("div", caseInsensitive=0, preserveCase=0) -missingPattern.setAttribute("style", "border: dashed red 1px; margin: 4px") - -""" -DOMWidgets are views which can be composed into bigger views. -""" - -DEBUG = 0 - -_RAISE = 1 - -class Dummy: - pass - -class Widget(view.View): - """ - A Widget wraps an object, its model, for display. The model can be a - simple Python object (string, list, etc.) or it can be an instance - of L{model.Model}. (The former case is for interface purposes, so that - the rest of the code does not have to treat simple objects differently - from Model instances.) - - If the model is-a Model, there are two possibilities: - - - we are being called to enable an operation on the model - - we are really being called to enable an operation on an attribute - of the model, which we will call the submodel - - @cvar tagName: The tag name of the element that this widget creates. If this - is None, then the original Node will be cloned. - @cvar wantsAllNotifications: Indicate that this widget wants to recieve every - change notification from the main model, not just notifications that affect - its model. - @ivar model: If the current model is an L{model.Model}, then the result of - model.getData(). Otherwise the original object itself. - """ - # wvupdate_xxx method signature: request, widget, data; returns None - - # Don't do lots of work setting up my stacks; they will be passed to me - setupStacks = 0 - - # Should we clear the node before we render the widget? - clearNode = 0 - - # If some code has to ask if a widget is livePage, the answer is yes - livePage = 1 - - tagName = None - def __init__(self, model = None, submodel = None, setup = None, controller = None, viewStack=None, *args, **kwargs): - """ - @type model: L{interfaces.IModel} - - @param submodel: see L{Widget.setSubmodel} - @type submodel: String - - @type setup: Callable - """ - self.errorFactory = Error - self.controller = controller - self.become = None - self._reset() - view.View.__init__(self, model) - self.node = None - self.templateNode = None - if submodel: - self.submodel = submodel - else: - self.submodel = "" - if setup: - self.setupMethods = [setup] - else: - self.setupMethods = [] - self.viewStack = viewStack - self.initialize(*args, **kwargs) - - def _reset(self): - self.attributes = {} - self.slots = {} - self._children = [] - - def initialize(self, *args, **kwargs): - """ - Use this method instead of __init__ to initialize your Widget, so you - don't have to deal with calling the __init__ of the superclass. - """ - pass - - def setSubmodel(self, submodel): - """ - I use the submodel to know which attribute in self.model I am responsible for - """ - self.submodel = submodel - - def getData(self, request=None): - """ - I have a model; however since I am a widget I am only responsible - for a portion of that model. This method returns the portion I am - responsible for. - - The return value of this may be a Deferred; if it is, then - L{setData} will be called once the result is available. - """ - return self.model.getData(request) - - def setData(self, request=None, data=None): - """ - If the return value of L{getData} is a Deferred, I am called - when the result of the Deferred is available. - """ - self.model.setData(request, data) - - def add(self, item): - """ - Add `item' to the children of the resultant DOM Node of this widget. - - @type item: A DOM node or L{Widget}. - """ - self._children.append(item) - - def appendChild(self, item): - """ - Add `item' to the children of the resultant DOM Node of this widget. - - @type item: A DOM node or L{Widget}. - """ - self._children.append(item) - - def insert(self, index, item): - """ - Insert `item' at `index' in the children list of the resultant DOM Node - of this widget. - - @type item: A DOM node or L{Widget}. - """ - self._children.insert(index, item) - - def setNode(self, node): - """ - Set a node for this widget to use instead of creating one programatically. - Useful for looking up a node in a template and using that. - """ - # self.templateNode should always be the original, unmutated - # node that was in the HTML template. - if self.templateNode == None: - self.templateNode = node - self.node = node - - def cleanNode(self, node): - """ - Do your part, prevent infinite recursion! - """ - if not DEBUG: - if node.attributes.has_key('model'): - del node.attributes['model'] - if node.attributes.has_key('view'): - del node.attributes['view'] - if node.attributes.has_key('controller'): - del node.attributes['controller'] - return node - - def generate(self, request, node): - data = self.getData(request) - if isinstance(data, defer.Deferred): - data.addCallback(self.setDataCallback, request, node) - data.addErrback(utils.renderFailure, request) - return data - return self._regenerate(request, node, data) - - def _regenerate(self, request, node, data): - self._reset() - self.setUp(request, node, data) - for setupMethod in self.setupMethods: - setupMethod(request, self, data) - # generateDOM should always get a reference to the - # templateNode from the original HTML - result = self.generateDOM(request, self.templateNode or node) - if DEBUG: - result.attributes['woven_class'] = reflect.qual(self.__class__) - return result - - def setDataCallback(self, result, request, node): - if isinstance(self.getData(request), defer.Deferred): - self.setData(request, result) - data = self.getData(request) - if isinstance(data, defer.Deferred): - import warnings - warnings.warn("%r has returned a Deferred multiple times for the " - "same request; this is a potential infinite loop." - % self.getData) - data.addCallback(self.setDataCallback, request, node) - data.addErrback(utils.renderFailure, request) - return data - - newNode = self._regenerate(request, node, result) - returnNode = self.dispatchResult(request, node, newNode) - # isinstance(Element) added because I was having problems with - # this code trying to call setAttribute on my RawTexts -radix 2003-5-28 - if hasattr(self, 'outgoingId') and isinstance(returnNode, Element): - returnNode.attributes['id'] = self.outgoingId - self.handleNewNode(request, returnNode) - self.handleOutstanding(request) - if self.subviews: - self.getTopModel().subviews.update(self.subviews) - self.controller.domChanged(request, self, returnNode) - - ## We need to return the result along the callback chain - ## so that any other views which added a setDataCallback - ## to the same deferred will get the correct data. - return result - - def setUp(self, request, node, data): - """ - Override this method to set up your Widget prior to generateDOM. This - is a good place to call methods like L{add}, L{insert}, L{__setitem__} - and L{__getitem__}. - - Overriding this method obsoletes overriding generateDOM directly, in - most cases. - - @type request: L{twisted.web.server.Request}. - @param node: The DOM node which this Widget is operating on. - @param data: The Model data this Widget is meant to operate upon. - """ - pass - - def generateDOM(self, request, node): - """ - @returns: A DOM Node to replace the Node in the template that this - Widget handles. This Node is created based on L{tagName}, - L{children}, and L{attributes} (You should populate these - in L{setUp}, probably). - """ - if self.become: - #print "becoming" - become = self.become - self.become = None - parent = node.parentNode - node.parentNode = None - old = node.cloneNode(1) - node.parentNode = parent - gen = become.generateDOM(request, node) - if old.attributes.has_key('model'): - del old.attributes['model'] - del old.attributes['controller'] - gen.appendChild(old) - self.node = gen - return gen - if DEBUG: - template = node.toxml() - log.msg(template) - if not self.tagName: - self.tagName = self.templateNode.tagName - if node is not self.templateNode or self.tagName != self.templateNode.tagName: - parent = node.parentNode - node = document.createElement(self.tagName, caseInsensitive=0, preserveCase=0) - node.parentNode = parent - else: - parentNode = node.parentNode - node.parentNode = None - if self.clearNode: - new = node.cloneNode(0) - else: - new = node.cloneNode(1) - node.parentNode = parentNode - node = self.cleanNode(new) - #print "NICE CLEAN NODE", node.toxml(), self._children - node.attributes.update(self.attributes) - for item in self._children: - if hasattr(item, 'generate'): - parentNode = node.parentNode - node.parentNode = None - item = item.generate(request, node.cloneNode(1)) - node.parentNode = parentNode - node.appendChild(item) - #print "WE GOT A NODE", node.toxml() - self.node = node - return self.node - - def modelChanged(self, payload): - request = payload.get('request', None) - if request is None: - request = Dummy() - request.d = document - oldNode = self.node - if payload.has_key(self.submodel): - data = payload[self.submodel] - else: - data = self.getData(request) - newNode = self._regenerate(request, oldNode, data) - returnNode = self.dispatchResult(request, oldNode, newNode) - # shot in the dark: this seems to make *my* code work. probably will - # break if returnNode returns a Deferred, as it's supposed to be able - # to do -glyph -# self.viewStack.push(self) -# self.controller.controllerStack.push(self.controller) - self.handleNewNode(request, returnNode) - self.handleOutstanding(request) - self.controller.domChanged(request, self, returnNode) - - def __setitem__(self, item, value): - """ - Convenience syntax for adding attributes to the resultant DOM Node of - this widget. - """ - assert value is not None - self.attributes[item] = value - - setAttribute = __setitem__ - - def __getitem__(self, item): - """ - Convenience syntax for getting an attribute from the resultant DOM Node - of this widget. - """ - return self.attributes[item] - - getAttribute = __getitem__ - - def setError(self, request, message): - """ - Convenience method for allowing a Controller to report an error to the - user. When this is called, a Widget of class self.errorFactory is instanciated - and set to self.become. When generate is subsequently called, self.become - will be responsible for mutating the DOM instead of this widget. - """ - #print "setError called", self - id = self.attributes.get('id', '') - - self.become = self.errorFactory(self.model, message) - self.become['id'] = id -# self.modelChanged({'request': request}) - - def getTopModel(self): - """Get a reference to this page's top model object. - """ - top = self.model - while top.parent is not None: - top = top.parent - return top - - def getAllPatterns(self, name, default=missingPattern, clone=1, deep=1): - """Get all nodes below this one which have a matching pattern attribute. - """ - if self.slots.has_key(name): - slots = self.slots[name] - else: - sm = self.submodel.split('/')[-1] - slots = domhelpers.locateNodes(self.templateNode, name + 'Of', sm) - if not slots: -# slots = domhelpers.locateNodes(self.templateNode, "pattern", name, noNesting=1) - matcher = lambda n, name=name: isinstance(n, Element) and \ - n.attributes.has_key("pattern") and n.attributes["pattern"] == name - recurseMatcher = lambda n: isinstance(n, Element) and not n.attributes.has_key("view") and not n.attributes.has_key('model') - slots = domhelpers.findNodesShallowOnMatch(self.templateNode, matcher, recurseMatcher) - if not slots: - msg = 'WARNING: No template nodes were found '\ - '(tagged %s="%s"'\ - ' or pattern="%s") for node %s (full submodel path %s)' % (name + "Of", - sm, name, self.templateNode, `self.submodel`) - if default is _RAISE: - raise Exception(msg) - if DEBUG: - warnings.warn(msg) - if default is missingPattern: - newNode = missingPattern.cloneNode(1) - newNode.appendChild(document.createTextNode(msg)) - return [newNode] - if default is None: - return None - return [default] - self.slots[name] = slots - if clone: - return [x.cloneNode(deep) for x in slots] - return slots - - def getPattern(self, name, default=missingPattern, clone=1, deep=1): - """Get a named slot from the incoming template node. Returns a copy - of the node and all its children. If there was more than one node with - the same slot identifier, they will be returned in a round-robin fashion. - """ - slots = self.getAllPatterns(name, default=default, clone=0) - if slots is None: - return None - slot = slots.pop(0) - slots.append(slot) - if clone: - parentNode = slot.parentNode - slot.parentNode = None - clone = slot.cloneNode(deep) - if clone.attributes.has_key('pattern'): - del clone.attributes['pattern'] - elif clone.attributes.has_key(name + 'Of'): - del clone.attributes[name + 'Of'] - slot.parentNode = parentNode - if DEBUG: - clone.attributes['ofPattern'] = name + 'Of' - clone.attributes['nameOf'] = self.submodel.split('/')[-1] - return clone - if DEBUG: - slot.attributes['ofPattern'] = name + 'Of' - slot.attributes['nameOf'] = self.submodel.split('/')[-1] - return slot - - def addUpdateMethod(self, updateMethod): - """Add a method to this widget that will be called when the widget - is being rendered. The signature for this method should be - updateMethod(request, widget, data) where widget will be the - instance you are calling addUpdateMethod on. - """ - self.setupMethods.append(updateMethod) - - def addEventHandler(self, eventName, handler, *args): - """Add an event handler to this widget. eventName is a string - indicating which javascript event handler should cause this - handler to fire. Handler is a callable that has the signature - handler(request, widget, *args). - """ - def handlerUpdateStep(request, widget, data): - extraArgs = '' - for x in args: - extraArgs += " ,'" + x.replace("'", "\\'") + "'" - widget[eventName] = "return woven_eventHandler('%s', this%s)" % (eventName, extraArgs) - setattr(self, 'wevent_' + eventName, handler) - self.addUpdateMethod(handlerUpdateStep) - - def onEvent(self, request, eventName, *args): - """Dispatch a client-side event to an event handler that was - registered using addEventHandler. - """ - eventHandler = getattr(self, 'wevent_' + eventName, None) - if eventHandler is None: - raise NotImplementedError("A client side '%s' event occurred," - " but there was no event handler registered on %s." % - (eventName, self)) - - eventHandler(request, self, *args) - - -class DefaultWidget(Widget): - def generate(self, request, node): - """ - By default, we just return the node unchanged - """ - self.cleanNode(node) - if self.become: - become = self.become - self.become = None - parent = node.parentNode - node.parentNode = None - old = node.cloneNode(1) - node.parentNode = parent - gen = become.generateDOM(request, node) - del old.attributes['model'] - gen.appendChild(self.cleanNode(old)) - return gen - return node - - def modelChanged(self, payload): - """We're not concerned if the model has changed. - """ - pass - - -class Attributes(Widget): - """Set attributes on a node. - - Assumes model is a dictionary of attributes. - """ - - def setUp(self, request, node, data): - for k, v in data.items(): - self[k] = v - - -class Text(Widget): - """ - A simple Widget that renders some text. - """ - def __init__(self, model, raw=0, clear=1, *args, **kwargs): - """ - @param model: The text to render. - @type model: A string or L{model.Model}. - @param raw: A boolean that specifies whether to render the text as - a L{domhelpers.RawText} or as a DOM TextNode. - """ - self.raw = raw - self.clearNode = clear - Widget.__init__(self, model, *args, **kwargs) - - def generate(self, request, node): - if self.templateNode is None: - if self.raw: - return domhelpers.RawText(str(self.getData(request))) - else: - return document.createTextNode(str(self.getData(request))) - return Widget.generate(self, request, node) - - def setUp(self, request, node, data): - if self.raw: - textNode = domhelpers.RawText(str(data)) - else: - textNode = document.createTextNode(str(data)) - self.appendChild(textNode) - - -class ParagraphText(Widget): - """ - Like a normal text widget, but it takes line breaks in the text and - formats them as HTML paragraphs. - """ - def setUp(self, request, node, data): - nSplit = data.split('\n') - for line in nSplit: - if line.strip(): - para = request.d.createElement('p', caseInsensitive=0, preserveCase=0) - para.appendChild(request.d.createTextNode(line)) - self.add(para) - -class Image(Widget): - """ - A simple Widget that creates an `img' tag. - """ - tagName = 'img' - border = '0' - def setUp(self, request, node, data): - self['border'] = self.border - self['src'] = data - - -class Error(Widget): - tagName = 'span' - def __init__(self, model, message="", *args, **kwargs): - Widget.__init__(self, model, *args, **kwargs) - self.message = message - - def generateDOM(self, request, node): - self['style'] = 'color: red' - self.add(Text(" " + self.message)) - return Widget.generateDOM(self, request, node) - - -class Div(Widget): - tagName = 'div' - - -class Span(Widget): - tagName = 'span' - - -class Br(Widget): - tagName = 'br' - - -class Input(Widget): - tagName = 'input' - def setSubmodel(self, submodel): - self.submodel = submodel - self['name'] = submodel - - def setUp(self, request, node, data): - if not self.attributes.has_key('name') and not node.attributes.get('name'): - if self.submodel: - id = self.submodel - else: - id = self.attributes.get('id', node.attributes.get('id')) - self['name'] = id - if data is None: - data = '' - if not self.attributes.has_key('value'): - self['value'] = str(data) - - -class CheckBox(Input): - def setUp(self, request, node, data): - self['type'] = 'checkbox' - Input.setUp(self, request, node, data) - - -class RadioButton(Input): - def setUp(self, request, node, data): - self['type'] = 'radio' - Input.setUp(self, request, node, data) - - -class File(Input): - def setUp(self, request, node, data): - self['type'] = 'file' - Input.setUp(self, request, node, data) - - -class Hidden(Input): - def setUp(self, request, node, data): - self['type'] = 'hidden' - Input.setUp(self, request, node, data) - - -class InputText(Input): - def setUp(self, request, node, data): - self['type'] = 'text' - Input.setUp(self, request, node, data) - - -class PasswordText(Input): - """ - I render a password input field. - """ - def setUp(self, request, node, data): - self['type'] = 'password' - Input.setUp(self, request, node, data) - - -class Button(Input): - def setUp(self, request, node, data): - self['type'] = 'button' - Input.setUp(self, request, node, data) - - -class Select(Input): - tagName = 'select' - - -class Option(Widget): - tagName = 'option' - def initialize(self): - self.text = '' - - def setText(self, text): - """ - Set the text to be displayed within the select menu. - """ - self.text = text - - def setValue(self, value): - self['value'] = str(value) - - def setUp(self, request, node, data): - self.add(Text(self.text or data)) - if data is None: - data = '' - if not self.attributes.has_key('value'): - self['value'] = str(data) - -class Anchor(Widget): - tagName = 'a' - trailingSlash = '' - def initialize(self): - self.baseHREF = '' - self.parameters = {} - self.raw = 0 - self.text = '' - - def setRaw(self, raw): - self.raw = raw - - def setLink(self, href): - self.baseHREF= href - - def setParameter(self, key, value): - self.parameters[key] = value - - def setText(self, text): - self.text = text - - def setUp(self, request, node, data): - href = self.baseHREF - params = urllib.urlencode(self.parameters) - if params: - href = href + '?' + params - self['href'] = href or str(data) + self.trailingSlash - if data is None: - data = "" - self.add(Text(self.text or data, self.raw, 0)) - - -class SubAnchor(Anchor): - def initialize(self): - warnings.warn( - "SubAnchor is deprecated, you might want either Anchor or DirectoryAnchor", - DeprecationWarning) - Anchor.initialize(self) - - - -class DirectoryAnchor(Anchor): - trailingSlash = '/' - - -def appendModel(newNode, modelName): - if newNode is None: return - curModel = newNode.attributes.get('model') - if curModel is None: - newModel = str(modelName) - else: - newModel = '/'.join((curModel, str(modelName))) - newNode.attributes['model'] = newModel - - -class List(Widget): - """ - I am a widget which knows how to generateDOM for a python list. - - A List should be specified in the template HTML as so:: - - | <ul model="blah" view="List"> - | <li pattern="emptyList">This will be displayed if the list - | is empty.</li> - | <li pattern="listItem" view="Text">Foo</li> - | </ul> - - If you have nested lists, you may also do something like this:: - - | <table model="blah" view="List"> - | <tr pattern="listHeader"><th>A</th><th>B</th></tr> - | <tr pattern="emptyList"><td colspan='2'>***None***</td></tr> - | <tr pattern="listItem"> - | <td><span view="Text" model="1" /></td> - | <td><span view="Text" model="2" /></td> - | </tr> - | <tr pattern="listFooter"><td colspan="2">All done!</td></tr> - | </table> - - Where blah is the name of a list on the model; eg:: - - | self.model.blah = ['foo', 'bar'] - - """ - tagName = None - defaultItemView = "DefaultWidget" - def generateDOM(self, request, node): - node = Widget.generateDOM(self, request, node) - listHeaders = self.getAllPatterns('listHeader', None) - listFooters = self.getAllPatterns('listFooter', None) - emptyLists = self.getAllPatterns('emptyList', None) - domhelpers.clearNode(node) - if listHeaders: - node.childNodes.extend(listHeaders) - for n in listHeaders: n.parentNode = node - data = self.getData(request) - if data: - self._iterateData(node, self.submodel, data) - elif emptyLists: - node.childNodes.extend(emptyLists) - for n in emptyLists: n.parentNode = node - if listFooters: - node.childNodes.extend(listFooters) - for n in listFooters: n.parentNode = node - return node - - def _iterateData(self, parentNode, submodel, data): - currentListItem = 0 - retVal = [None] * len(data) - for itemNum in range(len(data)): - # theory: by appending copies of the li node - # each node will be handled once we exit from - # here because handleNode will then recurse into - # the newly appended nodes - - newNode = self.getPattern('listItem') - if newNode.getAttribute('model') == '.': - newNode.removeAttribute('model') - elif not newNode.attributes.get("view"): - newNode.attributes["view"] = self.defaultItemView - appendModel(newNode, itemNum) - retVal[itemNum] = newNode - newNode.parentNode = parentNode -# parentNode.appendChild(newNode) - parentNode.childNodes.extend(retVal) - - -class KeyedList(List): - """ - I am a widget which knows how to display the values stored within a - Python dictionary.. - - A KeyedList should be specified in the template HTML as so:: - - | <ul model="blah" view="KeyedList"> - | <li pattern="emptyList">This will be displayed if the list is - | empty.</li> - | <li pattern="keyedListItem" view="Text">Foo</li> - | </ul> - - I can take advantage of C{listHeader}, C{listFooter} and C{emptyList} - items just as a L{List} can. - """ - def _iterateData(self, parentNode, submodel, data): - """ - """ - currentListItem = 0 - keys = data.keys() - # Keys may be a tuple, if this is not a true dictionary but a dictionary-like object - if hasattr(keys, 'sort'): - keys.sort() - for key in keys: - newNode = self.getPattern('keyedListItem') - if not newNode: - newNode = self.getPattern('item', _RAISE) - if newNode: - warnings.warn("itemOf= is deprecated, " - "please use listItemOf instead", - DeprecationWarning) - - appendModel(newNode, key) - if not newNode.attributes.get("view"): - newNode.attributes["view"] = "DefaultWidget" - parentNode.appendChild(newNode) - - -class ColumnList(Widget): - def __init__(self, model, columns=1, start=0, end=0, *args, **kwargs): - Widget.__init__(self, model, *args, **kwargs) - self.columns = columns - self.start = start - self.end = end - - def setColumns(self, columns): - self.columns = columns - - def setStart(self, start): - self.start = start - - def setEnd(self, end): - self.end = end - - def setUp(self, request, node, data): - pattern = self.getPattern('columnListRow', clone=0) - if self.end: - listSize = self.end - self.start - if listSize > len(data): - listSize = len(data) - else: - listSize = len(data) - for itemNum in range(listSize): - if itemNum % self.columns == 0: - row = self.getPattern('columnListRow') - domhelpers.clearNode(row) - node.appendChild(row) - - newNode = self.getPattern('columnListItem') - - appendModel(newNode, itemNum + self.start) - if not newNode.attributes.get("view"): - newNode.attributes["view"] = "DefaultWidget" - row.appendChild(newNode) - node.removeChild(pattern) - return node - - -class Bold(Widget): - tagName = 'b' - - -class Table(Widget): - tagName = 'table' - - -class Row(Widget): - tagName = 'tr' - - -class Cell(Widget): - tagName = 'td' - - -class RawText(Widget): - def generateDOM(self, request, node): - self.node = domhelpers.RawText(self.getData(request)) - return self.node - -from types import StringType - -class Link(Widget): - """A utility class for generating <a href='foo'>bar</a> tags. - """ - tagName = 'a' - def setUp(self, request, node, data): - # TODO: we ought to support Deferreds here for both text and href! - if isinstance(data, StringType): - node.tagName = self.tagName - node.attributes["href"] = data - else: - data = self.model - txt = data.getSubmodel(request, "text").getData(request) - if not isinstance(txt, Node): - txt = document.createTextNode(txt) - lnk = data.getSubmodel(request, "href").getData(request) - self['href'] = lnk - node.tagName = self.tagName - domhelpers.clearNode(node) - node.appendChild(txt) - -class RootRelativeLink(Link): - """ - Just like a regular Link, only it makes the href relative to the - appRoot (that is, request.getRootURL()). - """ - def setUp(self, request, node, data): - # hack, hack: some juggling so I can type less and share more - # code with Link - st = isinstance(data, StringType) - if st: - data = request.getRootURL() + '/' + data - Link.setUp(self, request, node, data) - if not st: - self['href'] = request.getRootURL() + '/' + self['href'] - -class ExpandMacro(Widget): - """A Macro expansion widget modeled after the METAL expander - in ZPT/TAL/METAL. Usage: - - In the Page that is being rendered, place the ExpandMacro widget - on the node you want replaced with the Macro, and provide nodes - tagged with fill-slot= attributes which will fill slots in the Macro:: - - def wvfactory_myMacro(self, request, node, model): - return ExpandMacro( - model, - macroFile="MyMacro.html", - macroName="main") - - <div view="myMacro"> - <span fill-slot="greeting">Hello</span> - <span fill-slot="greetee">World</span> - </div> - - Then, in your Macro template file ("MyMacro.html" in the above - example) designate a node as the macro node, and nodes - inside that as the slot nodes:: - - <div macro="main"> - <h3><span slot="greeting" />, <span slot="greetee" />!</h3> - </div> - """ - def __init__(self, model, macroTemplate = "", macroFile="", macroFileDirectory="", macroName="", **kwargs): - self.macroTemplate = macroTemplate - self.macroFile=macroFile - self.macroFileDirectory=macroFileDirectory - self.macroName=macroName - Widget.__init__(self, model, **kwargs) - - def generate(self, request, node): - if self.macroTemplate: - templ = view.View( - self.model, - template = self.macroTemplate).lookupTemplate(request) - else: - templ = view.View( - self.model, - templateFile=self.macroFile, - templateDirectory=self.macroFileDirectory).lookupTemplate(request) - - ## We are going to return the macro node from the metatemplate, - ## after replacing any slot= nodes in it with fill-slot= nodes from `node' - macrolist = domhelpers.locateNodes(templ.childNodes, "macro", self.macroName) - assert len(macrolist) == 1, ("No macro or more than " - "one macro named %s found." % self.macroName) - - macro = macrolist[0] - del macro.attributes['macro'] - slots = domhelpers.findElementsWithAttributeShallow(macro, "slot") - for slot in slots: - slotName = slot.attributes.get("slot") - fillerlist = domhelpers.locateNodes(node.childNodes, "fill-slot", slotName) - assert len(fillerlist) <= 1, "More than one fill-slot found with name %s" % slotName - if len(fillerlist): - filler = fillerlist[0] - filler.tagName = filler.endTagName = slot.tagName - del filler.attributes['fill-slot'] - del slot.attributes['slot'] - filler.attributes.update(slot.attributes) - slot.parentNode.replaceChild(filler, slot) - - return macro - -class DeferredWidget(Widget): - def setDataCallback(self, result, request, node): - model = result - view = None - if isinstance(model, components.Componentized): - view = model.getAdapter(interfaces.IView) - if not view and hasattr(model, '__class__'): - view = interfaces.IView(model, None) - - if view: - view["id"] = self.attributes.get('id', '') - view.templateNode = node - view.controller = self.controller - return view.setDataCallback(result, request, node) - else: - return Widget.setDataCallback(self, result, request, node) - - -class Break(Widget): - """Break into pdb when this widget is rendered. Mildly - useful for debugging template structure, model stacks, - etc. - """ - def setUp(self, request, node, data): - import pdb; pdb.set_trace() - - -view.registerViewForModel(Text, model.StringModel) -view.registerViewForModel(List, model.ListModel) -view.registerViewForModel(KeyedList, model.DictionaryModel) -view.registerViewForModel(Link, model.Link) -view.registerViewForModel(DeferredWidget, model.DeferredWrapper) diff --git a/tools/buildbot/pylibs/twisted/web/xmlrpc.py b/tools/buildbot/pylibs/twisted/web/xmlrpc.py deleted file mode 100644 index 70be322..0000000 --- a/tools/buildbot/pylibs/twisted/web/xmlrpc.py +++ /dev/null @@ -1,414 +0,0 @@ -# -*- test-case-name: twisted.web.test.test_xmlrpc -*- -# -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -A generic resource for publishing objects via XML-RPC. - -Requires xmlrpclib (comes standard with Python 2.2 and later, otherwise can be -downloaded from http://www.pythonware.com/products/xmlrpc/). - -Maintainer: U{Itamar Shtull-Trauring<mailto:twisted@itamarst.org>} -""" -from __future__ import nested_scopes - -__version__ = "$Revision: 1.32 $"[11:-2] - -# System Imports -import xmlrpclib -import urlparse - -# Sibling Imports -from twisted.web import resource, server, http -from twisted.internet import defer, protocol, reactor -from twisted.python import log, reflect, failure - -# These are deprecated, use the class level definitions -NOT_FOUND = 8001 -FAILURE = 8002 - - -# Useful so people don't need to import xmlrpclib directly -Fault = xmlrpclib.Fault -Binary = xmlrpclib.Binary -Boolean = xmlrpclib.Boolean -DateTime = xmlrpclib.DateTime - -class NoSuchFunction(Fault): - """ - There is no function by the given name. - """ - - -class Handler: - """ - Handle a XML-RPC request and store the state for a request in progress. - - Override the run() method and return result using self.result, - a Deferred. - - We require this class since we're not using threads, so we can't - encapsulate state in a running function if we're going to have - to wait for results. - - For example, lets say we want to authenticate against twisted.cred, - run a LDAP query and then pass its result to a database query, all - as a result of a single XML-RPC command. We'd use a Handler instance - to store the state of the running command. - """ - - def __init__(self, resource, *args): - self.resource = resource # the XML-RPC resource we are connected to - self.result = defer.Deferred() - self.run(*args) - - def run(self, *args): - # event driven equivalent of 'raise UnimplementedError' - self.result.errback( - NotImplementedError("Implement run() in subclasses")) - - -class XMLRPC(resource.Resource): - """ - A resource that implements XML-RPC. - - You probably want to connect this to '/RPC2'. - - Methods published can return XML-RPC serializable results, Faults, - Binary, Boolean, DateTime, Deferreds, or Handler instances. - - By default methods beginning with 'xmlrpc_' are published. - - Sub-handlers for prefixed methods (e.g., system.listMethods) - can be added with putSubHandler. By default, prefixes are - separated with a '.'. Override self.separator to change this. - """ - - # Error codes for Twisted, if they conflict with yours then - # modify them at runtime. - NOT_FOUND = 8001 - FAILURE = 8002 - - isLeaf = 1 - separator = '.' - allowedMethods = ('POST',) - - def __init__(self, allowNone=False): - resource.Resource.__init__(self) - self.subHandlers = {} - self.allowNone = allowNone - - def putSubHandler(self, prefix, handler): - self.subHandlers[prefix] = handler - - def getSubHandler(self, prefix): - return self.subHandlers.get(prefix, None) - - def getSubHandlerPrefixes(self): - return self.subHandlers.keys() - - def render_POST(self, request): - request.content.seek(0, 0) - request.setHeader("content-type", "text/xml") - try: - args, functionPath = xmlrpclib.loads(request.content.read()) - except Exception, e: - f = Fault(self.FAILURE, "Can't deserialize input: %s" % (e,)) - self._cbRender(f, request) - else: - try: - function = self._getFunction(functionPath) - except Fault, f: - self._cbRender(f, request) - else: - defer.maybeDeferred(function, *args).addErrback( - self._ebRender - ).addCallback( - self._cbRender, request - ) - return server.NOT_DONE_YET - - def _cbRender(self, result, request): - if isinstance(result, Handler): - result = result.result - if not isinstance(result, Fault): - result = (result,) - try: - s = xmlrpclib.dumps(result, methodresponse=True, - allow_none=self.allowNone) - except Exception, e: - f = Fault(self.FAILURE, "Can't serialize output: %s" % (e,)) - s = xmlrpclib.dumps(f, methodresponse=True, - allow_none=self.allowNone) - request.setHeader("content-length", str(len(s))) - request.write(s) - request.finish() - - def _ebRender(self, failure): - if isinstance(failure.value, Fault): - return failure.value - log.err(failure) - return Fault(self.FAILURE, "error") - - def _getFunction(self, functionPath): - """ - Given a string, return a function, or raise NoSuchFunction. - - This returned function will be called, and should return the result - of the call, a Deferred, or a Fault instance. - - Override in subclasses if you want your own policy. The default - policy is that given functionPath 'foo', return the method at - self.xmlrpc_foo, i.e. getattr(self, "xmlrpc_" + functionPath). - If functionPath contains self.separator, the sub-handler for - the initial prefix is used to search for the remaining path. - """ - if functionPath.find(self.separator) != -1: - prefix, functionPath = functionPath.split(self.separator, 1) - handler = self.getSubHandler(prefix) - if handler is None: - raise NoSuchFunction(self.NOT_FOUND, - "no such subHandler %s" % prefix) - return handler._getFunction(functionPath) - - f = getattr(self, "xmlrpc_%s" % functionPath, None) - if not f: - raise NoSuchFunction(self.NOT_FOUND, - "function %s not found" % functionPath) - elif not callable(f): - raise NoSuchFunction(self.NOT_FOUND, - "function %s not callable" % functionPath) - else: - return f - - def _listFunctions(self): - """ - Return a list of the names of all xmlrpc methods. - """ - return reflect.prefixedMethodNames(self.__class__, 'xmlrpc_') - - -class XMLRPCIntrospection(XMLRPC): - """ - Implement the XML-RPC Introspection API. - - By default, the methodHelp method returns the 'help' method attribute, - if it exists, otherwise the __doc__ method attribute, if it exists, - otherwise the empty string. - - To enable the methodSignature method, add a 'signature' method attribute - containing a list of lists. See methodSignature's documentation for the - format. Note the type strings should be XML-RPC types, not Python types. - """ - - def __init__(self, parent): - """ - Implement Introspection support for an XMLRPC server. - - @param parent: the XMLRPC server to add Introspection support to. - """ - - XMLRPC.__init__(self) - self._xmlrpc_parent = parent - - def xmlrpc_listMethods(self): - """ - Return a list of the method names implemented by this server. - """ - functions = [] - todo = [(self._xmlrpc_parent, '')] - while todo: - obj, prefix = todo.pop(0) - functions.extend([prefix + name for name in obj._listFunctions()]) - todo.extend([ (obj.getSubHandler(name), - prefix + name + obj.separator) - for name in obj.getSubHandlerPrefixes() ]) - return functions - - xmlrpc_listMethods.signature = [['array']] - - def xmlrpc_methodHelp(self, method): - """ - Return a documentation string describing the use of the given method. - """ - method = self._xmlrpc_parent._getFunction(method) - return (getattr(method, 'help', None) - or getattr(method, '__doc__', None) or '') - - xmlrpc_methodHelp.signature = [['string', 'string']] - - def xmlrpc_methodSignature(self, method): - """ - Return a list of type signatures. - - Each type signature is a list of the form [rtype, type1, type2, ...] - where rtype is the return type and typeN is the type of the Nth - argument. If no signature information is available, the empty - string is returned. - """ - method = self._xmlrpc_parent._getFunction(method) - return getattr(method, 'signature', None) or '' - - xmlrpc_methodSignature.signature = [['array', 'string'], - ['string', 'string']] - - -def addIntrospection(xmlrpc): - """ - Add Introspection support to an XMLRPC server. - - @param xmlrpc: The xmlrpc server to add Introspection support to. - """ - xmlrpc.putSubHandler('system', XMLRPCIntrospection(xmlrpc)) - - -class QueryProtocol(http.HTTPClient): - - def connectionMade(self): - self.sendCommand('POST', self.factory.path) - self.sendHeader('User-Agent', 'Twisted/XMLRPClib') - self.sendHeader('Host', self.factory.host) - self.sendHeader('Content-type', 'text/xml') - self.sendHeader('Content-length', str(len(self.factory.payload))) - if self.factory.user: - auth = '%s:%s' % (self.factory.user, self.factory.password) - auth = auth.encode('base64').strip() - self.sendHeader('Authorization', 'Basic %s' % (auth,)) - self.endHeaders() - self.transport.write(self.factory.payload) - - def handleStatus(self, version, status, message): - if status != '200': - self.factory.badStatus(status, message) - - def handleResponse(self, contents): - self.factory.parseResponse(contents) - - -payloadTemplate = """<?xml version="1.0"?> -<methodCall> -<methodName>%s</methodName> -%s -</methodCall> -""" - - -class _QueryFactory(protocol.ClientFactory): - - deferred = None - protocol = QueryProtocol - - def __init__(self, path, host, method, user=None, password=None, - allowNone=False, args=()): - self.path, self.host = path, host - self.user, self.password = user, password - self.payload = payloadTemplate % (method, - xmlrpclib.dumps(args, allow_none=allowNone)) - self.deferred = defer.Deferred() - - def parseResponse(self, contents): - if not self.deferred: - return - try: - response = xmlrpclib.loads(contents) - except: - deferred, self.deferred = self.deferred, None - deferred.errback(failure.Failure()) - else: - deferred, self.deferred = self.deferred, None - deferred.callback(response[0][0]) - - def clientConnectionLost(self, _, reason): - if self.deferred is not None: - deferred, self.deferred = self.deferred, None - deferred.errback(reason) - - clientConnectionFailed = clientConnectionLost - - def badStatus(self, status, message): - deferred, self.deferred = self.deferred, None - deferred.errback(ValueError(status, message)) - - - -class Proxy: - """ - A Proxy for making remote XML-RPC calls. - - Pass the URL of the remote XML-RPC server to the constructor. - - Use proxy.callRemote('foobar', *args) to call remote method - 'foobar' with *args. - - @ivar queryFactory: object returning a factory for XML-RPC protocol. Mainly - useful for tests. - """ - queryFactory = _QueryFactory - - def __init__(self, url, user=None, password=None, allowNone=False): - """ - @type url: C{str} - @param url: The URL to which to post method calls. Calls will be made - over SSL if the scheme is HTTPS. If netloc contains username or - password information, these will be used to authenticate, as long as - the C{user} and C{password} arguments are not specified. - - @type user: C{str} or None - @param user: The username with which to authenticate with the server - when making calls. If specified, overrides any username information - embedded in C{url}. If not specified, a value may be taken from C{url} - if present. - - @type password: C{str} or None - @param password: The password with which to authenticate with the - server when making calls. If specified, overrides any password - information embedded in C{url}. If not specified, a value may be taken - from C{url} if present. - - @type allowNone: C{bool} or None - @param allowNone: allow the use of None values in parameters. It's - passed to the underlying xmlrpclib implementation. Default to False. - """ - scheme, netloc, path, params, query, fragment = urlparse.urlparse(url) - netlocParts = netloc.split('@') - if len(netlocParts) == 2: - userpass = netlocParts.pop(0).split(':') - self.user = userpass.pop(0) - try: - self.password = userpass.pop(0) - except: - self.password = None - else: - self.user = self.password = None - hostport = netlocParts[0].split(':') - self.host = hostport.pop(0) - try: - self.port = int(hostport.pop(0)) - except: - self.port = None - self.path = path - if self.path in ['', None]: - self.path = '/' - self.secure = (scheme == 'https') - if user is not None: - self.user = user - if password is not None: - self.password = password - self.allowNone = allowNone - - def callRemote(self, method, *args): - factory = self.queryFactory( - self.path, self.host, method, self.user, - self.password, self.allowNone, args) - if self.secure: - from twisted.internet import ssl - reactor.connectSSL(self.host, self.port or 443, - factory, ssl.ClientContextFactory()) - else: - reactor.connectTCP(self.host, self.port or 80, factory) - return factory.deferred - -__all__ = ["XMLRPC", "Handler", "NoSuchFunction", "Fault", "Proxy"] - |