[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[minion-cvs] First cut at implementing headers (server-side)
Update of /home/minion/cvsroot/src/minion/lib/mixminion
In directory moria.mit.edu:/tmp/cvs-serv30719/lib/mixminion
Modified Files:
BuildMessage.py Packet.py test.py
Log Message:
First cut at implementing headers (server-side)
Index: BuildMessage.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/BuildMessage.py,v
retrieving revision 1.47
retrieving revision 1.48
diff -u -d -r1.47 -r1.48
--- BuildMessage.py 11 Jun 2003 19:05:35 -0000 1.47
+++ BuildMessage.py 30 Jun 2003 17:33:33 -0000 1.48
@@ -690,3 +690,4 @@
raise MixError("Routing info won't fit in header")
return routing, sizes, totalSize
+
Index: Packet.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/Packet.py,v
retrieving revision 1.47
retrieving revision 1.48
diff -u -d -r1.47 -r1.48
--- Packet.py 25 Jun 2003 17:03:11 -0000 1.47
+++ Packet.py 30 Jun 2003 17:33:33 -0000 1.48
@@ -11,6 +11,7 @@
__all__ = [ 'compressData', 'CompressedDataTooLong', 'DROP_TYPE',
'ENC_FWD_OVERHEAD', 'ENC_SUBHEADER_LEN',
+ 'encodeMailHeaders', 'encodeMessageHeaders',
'FRAGMENT_PAYLOAD_OVERHEAD', 'FWD_TYPE', 'FragmentPayload',
'HEADER_LEN', 'IPV4Info', 'MAJOR_NO', 'MBOXInfo',
'MBOX_TYPE', 'MINOR_NO', 'MIN_EXIT_TYPE',
@@ -20,7 +21,8 @@
'SMTPInfo', 'SMTP_TYPE', 'SWAP_FWD_TYPE', 'SingletonPayload',
'Subheader', 'TAG_LEN', 'TextEncodedMessage',
'parseHeader', 'parseIPV4Info',
- 'parseMBOXInfo', 'parseMessage', 'parsePayload', 'parseReplyBlock',
+ 'parseMBOXInfo', 'parseMessage', 'parseMessageAndHeaders',
+ 'parsePayload', 'parseReplyBlock',
'parseReplyBlocks', 'parseSMTPInfo', 'parseSubheader',
'parseTextEncodedMessages', 'parseTextReplyBlocks', 'uncompressData' ]
@@ -665,6 +667,58 @@
return armorText(c, MESSAGE_ARMOR_NAME, headers=fields,
base64=(self.messageType!='TXT'))
+
+#----------------------------------------------------------------------
+# Header encoding
+
+def encodeMailHeaders(subject=None, fromAddr=None, inReplyTo=None,
+ references=None):
+ """DOCDOC"""
+ #XXXX005 check values
+ headers = {}
+ if subject:
+ headers['SUBJECT'] = subject
+ if fromAddr:
+ headers['FROM'] = fromAddr
+ if inReplyTo:
+ headers['IN-REPLY-TO'] = inReplyTo
+ if references:
+ headers['REFERENCES'] = references
+ return encodeMessageHeaders(message, headers)
+
+def encodeMessageHeaders(headers):
+ """DOCDOC msg, dict
+
+ Requires that headers are in acceptable format.
+ """
+ items = []
+ hitems = headers.items()
+ hitems.sort()
+ for k,v in hitems:
+ items.append("%s:%s\n"%(k,v))
+ items.append("\n")
+ return "".join(items)
+
+HEADER_RE = re.compile(r'^([!-9;-~]+):([ -~]*)\n')
+
+def parseMessageAndHeaders(message):
+ """DOCDOC -> message, {header : value}"""
+ headers = {}
+ msg = message
+ while 1:
+ if msg[0] == '\n':
+ return msg[1:], headers
+ m = HEADER_RE.match(msg)
+ if m:
+ k,v = m.groups()
+ if len(v) > 900:
+ LOG.warn("Rejecting overlong exit header %r:%r...",k,v[:30])
+ else:
+ headers[k] = v
+ msg = msg[m.end():]
+ else:
+ LOG.warn("Could not parse headers on message; not using them.")
+ return message, headers
#----------------------------------------------------------------------
# COMPRESSION FOR PAYLOADS
Index: test.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/test.py,v
retrieving revision 1.126
retrieving revision 1.127
diff -u -d -r1.126 -r1.127
--- test.py 28 Jun 2003 03:34:00 -0000 1.126
+++ test.py 30 Jun 2003 17:33:33 -0000 1.127
@@ -1331,6 +1331,34 @@
self.assert_(p.isEncrypted())
eq(p.getTag(), "9"*20)
+ def testHeaders(self):
+ emh = encodeMessageHeaders
+ pmh = parseMessageAndHeaders
+ eq = self.assertEquals
+
+ encoded = emh({"ABC": "x y zzy", "X": "<42>"}) + "Hello whirled"
+ eq(encoded, "ABC:x y zzy\nX:<42>\n\nHello whirled")
+ m,h = pmh(encoded)
+ eq(m, "Hello whirled")
+ eq(h, {"ABC": "x y zzy", "X": "<42>"})
+
+ encoded = emh({}) + "A short message"
+ eq(encoded, "\nA short message")
+ eq(("A short message", {}), pmh(encoded))
+ eq(("\nA short message", {}), pmh("\n"+encoded))
+
+ try:
+ suspendLog()
+ m,h = pmh("A message that doesn't start with a header")
+ eq(m, "A message that doesn't start with a header")
+ eq(h, {})
+ encoded = "X:"+("Y"*1000)+"\nY:X\n\nZ"
+ m,h = pmh(encoded)
+ eq(h, {"Y": "X"})
+ eq(m, "Z")
+ finally:
+ resumeLog()
+
#----------------------------------------------------------------------
class HashLogTests(unittest.TestCase):
def test_hashlog(self):
@@ -2218,7 +2246,7 @@
bfm = BuildMessage.buildForwardMessage
# A two-hop/one-hop message.
p = "Now is the time for all good men to come to the aid"
- m = bfm(p, SMTP_TYPE, "nobody@invalid",
+ m = bfm("\n"+p, SMTP_TYPE, "nobody@invalid",
[self.server1, self.server2], [self.server3])
self.do_test_chain(m,
@@ -2230,7 +2258,8 @@
p)
# A one-hop/one-hop message.
- m = bfm(p, SMTP_TYPE, "nobody@invalid", [self.server1], [self.server3])
+ m = bfm("\n"+p,
+ SMTP_TYPE, "nobody@invalid", [self.server1], [self.server3])
self.do_test_chain(m,
[self.sp1,self.sp3],
@@ -2240,7 +2269,8 @@
p)
# Try servers with multiple keys
- m = bfm(p, SMTP_TYPE, "nobody@invalid", [self.server2], [self.server3])
+ m = bfm("\n"+p,
+ SMTP_TYPE, "nobody@invalid", [self.server2], [self.server3])
self.do_test_chain(m, [self.sp2_3, self.sp2_3], [FWD_TYPE, SMTP_TYPE],
[self.server3.getRoutingInfo().pack(),
"nobody@invalid"], p)
@@ -2248,7 +2278,7 @@
# A 3/3 message with a long exit header.
for i in (100,300):
longemail = "f"*i+"@invalid"
- m = bfm(p, SMTP_TYPE, longemail,
+ m = bfm("\n"+p, SMTP_TYPE, longemail,
[self.server1, self.server2, self.server1],
[self.server3, self.server1, self.server2])
@@ -2270,8 +2300,10 @@
bfm = BuildMessage.buildForwardMessage
befm = BuildMessage.buildEncryptedForwardMessage
+ h = "SUBJECT:cooper\n\n"
p = "That gum you like, it's coming back in style."
- m = bfm(p, SMTP_TYPE, "nobody@invalid", [self.server1], [self.server3])
+ m = bfm(h+p, SMTP_TYPE, "nobody@invalid", [self.server1],
+ [self.server3])
pkt = self.do_test_chain(m,
[self.sp1,self.sp3],
@@ -2292,9 +2324,10 @@
self.assertEquals(p, pkt.getAsciiContents())
self.assertEquals(base64.encodestring(pkt.getTag()).strip(),
pkt.getAsciiTag())
+ self.assertEquals({"SUBJECT":"cooper"}, pkt.getHeaders())
# with a plaintext, nonascii packet.
pbin = hexread("0123456789ABCDEFFEDCBA9876543210")
- m = bfm(pbin, SMTP_TYPE, "nobody@invalid",
+ m = bfm("\n"+pbin, SMTP_TYPE, "nobody@invalid",
[self.server1], [self.server3])
pkt = self.do_test_chain(m,
[self.sp1,self.sp3],
@@ -4523,12 +4556,14 @@
class FakeDeliveryPacket(mixminion.server.PacketHandler.DeliveryPacket):
"""Stub version of DeliveryPacket used for testing modules"""
- def __init__(self, type, exitType, exitAddress, contents, tag=None):
+ def __init__(self, type, exitType, exitAddress, contents, tag=None,
+ headers = {}):
if tag is None:
tag = "-="*10
mixminion.server.PacketHandler.DeliveryPacket.__init__(self,
exitType, exitAddress, "Z"*16, tag, "Q"*(28*1024))
self.type = type
+ self.headers = headers
self.payload = None
self.contents = contents
@@ -4634,16 +4669,17 @@
mixfn, mixargs = calls[0][1][2], calls[0][1][3:]
self.assertEquals("ls", mixfn)
self.assertEquals(mixargs[:-1],
- ('-z', '-l', 'nonesuch', '-s', 'foobar',
- '-t', 'foo@bar'))
+ ('-z', '-l', 'nonesuch'))
# ...and, if the temporary file it used hasn't been removed yet,
# that it contains the correct data.
fn = mixargs[-1]
fn = os.path.join(os.path.split(fn)[0],
"rmv_"+os.path.split(fn)[1][4:])
- if os.path.exists(fn):
- self.assert_(stringContains(readFile(fn),
- "This is the message"))
+ m = readFile(fn)
+ self.assert_(m.startswith(
+ "To: foo@bar\nFrom: nobody\n"
+ "Subject: foobar\nX-Anonymous: yes\n\n"))
+ self.assert_(stringContains(m, "This is the message"))
## What about the flush command?
self.assertEquals("spawnl", calls[-1][0])
@@ -5877,7 +5913,7 @@
tc = loader.loadTestsFromTestCase
if 0:
- suite.addTest(tc(ServerKeysTests))
+ suite.addTest(tc(ModuleTests))
return suite
suite.addTest(tc(MiscTests))