def handlePLAINTEXTServer(self, header): """ Parse a complete HTTP-like Foolscap negotiation request and begin proxying to a destination selected based on the extract TubID. """ # the client sends us a GET message lines = header.split("\r\n") if not lines[0].startswith("GET "): raise BananaError("not right") command, url, version = lines[0].split() if not url.startswith("/id/"): # probably a web browser raise BananaError("not right") targetTubID = url[4:] Message.log(event_type=u"handlePLAINTEXTServer", tub_id=targetTubID) if targetTubID == "": # they're asking for an old UnauthenticatedTub. Refuse. raise NegotiationError("secure Tubs require encryption") if isSubstring("Upgrade: TLS/1.0\r\n", header): wantEncrypted = True else: wantEncrypted = False Message.log(event_type=u"handlePLAINTEXTServer", want_encrypted=wantEncrypted) self._handleTubRequest(header, targetTubID)
def checkToken(self, typebyte, size): if self.classname is None: if typebyte not in (tokens.STRING, tokens.VOCAB): raise BananaError("InstanceUnslicer classname must be string") elif self.attrname is None: if typebyte not in (tokens.STRING, tokens.VOCAB): raise BananaError("InstanceUnslicer keys must be STRINGs")
def checkToken(self, typebyte, size): if self.state == 0: if typebyte not in (tokens.STRING, tokens.VOCAB): raise BananaError("MethodUnslicer methodname must be a string") elif self.state == 1: if typebyte != tokens.OPEN: raise BananaError("MethodUnslicer instance must be OPEN") elif self.state == 2: if typebyte != tokens.OPEN: raise BananaError("MethodUnslicer class must be an OPEN")
def checkToken(self, typebyte, size): if self.maxKeys is not None and len(self.d) >= self.maxKeys: raise Violation("the table is full") if self.key is None: if typebyte != INT: raise BananaError("VocabUnslicer only accepts INT keys") else: if typebyte != STRING: raise BananaError("VocabUnslicer only accepts STRING values") if self.valueConstraint: self.valueConstraint.checkToken(typebyte, size)
def checkToken(self, typebyte, size): if self.index is None: if typebyte != INT: raise BananaError("Vocab key must be an INT") elif self.value is None: if typebyte != STRING: raise BananaError("Vocab value must be a STRING") if self.valueConstraint: self.valueConstraint.checkToken(typebyte, size) else: raise Violation("add-vocab only accepts two values")
def doOpen(self, opentype): # check the opentype if self.state == 1: if opentype[0] not in ("instance", "none"): raise BananaError("MethodUnslicer instance must be " + "instance or None") elif self.state == 2: if opentype[0] != "class": raise BananaError("MethodUnslicer class must be a class") unslicer = self.open(opentype) # TODO: apply constraint return unslicer
def checkToken(self, typebyte, size): if self.maxKeys is not None and len(self.d) >= self.maxKeys: raise Violation('the table is full') if self.key is None: if typebyte != INT: raise BananaError('VocabUnslicer only accepts INT keys') else: if typebyte != BYTES: raise BananaError('VocabUnslicer only accepts BYTES values') if self.valueConstraint: self.valueConstraint.checkToken(typebyte, size)
def receiveKey(self, key): # I don't think it is legal (in python) to use an incomplete object # as a dictionary key, because you must have all the contents to # hash it. Someone could fake up a token stream to hit this case, # however: OPEN(dict), OPEN(tuple), OPEN(reference), 0, CLOSE, CLOSE, # "value", CLOSE if isinstance(key, Deferred): raise BananaError("incomplete object as dictionary key") try: if key in self.d: raise BananaError("duplicate key '%s'" % key) except TypeError: raise BananaError("unhashable key '%s'" % key) self.key = key
def openerCheckToken(self, typebyte, size, opentype): if typebyte == tokens.STRING: if len(opentype) == 0: if size > self.maxIndexLength: why = "first opentype STRING token is too long, %d>%d" % \ (size, self.maxIndexLength) raise Violation(why) if opentype == ("copyable", ): # TODO: this is silly, of course (should pre-compute maxlen) maxlen = reduce(max, [len(cname) \ for cname in copyable.CopyableRegistry.keys()] ) if size > maxlen: why = "copyable-classname token is too long, %d>%d" % \ (size, maxlen) raise Violation(why) elif typebyte == tokens.VOCAB: return else: # TODO: hack for testing raise Violation("index token 0x%02x not STRING or VOCAB" % \ ord(typebyte)) raise BananaError("index token 0x%02x not STRING or VOCAB" % \ ord(typebyte))
def _getReference(self, sturdyOrURL): if isinstance(sturdyOrURL, SturdyRef): sturdy = sturdyOrURL else: sturdy = SturdyRef(sturdyOrURL) # pb->pb: ok, requires crypto # pbu->pb: ok, requires crypto # pbu->pbu: ok # pb->pbu: ok, requires crypto if sturdy.encrypted and not crypto_available: e = BananaError("crypto for PB is not available, " "we cannot handle encrypted PB-URLs like %s" % sturdy.getURL()) return defer.fail(e) if not self.running: # queue their request for service once the Tub actually starts log.msg( "Tub.getReference(%s) queued until Tub.startService called" % sturdy, facility="foolscap.tub") d = defer.Deferred() self._pending_getReferences.append((d, sturdy)) return d name = sturdy.name d = self.getBrokerForTubRef(sturdy.getTubRef()) d.addCallback(lambda b: b.getYourReferenceByName(name)) return d
def brokerAttached(self, tubref, broker, isClient): assert self.running assert tubref if tubref in self.tubConnectors: # we initiated an outbound connection to this tubref if not isClient: # however, the connection we got was from an inbound # connection. The completed (inbound) connection wins, so # abandon the outbound TubConnector self.tubConnectors[tubref].shutdown() # we don't need the TubConnector any more del self.tubConnectors[tubref] if tubref in self.brokers: # this shouldn't happen: acceptDecision is supposed to drop any # existing old connection first. self.log("ERROR: unexpected duplicate connection from %s" % tubref) raise BananaError("unexpected duplicate connection") self.brokers[tubref] = broker # now inform everyone who's been waiting on it if tubref in self.waitingForBrokers: for d in self.waitingForBrokers[tubref]: eventual.eventually(d.callback, broker) del self.waitingForBrokers[tubref]
def receiveChild(self, obj, ready_deferred=None): assert not isinstance(obj, Deferred) assert ready_deferred is None if self.value is not None: raise BananaError('already received a string') self.value = decimal.Decimal(obj)
def receiveChild(self, obj, ready_deferred=None): assert not isinstance(obj, Deferred) assert ready_deferred is None if self.finished: raise BananaError("FunctionUnslicer only accepts one string") self.finished = True # TODO: taste here! self.func = reflect.namedObject(obj)
def receiveChild(self, obj, ready_deferred=None): assert not isinstance(obj, Deferred) assert ready_deferred is None if self.finished: raise BananaError("ModuleUnslicer only accepts one string") self.finished = True # TODO: taste here! mod = __import__(obj, {}, {}, "x") self.mod = mod
def receiveChild(self, obj, ready_deferred=None): assert ready_deferred is None if self.classname is None: self.classname = obj self.attrname = None elif self.attrname is None: self.attrname = obj else: if isinstance(obj, Deferred): # TODO: this is an artificial restriction, and it might # be possible to remove it, but I need to think through # it carefully first raise BananaError("unreferenceable object in attribute") if self.d.has_key(self.attrname): raise BananaError("duplicate attribute name '%s'" % self.attrname) self.setAttribute(self.attrname, obj) self.attrname = None
def receiveChild(self, token, ready_deferred=None): assert not isinstance(token, Deferred) assert ready_deferred is None if self.key is None: if self.d.has_key(token): raise BananaError("duplicate key '%s'" % token) self.key = token else: self.d[self.key] = token self.key = None
def openerCheckToken(self, typebyte, size, opentype): if typebyte == tokens.STRING: if size > self.maxIndexLength: why = "STRING token is too long, %d>%d" % \ (size, self.maxIndexLength) raise Violation(why) elif typebyte == tokens.VOCAB: return else: # TODO: hack for testing raise Violation("index token 0x%02x not STRING or VOCAB" % \ ord(typebyte)) raise BananaError("index token 0x%02x not STRING or VOCAB" % \ ord(typebyte))
def receiveClose(self): if self.state != 3: raise BananaError("MethodUnslicer requires three objects") if self.im_self is None: meth = getattr(self.im_class, self.im_func) # getattr gives us an unbound method return meth, None # TODO: late-available instances #if isinstance(self.im_self, NotKnown): # im = _InstanceMethod(self.im_name, self.im_self, self.im_class) # return im meth = self.im_class.__dict__[self.im_func] # whereas __dict__ gives us a function im = instancemethod(meth, self.im_self, self.im_class) return im, None
def checkToken(self, typebyte, size): """Check the token type. Raise an exception if it is not accepted right now, or if the body-length limit is exceeded.""" limit = self.taster.get(typebyte, "not in list") if limit == "not in list": if self.strictTaster: raise BananaError("invalid token type: %s" % tokenNames[typebyte]) else: raise Violation("%s token rejected by %s" % (tokenNames[typebyte], self.name)) if limit and size > limit: raise Violation("%s token too large: %d>%d" % (tokenNames[typebyte], size, limit))
def receiveChild(self, obj, ready_deferred=None): assert not isinstance(obj, Deferred) assert ready_deferred is None if self.state == 0: self.im_func = obj self.state = 1 elif self.state == 1: assert type(obj) in (types.InstanceType, types.NoneType) self.im_self = obj self.state = 2 elif self.state == 2: assert type(obj) == types.ClassType # TODO: new-style classes? self.im_class = obj self.state = 3 else: raise BananaError("MethodUnslicer only accepts three objects")
def checkToken(self, typebyte, size): raise BananaError("NoneUnslicer does not accept any tokens")
def receiveClose(self): raise BananaError("top-level should never receive CLOSE tokens")
def receiveClose(self): if not self.finished: raise BananaError("FunctionUnslicer requires a string") return self.func, None
def receiveChild(self, obj, ready_deferred=None): assert not isinstance(obj, Deferred) assert ready_deferred is None if self.string != None: raise BananaError("already received a string") self.string = obj.decode("UTF-8")
def checkToken(self, typebyte, size): if typebyte not in (STRING, VOCAB): raise BananaError("UnicodeUnslicer only accepts strings")
def receiveChild(self, obj, ready_deferred=None): assert not isinstance(obj, Deferred) assert ready_deferred is None if self.value != None: raise BananaError("already received a string") self.value = decimal.Decimal(six.ensure_str(obj))
def checkToken(self, typebyte, size): if typebyte not in (tokens.STRING, tokens.VOCAB): raise BananaError("FunctionUnslicer only accepts strings")
def receiveClose(self): if not self.finished: raise BananaError("ClassUnslicer requires a string") return self.klass, None
def checkToken(self, typebyte, size): if typebyte != tokens.OPEN: raise BananaError("top-level must be OPEN")
def checkToken(self, typebyte, size): if typebyte != tokens.INT: raise BananaError("BooleanUnslicer only accepts an INT token") if self.value != None: raise BananaError("BooleanUnslicer only accepts one token")