Index: third_party/twisted_8_1/twisted/web/server.py |
diff --git a/third_party/twisted_8_1/twisted/web/server.py b/third_party/twisted_8_1/twisted/web/server.py |
deleted file mode 100644 |
index 9ee9579b707092122f9d82beeb69765a977ae140..0000000000000000000000000000000000000000 |
--- a/third_party/twisted_8_1/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 |
- |