[Python-checkins] cpython (merge 3.2 -> default): Issue #10287: nntplib now queries the server's CAPABILITIES again after

antoine.pitrou python-checkins at python.org
Sun Feb 12 19:18:13 CET 2012


http://hg.python.org/cpython/rev/98ad67529241
changeset:   74890:98ad67529241
parent:      74887:29dbd42970ff
parent:      74889:d789f453387d
user:        Antoine Pitrou <solipsis at pitrou.net>
date:        Sun Feb 12 19:15:09 2012 +0100
summary:
  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.

files:
  Lib/nntplib.py           |   5 +-
  Lib/test/test_nntplib.py |  62 +++++++++++++++++++++++++--
  Misc/NEWS                |   4 +
  3 files changed, 65 insertions(+), 6 deletions(-)


diff --git a/Lib/nntplib.py b/Lib/nntplib.py
--- a/Lib/nntplib.py
+++ b/Lib/nntplib.py
@@ -378,7 +378,7 @@
             self.nntp_implementation = None
             try:
                 resp, caps = self.capabilities()
-            except NNTPPermanentError:
+            except (NNTPPermanentError, NNTPTemporaryError):
                 # Server doesn't support capabilities
                 self._caps = {}
             else:
@@ -955,6 +955,9 @@
                 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
--- a/Lib/test/test_nntplib.py
+++ b/Lib/test/test_nntplib.py
@@ -395,6 +395,8 @@
         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()
 
@@ -687,27 +689,56 @@
         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):
@@ -716,6 +747,14 @@
     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")
@@ -1094,6 +1133,18 @@
         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):
@@ -1253,7 +1304,8 @@
 
 
 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)
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -466,6 +466,10 @@
 Library
 -------
 
+- 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.
+
 - Issue #13989: Document that GzipFile does not support text mode, and give a
   more helpful error message when opened with an invalid mode string.
 

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list