changeset: 96152:ea878f847eee branch: 3.4 parent: 96148:fd7ef3972215 user: Serhiy Storchaka date: Tue May 19 10:09:42 2015 +0300 files: Lib/email/utils.py Lib/test/test_email/test_email.py Misc/NEWS description: Issue #6598: Increased time precision and random number range in email.utils.make_msgid() to strengthen the uniqueness of the message ID. diff -r fd7ef3972215 -r ea878f847eee Lib/email/utils.py --- a/Lib/email/utils.py Tue May 19 01:36:55 2015 +0300 +++ b/Lib/email/utils.py Tue May 19 10:09:42 2015 +0300 @@ -202,24 +202,23 @@ def make_msgid(idstring=None, domain=None): """Returns a string suitable for RFC 2822 compliant Message-ID, e.g: - <20020201195627.33539.96671@nightshade.la.mastaler.com> + <142480216486.20800.16526388040877946887@nightshade.la.mastaler.com> Optional idstring if given is a string used to strengthen the uniqueness of the message id. Optional domain if given provides the portion of the message id after the '@'. It defaults to the locally defined hostname. """ - timeval = time.time() - utcdate = time.strftime('%Y%m%d%H%M%S', time.gmtime(timeval)) + timeval = int(time.time()*100) pid = os.getpid() - randint = random.randrange(100000) + randint = random.getrandbits(64) if idstring is None: idstring = '' else: idstring = '.' + idstring if domain is None: domain = socket.getfqdn() - msgid = '<%s.%s.%s%s@%s>' % (utcdate, pid, randint, idstring, domain) + msgid = '<%d.%d.%d%s@%s>' % (timeval, pid, randint, idstring, domain) return msgid diff -r fd7ef3972215 -r ea878f847eee Lib/test/test_email/test_email.py --- a/Lib/test/test_email/test_email.py Tue May 19 01:36:55 2015 +0300 +++ b/Lib/test/test_email/test_email.py Tue May 19 10:09:42 2015 +0300 @@ -11,6 +11,10 @@ from io import StringIO, BytesIO from itertools import chain from random import choice +try: + from threading import Thread +except ImportError: + from dummy_threading import Thread import email import email.policy @@ -34,7 +38,7 @@ from email import base64mime from email import quoprimime -from test.support import unlink +from test.support import unlink, start_threads from test.test_email import openfile, TestEmailBase # These imports are documented to work, but we are testing them using a @@ -3152,6 +3156,25 @@ addrs = utils.getaddresses(['User ((nested comment)) ']) eq(addrs[0][1], 'foo@bar.com') + def test_make_msgid_collisions(self): + # Test make_msgid uniqueness, even with multiple threads + class MsgidsThread(Thread): + def run(self): + # generate msgids for 3 seconds + self.msgids = [] + append = self.msgids.append + make_msgid = utils.make_msgid + clock = time.clock + tfin = clock() + 3.0 + while clock() < tfin: + append(make_msgid(domain='testdomain-string')) + + threads = [MsgidsThread() for i in range(5)] + with start_threads(threads): + pass + all_ids = sum([t.msgids for t in threads], []) + self.assertEqual(len(set(all_ids)), len(all_ids)) + def test_utils_quote_unquote(self): eq = self.assertEqual msg = Message() diff -r fd7ef3972215 -r ea878f847eee Misc/NEWS --- a/Misc/NEWS Tue May 19 01:36:55 2015 +0300 +++ b/Misc/NEWS Tue May 19 10:09:42 2015 +0300 @@ -50,6 +50,9 @@ Library ------- +- Issue #6598: Increased time precision and random number range in + email.utils.make_msgid() to strengthen the uniqueness of the message ID. + - Issue #24091: Fixed various crashes in corner cases in C implementation of ElementTree.