diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2012-02-12 18:14:17 (GMT) |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2012-02-12 18:14:17 (GMT) |
commit | 54411c1784bc404448f496e7a9bf657eaab14daf (patch) | |
tree | e7917bd18d0652cbbfe6883d9c8e4a7073583a95 /Lib | |
parent | 9ce366a5a691fb929c41d7f2c065bcbbddc81026 (diff) | |
download | cpython-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.py | 5 | ||||
-rw-r--r-- | Lib/test/test_nntplib.py | 62 |
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) |