Repository navigation
fix(ftp): reject a status code that is not three digits (#2416) - #2419
Conversation
FTP.make's code branch ran int(code) with no guard, so 'abc' raised a bare ValueError and [220] a bare TypeError, while True wrote code 001, 3.7 wrote 003, 1000 wrote b'1000' and -5 wrote b'-05' -- the %03d formatting accepted out-of-range values silently. The sibling cmmd (#2290) and args (#2410) parameters on the same method already guard their types. Normalise and validate the code in a new FTP._make_code helper: a bool is refused, an int (a ReturnCode member included) is taken as it is, a numeric str, bytes or bytearray is converted, and anything else -- or a value outside 0-999 -- raises "FTP: invalid status code: must be an int in 0-999 or a numeric str, bytes or bytearray, not ...". The range is the three digits the wire format holds and the [0-9]{3} of FTP_RESPONSE reads back, not the 1xx-5xx of RFC 959 section 4.2 alone, since 6xx is RFC 2228 section 5 and the read path accepts it. Widened the code annotation to bytearray, which int() already converted, and extended the Args:/Raises: docstring entries. Test: tests/protocols/application/test_ftp_unit.py gains test_ftp_make_rejects_a_status_code_that_is_not_three_digits, pinning the exact message for bool, float, list, memoryview, a .value-carrying object, a non-numeric str and bytes, and 1000, -5, '1000' and b'-5', plus the unchanged build for an int, a ReturnCode member and a numeric str, bytes and bytearray, and the leading zeroes at 0 and 999. Confirmed fail-without-fix: with the guard reverted the test fails 12/12 -- four with the bare ValueError/TypeError and eight with "ProtocolError not raised". tests/protocols/ in full: 2035 passed / 51410 subtests / 0 failed, after regenerating examples/captures via examples/generators/make_samples.py. mypy reports nothing on ftp.py and pylint's findings on both touched files are unchanged in kind from main -- the extracted helper keeps make off too-many-branches.
|
Coverage: 91.73% (unit tier, Python 3.15,
Per-file detail: the |
|
Review: GOOD TO GO at |
|
We now accept bool values for integer args? |
|
No — |
make pylint,make mypy,make isort)make testpasses, and a test case covers the changedocs/source/changelog/and regeneratedCHANGELOG.md, if the change is user-visible — N/A, centralised in docs(changelog): shared 1.5.0 changelog — long-lived, merges last (#610, #616, #617, #618, #620) #657What is the purpose of your pull request?
fix— corrects a defectDescription of your pull request and other information
Fixes #2416.
FTP.make'scodebranch ranint(code)with no guard, so'abc'raised a bareValueErrorand[220]a bareTypeError, whileTruewrote code001,3.7wrote003,1000wroteb'1000'and-5wroteb'-05'— the%03dformatting accepted out-of-range values silently. The siblingcmmd(#2290) andargs(#2410) parameters on the same method already guard their types.A new
FTP._make_codehelper normalises and validates it: aboolis refused, anint(aReturnCodemember included) is taken as it is, a numericstr,bytesorbytearrayis converted, and anything else — or a value outside0–999— raisesFTP: invalid status code: must be an int in 0-999 or a numeric str, bytes or bytearray, not ....Range:
0–999, the three digits the wire format holds and the[0-9]{3}ofFTP_RESPONSEreads back — not the 1xx–5xx of RFC 959 §4.2 alone, since 6xx is RFC 2228 §5 and the read path accepts it. Narrowing further would refuse a replyreadparses.Numeric
strandbytesstay valid per the annotation, which is widened tobytearray—int()already converted one.Test:
test_ftp_make_rejects_a_status_code_that_is_not_three_digitspins the exact message forTrue,False,3.7,[220],memoryview(b'230'), a.value-carrying object,'abc',b'abc',1000,-5,'1000'andb'-5', plus the unchanged build for230,ReturnCode.CODE_230,'230',b'230'andbytearray(b'230'), and the leading zeroes at0and999.Fail-without-fix: with the guard reverted the test fails 12/12 — four with the bare
ValueError/TypeError, eight withProtocolError not raised.tests/protocols/in full: 2035 passed / 51410 subtests / 0 failed. mypy reports nothing onftp.py; pylint's findings on both touched files are unchanged in kind frommain(the extracted helper keepsmakeofftoo-many-branches).