Ticket #5411: 5411-2.diff

File 5411-2.diff, 6.3 KB (added by adiroiban, 3 years ago)
  • twisted/protocols/ftp.py

    diff --git a/twisted/protocols/ftp.py b/twisted/protocols/ftp.py
    index 19504a7..1506826 100644
    a b class DTP(object, protocol.Protocol): 
    417417            self._onConnLost.callback(None)
    418418
    419419    def sendLine(self, line):
     420        """
     421        Send a line to data channel.
     422
     423        @type  line: I{str} or I{unicdoe}
     424        @param line: The line to be sent.
     425
     426        If line is I{unicode}, it will be converted to I{str}.
     427        """
     428        if isinstance(line, unicode):
     429            warnings.warn(
     430                "Unicode date received. Encoded to UTF-8. "
     431                "Please send only alreay encoded data.",
     432                category=UserWarning)
     433            line = line.encode('utf-8')
     434
    420435        self.transport.write(line + '\r\n')
    421436
    422437
    class FTP(object, basic.LineReceiver, policies.TimeoutMixin): 
    951966        def gotListing(results):
    952967            self.reply(DATA_CNX_ALREADY_OPEN_START_XFR)
    953968            for (name, attrs) in results:
    954                 self.dtpInstance.sendListResponse(name, attrs)
     969                # IFTPShell returns Unicode file names.
     970                name_encoded = name.encode('utf-8')
     971                self.dtpInstance.sendListResponse(name_encoded, attrs)
    955972            self.dtpInstance.transport.loseConnection()
    956973            return (TXFR_COMPLETE_OK,)
    957974
    class FTP(object, basic.LineReceiver, policies.TimeoutMixin): 
    10141031            self.reply(DATA_CNX_ALREADY_OPEN_START_XFR)
    10151032            for (name, ignored) in results:
    10161033                if not glob or (glob and fnmatch.fnmatch(name, glob)):
    1017                     self.dtpInstance.sendLine(name)
     1034                    # IFTPShell returns Unicode file names.
     1035                    name_encoded = name.encode('utf-8')
     1036                    self.dtpInstance.sendLine(name_encoded)
    10181037            self.dtpInstance.transport.loseConnection()
    10191038            return (TXFR_COMPLETE_OK,)
    10201039
  • twisted/test/test_ftp.py

    diff --git a/twisted/test/test_ftp.py b/twisted/test/test_ftp.py
    index 7ba434e..da6769a 100644
    a b class FTPServerPasvDataConnectionTestCase(FTPServerTestCase): 
    672672            self.assertEqual('', download)
    673673        return d.addCallback(checkDownload)
    674674
     675
     676    def test_LISTUnicode(self):
     677        """
     678        LIST will receive Unicode filenames for IFTPShell.list, and will
     679        encode them using UTF-8.
     680        """
     681        # Login
     682        d = self._anonymousLogin()
     683
     684        def pachedList(me, segments, attributes):
     685            return defer.succeed([(
     686                u'my resum\xe9', (0, 1, 0777, 0, 0, 'user', 'group'))])
     687        self.patch(ftp.FTPAnonymousShell, 'list', pachedList)
     688
     689        self._download('LIST something', chainDeferred=d)
     690
     691        def checkDownload(download):
     692            self.assertEqual(
     693                'drwxrwxrwx   0 user      group                   '
     694                '0 Jan 01  1970 my resum\xc3\xa9\r\n',
     695                download)
     696        return d.addCallback(checkDownload)
     697
     698
    675699    def testManyLargeDownloads(self):
    676700        # Login
    677701        d = self._anonymousLogin()
    class FTPServerPasvDataConnectionTestCase(FTPServerTestCase): 
    756780        return d.addCallback(checkDownload)
    757781
    758782
     783    def test_NLSTUnicode(self):
     784        """
     785        NLST will receive Unicode filenames for IFTPShell.list, and will
     786        encode them using UTF-8.
     787        """
     788        # Login
     789        d = self._anonymousLogin()
     790
     791        def pachedList(me, segments):
     792            return defer.succeed([(u'my resum\xe9', None)])
     793        self.patch(ftp.FTPAnonymousShell, 'list', pachedList)
     794
     795        self._download('NLST something', chainDeferred=d)
     796
     797        def checkDownload(download):
     798            self.assertEqual('my resum\xc3\xa9\r\n', download)
     799        return d.addCallback(checkDownload)
     800
     801
    759802    def test_NLSTOnPathToFile(self):
    760803        """
    761804        NLST on an existent file returns only the path to that file.
    class FTPServerPasvDataConnectionTestCase(FTPServerTestCase): 
    767810        self.dirPath.child('test.txt').touch()
    768811
    769812        self._download('NLST test.txt', chainDeferred=d)
     813
    770814        def checkDownload(download):
    771815            filenames = download[:-2].split('\r\n')
    772816            self.assertEqual(['test.txt'], filenames)
    class DTPFactoryTests(unittest.TestCase): 
    9821026        return d
    9831027
    9841028
     1029class DTPTests(unittest.TestCase):
     1030    """
     1031    Tests for L{ftp.DTP}.
     1032
     1033    The DTP instances in these tests are generated using
     1034    DTPFactory.buildProtocol()
     1035    """
     1036
     1037    def setUp(self):
     1038        """
     1039        Create a fake protocol interpreter, a L{ftp.DTPFactory} instance,
     1040        and dummy transport to help with tests.
     1041        """
     1042        self.reactor = task.Clock()
     1043
     1044        class ProtocolInterpreter(object):
     1045            dtpInstance = None
     1046
     1047        self.protocolInterpreter = ProtocolInterpreter()
     1048        self.factory = ftp.DTPFactory(
     1049            self.protocolInterpreter, None, self.reactor)
     1050        self.transport = proto_helpers.StringTransportWithDisconnection()
     1051
     1052
     1053    def test_sendLine_newline(self):
     1054        """
     1055        Whend sending a line, the newline delimiter will be autoamtically
     1056        added.
     1057        """
     1058        dtp_instance = self.factory.buildProtocol(None)
     1059        dtp_instance.makeConnection(self.transport)
     1060        line_content = 'line content'
     1061
     1062        dtp_instance.sendLine(line_content)
     1063
     1064        data_sent = self.transport.value()
     1065        self.assertEqual(line_content + '\r\n', data_sent)
     1066
     1067
     1068    def test_sendLine_unicode(self):
     1069        """
     1070        When sending an unicode line, it will be converted to str and
     1071        a warning is raised.
     1072        """
     1073        dtp_instance = self.factory.buildProtocol(None)
     1074        dtp_instance.makeConnection(self.transport)
     1075        line_content = u'my resum\xe9'
     1076
     1077        self.assertWarns(
     1078            UserWarning,
     1079            "Unicode date received. "
     1080                "Encoded to UTF-8. Please send only alreay encoded data.",
     1081            ftp.__file__,
     1082            dtp_instance.sendLine, line_content)
     1083
     1084        data_sent = self.transport.value()
     1085        self.assertTrue(isinstance(data_sent, str))
     1086        self.assertEqual(line_content.encode('utf-8') + '\r\n', data_sent)
     1087
     1088
    9851089
    9861090# -- Client Tests -----------------------------------------------------------
    9871091