Rev 2925: (James Henstridge) Update SMTPConnection to better follow the SMTP spec. in file:///home/pqm/archives/thelove/bzr/%2Btrunk/
Canonical.com Patch Queue Manager
pqm at pqm.ubuntu.com
Mon Oct 22 19:35:49 BST 2007
At file:///home/pqm/archives/thelove/bzr/%2Btrunk/
------------------------------------------------------------
revno: 2925
revision-id: pqm at pqm.ubuntu.com-20071022183547-ylcflvri4vahgtmg
parent: pqm at pqm.ubuntu.com-20071022175339-ueibdaois8t36171
parent: james at jamesh.id.au-20071020003544-ol0k71n7vgefhlwd
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Mon 2007-10-22 19:35:47 +0100
message:
(James Henstridge) Update SMTPConnection to better follow the SMTP spec.
modified:
bzrlib/smtp_connection.py smtp_connection.py-20070618204456-nu6wag1ste4biuk2-1
bzrlib/tests/blackbox/test_merge_directive.py test_merge_directive-20070302012039-zh7uhy39biairtn0-1
bzrlib/tests/test_smtp_connection.py test_smtp_connection-20070618204509-wuyxc0r0ztrecv7e-1
------------------------------------------------------------
revno: 2898.2.4
merged: james at jamesh.id.au-20071020003544-ol0k71n7vgefhlwd
parent: james at jamesh.id.au-20071020001437-pbujo03uyui6idz4
parent: pqm at pqm.ubuntu.com-20071019201226-6z006xotgfe7zmu8
committer: James Henstridge <james at jamesh.id.au>
branch nick: bzr.smtp
timestamp: Sat 2007-10-20 08:35:44 +0800
message:
merge from bzr.dev
------------------------------------------------------------
revno: 2898.2.3
merged: james at jamesh.id.au-20071020001437-pbujo03uyui6idz4
parent: james at jamesh.id.au-20071010034304-pnj843bv68xy151f
committer: James Henstridge <james at jamesh.id.au>
branch nick: bzr.smtp
timestamp: Sat 2007-10-20 08:14:37 +0800
message:
* Fix merge-directive blackbox test.
* Fix small typo in comment in smtp_connection.py
------------------------------------------------------------
revno: 2898.2.2
merged: james at jamesh.id.au-20071010034304-pnj843bv68xy151f
parent: james at jamesh.id.au-20071009104548-ygqxbh7322f1jfem
committer: James Henstridge <james at jamesh.id.au>
branch nick: bzr.smtp
timestamp: Wed 2007-10-10 16:43:04 +1300
message:
Fix test helper class naming, per John's review comments.
------------------------------------------------------------
revno: 2898.2.1
merged: james at jamesh.id.au-20071009104548-ygqxbh7322f1jfem
parent: pqm at pqm.ubuntu.com-20071009044446-uliu5z9a52bzmps8
committer: James Henstridge <james at jamesh.id.au>
branch nick: bzr.smtp
timestamp: Tue 2007-10-09 23:45:48 +1300
message:
Update SMTPConnection._create_connection to better follow the SMTP
specification (and hence work with fussy servers):
* Call ehlo/helo ourselves instead of relying on login() or sendmail()
calling them implicitly.
* Only call starttls if the previous ehlo response indicates that the
server supports the extension. If starttls fails, raise SMTPError.
* If we call starttls, follow it with another ehlo to discover any
newly revealed extensions (e.g. auth).
Also add some tests for _create_connection().
=== modified file 'bzrlib/smtp_connection.py'
--- a/bzrlib/smtp_connection.py 2007-08-10 16:17:30 +0000
+++ b/bzrlib/smtp_connection.py 2007-10-20 00:14:37 +0000
@@ -79,10 +79,22 @@
else:
raise
- # If this fails, it just returns an error, but it shouldn't raise an
- # exception unless something goes really wrong (in which case we want
- # to fail anyway).
- self._connection.starttls()
+ # Say EHLO (falling back to HELO) to query the server's features.
+ code, resp = self._connection.ehlo()
+ if not (200 <= code <= 299):
+ code, resp = self._connection.helo()
+ if not (200 <= code <= 299):
+ raise SMTPError("server refused HELO: %d %s" % (code, resp))
+
+ # Use TLS if the server advertised it:
+ if self._connection.has_extn("starttls"):
+ code, resp = self._connection.starttls()
+ if not (200 <= code <= 299):
+ raise SMTPError("server refused STARTTLS: %d %s" % (code, resp))
+ # Say EHLO again, to check for newly revealed features
+ code, resp = self._connection.ehlo()
+ if not (200 <= code <= 299):
+ raise SMTPError("server refused EHLO: %d %s" % (code, resp))
def _authenticate(self):
"""If necessary authenticate yourself to the server."""
=== modified file 'bzrlib/tests/blackbox/test_merge_directive.py'
--- a/bzrlib/tests/blackbox/test_merge_directive.py 2007-08-09 03:39:31 +0000
+++ b/bzrlib/tests/blackbox/test_merge_directive.py 2007-10-20 00:14:37 +0000
@@ -116,20 +116,25 @@
connect_calls = []
def connect(self, host='localhost', port=0):
connect_calls.append((self, host, port))
- def starttls(self):
- pass
+ def has_extn(self, extension):
+ return False
+ def ehlo(self):
+ return (200, 'Ok')
old_sendmail = smtplib.SMTP.sendmail
smtplib.SMTP.sendmail = sendmail
old_connect = smtplib.SMTP.connect
smtplib.SMTP.connect = connect
- old_starttls = smtplib.SMTP.starttls
- smtplib.SMTP.starttls = starttls
+ old_ehlo = smtplib.SMTP.ehlo
+ smtplib.SMTP.ehlo = ehlo
+ old_has_extn = smtplib.SMTP.has_extn
+ smtplib.SMTP.has_extn = has_extn
try:
result = self.run_bzr(*args, **kwargs)
finally:
smtplib.SMTP.sendmail = old_sendmail
smtplib.SMTP.connect = old_connect
- smtplib.SMTP.starttls = old_starttls
+ smtplib.SMTP.ehlo = old_ehlo
+ smtplib.SMTP.has_extn = old_has_extn
return result + (connect_calls, sendmail_calls)
def test_mail_default(self):
=== modified file 'bzrlib/tests/test_smtp_connection.py'
--- a/bzrlib/tests/test_smtp_connection.py 2007-08-10 16:17:30 +0000
+++ b/bzrlib/tests/test_smtp_connection.py 2007-10-10 03:43:04 +0000
@@ -38,6 +38,49 @@
return smtp
+class StubSMTPFactory(object):
+ """A fake SMTP connection to test the connection setup."""
+ def __init__(self, fail_on=None, smtp_features=None):
+ self._fail_on = fail_on or []
+ self._calls = []
+ self._smtp_features = smtp_features or []
+ self._ehlo_called = False
+
+ def __call__(self):
+ # The factory pretends to be a connection
+ return self
+
+ def connect(self, server):
+ self._calls.append(('connect', server))
+
+ def helo(self):
+ self._calls.append(('helo',))
+ if 'helo' in self._fail_on:
+ return 500, 'helo failure'
+ else:
+ return 200, 'helo success'
+
+ def ehlo(self):
+ self._calls.append(('ehlo',))
+ if 'ehlo' in self._fail_on:
+ return 500, 'ehlo failure'
+ else:
+ self._ehlo_called = True
+ return 200, 'ehlo success'
+
+ def has_extn(self, extension):
+ self._calls.append(('has_extn', extension))
+ return self._ehlo_called and extension in self._smtp_features
+
+ def starttls(self):
+ self._calls.append(('starttls',))
+ if 'starttls' in self._fail_on:
+ return 500, 'starttls failure'
+ else:
+ self._ehlo_called = True
+ return 200, 'starttls success'
+
+
class TestSMTPConnection(TestCase):
def get_connection(self, text, smtp_factory=None):
@@ -77,6 +120,57 @@
conn = self.get_connection('[DEFAULT]\nsmtp_password=mypass\n')
self.assertEqual(u'mypass', conn._smtp_password)
+ def test_create_connection(self):
+ factory = StubSMTPFactory()
+ conn = self.get_connection('', smtp_factory=factory)
+ conn._create_connection()
+ self.assertEqual([('connect', 'localhost'),
+ ('ehlo',),
+ ('has_extn', 'starttls')], factory._calls)
+
+ def test_create_connection_ehlo_fails(self):
+ # Check that we call HELO if EHLO failed.
+ factory = StubSMTPFactory(fail_on=['ehlo'])
+ conn = self.get_connection('', smtp_factory=factory)
+ conn._create_connection()
+ self.assertEqual([('connect', 'localhost'),
+ ('ehlo',),
+ ('helo',),
+ ('has_extn', 'starttls')], factory._calls)
+
+ def test_create_connection_ehlo_helo_fails(self):
+ # Check that we raise an exception if both EHLO and HELO fail.
+ factory = StubSMTPFactory(fail_on=['ehlo', 'helo'])
+ conn = self.get_connection('', smtp_factory=factory)
+ self.assertRaises(errors.SMTPError, conn._create_connection)
+ self.assertEqual([('connect', 'localhost'),
+ ('ehlo',),
+ ('helo',)], factory._calls)
+
+ def test_create_connection_starttls(self):
+ # Check that STARTTLS plus a second EHLO are called if the
+ # server says it supports the feature.
+ factory = StubSMTPFactory(smtp_features=['starttls'])
+ conn = self.get_connection('', smtp_factory=factory)
+ conn._create_connection()
+ self.assertEqual([('connect', 'localhost'),
+ ('ehlo',),
+ ('has_extn', 'starttls'),
+ ('starttls',),
+ ('ehlo',)], factory._calls)
+
+ def test_create_connection_starttls_fails(self):
+ # Check that we raise an exception if the server claims to
+ # support STARTTLS, but then fails when we try to activate it.
+ factory = StubSMTPFactory(fail_on=['starttls'],
+ smtp_features=['starttls'])
+ conn = self.get_connection('', smtp_factory=factory)
+ self.assertRaises(errors.SMTPError, conn._create_connection)
+ self.assertEqual([('connect', 'localhost'),
+ ('ehlo',),
+ ('has_extn', 'starttls'),
+ ('starttls',)], factory._calls)
+
def test_get_message_addresses(self):
msg = Message()
More information about the bazaar-commits
mailing list