1
# -*- test-case-name: twisted.test.test_banana -*-
2
# Copyright (c) 2001-2010 Twisted Matrix Laboratories.
3
# See LICENSE for details.
6
Banana -- s-exp based protocol.
8
Future Plans: This module is almost entirely stable. The same caveat applies
9
to it as applies to L{twisted.spread.jelly}, however. Read its future plans
12
@author: Glyph Lefkowitz
15
import copy, cStringIO, struct
17
from twisted.internet import protocol
18
from twisted.persisted import styles
19
from twisted.python import log
21
class BananaError(Exception):
24
def int2b128(integer, stream):
28
assert integer > 0, "can only encode positive integers"
30
stream(chr(integer & 0x7f))
31
integer = integer >> 7
36
Convert an integer represented as a base 128 string into an C{int} or
39
@param st: The integer encoded in a string.
42
@return: The integer value extracted from the string.
43
@rtype: C{int} or C{long}
54
# delimiter characters.
60
# "optional" -- these might be refused by a low-level implementation.
63
# really optional; this is is part of the 'pb' vocabulary
66
HIGH_BIT_SET = chr(0x80)
68
def setPrefixLimit(limit):
70
Set the limit on the prefix length for all Banana connections
71
established after this call.
73
The prefix length limit determines how many bytes of prefix a banana
74
decoder will allow before rejecting a potential object as too large.
77
@param limit: The number of bytes of prefix for banana to allow when
84
SIZE_LIMIT = 640 * 1024 # 640k is all you'll ever need :-)
86
class Banana(protocol.Protocol, styles.Ephemeral):
87
knownDialects = ["pb", "none"]
90
sizeLimit = SIZE_LIMIT
92
def setPrefixLimit(self, limit):
94
Set the prefix limit for decoding done by this protocol instance.
96
@see: L{setPrefixLimit}
98
self.prefixLimit = limit
99
self._smallestLongInt = -2 ** (limit * 7) + 1
100
self._smallestInt = -2 ** 31
101
self._largestInt = 2 ** 31 - 1
102
self._largestLongInt = 2 ** (limit * 7) - 1
105
def connectionReady(self):
106
"""Surrogate for connectionMade
107
Called after protocol negotiation.
110
def _selectDialect(self, dialect):
111
self.currentDialect = dialect
112
self.connectionReady()
114
def callExpressionReceived(self, obj):
115
if self.currentDialect:
116
self.expressionReceived(obj)
118
# this is the first message we've received
120
# if I'm a client I have to respond
121
for serverVer in obj:
122
if serverVer in self.knownDialects:
123
self.sendEncoded(serverVer)
124
self._selectDialect(serverVer)
127
# I can't speak any of those dialects.
128
log.msg("The client doesn't speak any of the protocols "
129
"offered by the server: disconnecting.")
130
self.transport.loseConnection()
132
if obj in self.knownDialects:
133
self._selectDialect(obj)
135
# the client just selected a protocol that I did not suggest.
136
log.msg("The client selected a protocol the server didn't "
137
"suggest and doesn't know: disconnecting.")
138
self.transport.loseConnection()
141
def connectionMade(self):
142
self.setPrefixLimit(_PREFIX_LIMIT)
143
self.currentDialect = None
144
if not self.isClient:
145
self.sendEncoded(self.knownDialects)
148
def gotItem(self, item):
151
l[-1][1].append(item)
153
self.callExpressionReceived(item)
157
def dataReceived(self, chunk):
158
buffer = self.buffer + chunk
159
listStack = self.listStack
160
gotItem = self.gotItem
162
assert self.buffer != buffer, "This ain't right: %s %s" % (repr(self.buffer), repr(buffer))
166
if ch >= HIGH_BIT_SET:
170
if pos > self.prefixLimit:
171
raise BananaError("Security precaution: more than %d bytes of prefix" % (self.prefixLimit,))
174
typebyte = buffer[pos]
175
rest = buffer[pos+1:]
176
if len(num) > self.prefixLimit:
177
raise BananaError("Security precaution: longer than %d bytes worth of prefix" % (self.prefixLimit,))
181
raise BananaError("Security precaution: List too long.")
182
listStack.append((num, []))
184
elif typebyte == STRING:
187
raise BananaError("Security precaution: String too long.")
193
elif typebyte == INT:
197
elif typebyte == LONGINT:
201
elif typebyte == LONGNEG:
205
elif typebyte == NEG:
209
elif typebyte == VOCAB:
212
gotItem(self.incomingVocabulary[num])
213
elif typebyte == FLOAT:
216
gotItem(struct.unpack("!d", rest[:8])[0])
220
raise NotImplementedError(("Invalid Type Byte %r" % (typebyte,)))
221
while listStack and (len(listStack[-1][1]) == listStack[-1][0]):
222
item = listStack.pop()[1]
227
def expressionReceived(self, lst):
228
"""Called when an expression (list, string, or int) is received.
230
raise NotImplementedError()
233
outgoingVocabulary = {
246
'unpersistable' : 12,
256
# PB Protocol Messages
262
'not_logged_in' : 24,
272
incomingVocabulary = {}
273
for k, v in outgoingVocabulary.items():
274
incomingVocabulary[v] = k
276
def __init__(self, isClient=1):
278
self.outgoingSymbols = copy.copy(self.outgoingVocabulary)
279
self.outgoingSymbolCount = 0
280
self.isClient = isClient
282
def sendEncoded(self, obj):
283
io = cStringIO.StringIO()
284
self._encode(obj, io.write)
285
value = io.getvalue()
286
self.transport.write(value)
288
def _encode(self, obj, write):
289
if isinstance(obj, (list, tuple)):
290
if len(obj) > SIZE_LIMIT:
292
"list/tuple is too long to send (%d)" % (len(obj),))
293
int2b128(len(obj), write)
296
self._encode(elem, write)
297
elif isinstance(obj, (int, long)):
298
if obj < self._smallestLongInt or obj > self._largestLongInt:
300
"int/long is too large to send (%d)" % (obj,))
301
if obj < self._smallestInt:
302
int2b128(-obj, write)
305
int2b128(-obj, write)
307
elif obj <= self._largestInt:
313
elif isinstance(obj, float):
315
write(struct.pack("!d", obj))
316
elif isinstance(obj, str):
317
# TODO: an API for extending banana...
318
if self.currentDialect == "pb" and obj in self.outgoingSymbols:
319
symbolID = self.outgoingSymbols[obj]
320
int2b128(symbolID, write)
323
if len(obj) > SIZE_LIMIT:
325
"string is too long to send (%d)" % (len(obj),))
326
int2b128(len(obj), write)
330
raise BananaError("could not send object: %r" % (obj,))
333
# For use from the interactive interpreter
336
_i._selectDialect("none")
340
"""Encode a list s-expression."""
341
io = cStringIO.StringIO()
349
Decode a banana-encoded string.
352
_i.expressionReceived = l.append
357
del _i.expressionReceived