summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2012-02-12 18:14:17 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2012-02-12 18:14:17 (GMT)
commit54411c1784bc404448f496e7a9bf657eaab14daf (patch)
treee7917bd18d0652cbbfe6883d9c8e4a7073583a95 /Lib
parent9ce366a5a691fb929c41d7f2c065bcbbddc81026 (diff)
downloadcpython-54411c1784bc404448f496e7a9bf657eaab14daf.zip
cpython-54411c1784bc404448f496e7a9bf657eaab14daf.tar.gz
cpython-54411c1784bc404448f496e7a9bf657eaab14daf.tar.bz2
Issue #10287: nntplib now queries the server's CAPABILITIES again after authenticating (since the result may change, according to RFC 4643).
Patch by Hynek Schlawack.
Diffstat (limited to 'Lib')
-rw-r--r--Lib/nntplib.py5
-rw-r--r--Lib/test/test_nntplib.py62
2 files changed, 61 insertions, 6 deletions
diff --git a/Lib/nntplib.py b/Lib/nntplib.py
index bf66734..6b0150d 100644
--- a/Lib/nntplib.py
+++ b/Lib/nntplib.py
@@ -364,7 +364,7 @@ class _NNTPBase:
self.nntp_implementation = None
try:
resp, caps = self.capabilities()
- except NNTPPermanentError:
+ except (NNTPPermanentError, NNTPTemporaryError):
# Server doesn't support capabilities
self._caps = {}
else:
@@ -941,6 +941,9 @@ class _NNTPBase:
resp = self._shortcmd('authinfo pass ' + password)
if not resp.startswith('281'):
raise NNTPPermanentError(resp)
+ # Capabilities might have changed after login
+ self._caps = None
+ self.getcapabilities()
# Attempt to send mode reader if it was requested after login.
if self.readermode_afterauth:
self._setreadermode()
diff --git a/Lib/test/test_nntplib.py b/Lib/test/test_nntplib.py
index 786b5f0..23fb647 100644
--- a/Lib/test/test_nntplib.py
+++ b/Lib/test/test_nntplib.py
@@ -374,6 +374,8 @@ class NNTPv1Handler:
self.allow_posting = True
self._readline = readline
self._push_data = push_data
+ self._logged_in = False
+ self._user_sent = False
# Our welcome
self.handle_welcome()
@@ -666,27 +668,56 @@ class NNTPv1Handler:
self.push_lit(self.sample_body)
self.push_lit(".")
+ def handle_AUTHINFO(self, cred_type, data):
+ if self._logged_in:
+ self.push_lit('502 Already Logged In')
+ elif cred_type == 'user':
+ if self._user_sent:
+ self.push_lit('482 User Credential Already Sent')
+ else:
+ self.push_lit('381 Password Required')
+ self._user_sent = True
+ elif cred_type == 'pass':
+ self.push_lit('281 Login Successful')
+ self._logged_in = True
+ else:
+ raise Exception('Unknown cred type {}'.format(cred_type))
+
class NNTPv2Handler(NNTPv1Handler):
"""A handler for RFC 3977 (NNTP "v2")"""
def handle_CAPABILITIES(self):
- self.push_lit("""\
+ fmt = """\
101 Capability list:
VERSION 2 3
- IMPLEMENTATION INN 2.5.1
- AUTHINFO USER
+ IMPLEMENTATION INN 2.5.1{}
HDR
LIST ACTIVE ACTIVE.TIMES DISTRIB.PATS HEADERS NEWSGROUPS OVERVIEW.FMT
OVER
POST
READER
- .""")
+ ."""
+
+ if not self._logged_in:
+ self.push_lit(fmt.format('\n AUTHINFO USER'))
+ else:
+ self.push_lit(fmt.format(''))
def handle_OVER(self, message_spec=None):
return self.handle_XOVER(message_spec)
+class CapsAfterLoginNNTPv2Handler(NNTPv2Handler):
+ """A handler that allows CAPABILITIES only after login"""
+
+ def handle_CAPABILITIES(self):
+ if not self._logged_in:
+ self.push_lit('480 You must log in.')
+ else:
+ super().handle_CAPABILITIES()
+
+
class NNTPv1v2TestsMixin:
def setUp(self):
@@ -695,6 +726,14 @@ class NNTPv1v2TestsMixin:
def test_welcome(self):
self.assertEqual(self.server.welcome, self.handler.welcome)
+ def test_authinfo(self):
+ if self.nntp_version == 2:
+ self.assertIn('AUTHINFO', self.server._caps)
+ self.server.login('testuser', 'testpw')
+ # if AUTHINFO is gone from _caps we also know that getcapabilities()
+ # has been called after login as it should
+ self.assertNotIn('AUTHINFO', self.server._caps)
+
def test_date(self):
resp, date = self.server.date()
self.assertEqual(resp, "111 20100914001155")
@@ -1073,6 +1112,18 @@ class NNTPv2Tests(NNTPv1v2TestsMixin, MockedNNTPTestsMixin, unittest.TestCase):
self.assertEqual(self.server.nntp_implementation, 'INN 2.5.1')
+class CapsAfterLoginNNTPv2Tests(MockedNNTPTestsMixin, unittest.TestCase):
+ """Tests a probably NNTP v2 server with capabilities only after login."""
+
+ nntp_version = 2
+ handler_class = CapsAfterLoginNNTPv2Handler
+
+ def test_caps_only_after_login(self):
+ self.assertEqual(self.server._caps, {})
+ self.server.login('testuser', 'testpw')
+ self.assertIn('VERSION', self.server._caps)
+
+
class MiscTests(unittest.TestCase):
def test_decode_header(self):
@@ -1232,7 +1283,8 @@ class MiscTests(unittest.TestCase):
def test_main():
- tests = [MiscTests, NNTPv1Tests, NNTPv2Tests, NetworkedNNTPTests]
+ tests = [MiscTests, NNTPv1Tests, NNTPv2Tests, CapsAfterLoginNNTPv2Tests,
+ NetworkedNNTPTests]
if _have_ssl:
tests.append(NetworkedNNTP_SSLTests)
support.run_unittest(*tests)