Skip to content

ext/ftp: throw an Error when ftp_nb_fget()/ftp_nb_fput() hit a busy connection - #23540

Merged
ndossche merged 4 commits into
php:masterfrom
lacatoire:fix/ftp-nb-return-types-upstream
Sep 7, 2026
Merged

ext/ftp: throw an Error when ftp_nb_fget()/ftp_nb_fput() hit a busy connection#23540
ndossche merged 4 commits into
php:masterfrom
lacatoire:fix/ftp-nb-return-types-upstream

Conversation

@lacatoire

@lacatoire lacatoire commented Sep 2, 2026

Copy link
Copy Markdown
Member

Reworked as suggested: all four non-blocking transfer functions now throw the same Error on a busy connection, so the whole class is handled consistently. ftp_nb_get() and ftp_nb_put() keep their int|false declaration — false is still what they return when the local file cannot be opened — so there are no stub changes.

The guards stay ahead of the direction/closestream writes, and ftp_nb_put() closes the local stream before throwing, so a rejected re-entrant call leaves the running transfer untouched. ftp_nb_get_during_transfer.phpt and ftp_nb_get_during_nb_transfer.phpt asserted the old warning; they now record the Error and still assert that the outer transfer completes.

On the UPGRADING note: the phrase about the declared int return type is gone. I kept the entry itself, because the warning-and-false behaviour did ship — the in_use guards are in 8.4.24 and 8.5.9 onwards, not master-only. Happy to drop it if you would still rather not carry the entry.

@ndossche

ndossche commented Sep 2, 2026

Copy link
Copy Markdown
Member

Perhaps the code should be revised to throw an Error rather than returning false. Generally, Error is used to indicate a programming mistake, and this is the case here. I believe that's more appropriate than widening the return type

@ndossche

ndossche commented Sep 2, 2026

Copy link
Copy Markdown
Member

cc @iliaal

@iliaal

iliaal commented Sep 3, 2026

Copy link
Copy Markdown
Member

Agreed, ftp_close() already throws an Error on the same in_use flag. That guard is the only false in ftp_nb_fget() and ftp_nb_fput(), so throwing drops the stub and UPGRADING changes entirely. Keep the check ahead of the direction/closestream writes, and master only.

ftp_nb_fget() and ftp_nb_fput() answered an already busy connection with a
warning and false, against a declared int return type. Reaching that guard
means a transfer was started from inside another transfer, which is a
programming mistake, so throw an Error instead, as ftp_close() already does
on the same in_use flag. The declarations stay int.

The check stays ahead of the direction and closestream writes, so the
running transfer is left untouched. The test reaches the guard through a
stream wrapper that calls back into the extension mid transfer.
@lacatoire
lacatoire force-pushed the fix/ftp-nb-return-types-upstream branch from 6a0827e to fa921f8 Compare September 3, 2026 12:59
@lacatoire lacatoire changed the title ext/ftp: declare the false returned by ftp_nb_fget() and ftp_nb_fput() ext/ftp: throw an Error when ftp_nb_fget()/ftp_nb_fput() hit a busy connection Sep 3, 2026

@ndossche ndossche left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the right direction, but incomplete.
You should consistently do the same for ftp_nb_get & ftp_nb_put, such that this entire error class (which is rlly a programming error), can be handled in a consistent way.

Comment thread UPGRADING
The in_use guard is a programming error in all four non-blocking transfer
functions, so all four now throw the same Error instead of two of them
emitting a warning and returning false. ftp_nb_get() and ftp_nb_put() keep
their int|false declaration, which is still returned when the local file
cannot be opened.

ftp_nb_put() closes the local stream before throwing, and the guards stay
ahead of the direction/closestream writes, so a rejected re-entrant call
leaves the running transfer untouched.

ftp_nb_get_during_transfer.phpt and ftp_nb_get_during_nb_transfer.phpt
asserted the old warning; they now record the Error and still assert that
the outer transfer completes.
The test asserts the class it prints, so it must not presume Error in the
catch: a change of thrown class has to fail the test rather than escape it.

@ndossche ndossche left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you

@ndossche
ndossche merged commit 9e58a1d into php:master Sep 7, 2026
18 checks passed
@lacatoire
lacatoire deleted the fix/ftp-nb-return-types-upstream branch September 7, 2026 13:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants