sftp: Cap maximum SFTP write

The curl does not do any (or enough) chunking when writing large files using the
sftp_write() function which causes some servers to choke [1]. The simplest
solution is to limit the SFTP packet size according the SFTP specification
recommendation which is 32768 B and not write more.

This means the function will not write the whole amount of data it was asked to
write and the calling applications are required to handle the return values
correctly.

More complicated solution would be to send several SFTP packet from the single
sftp_write() function by iterating over the all data passed.

The next improvement in the long term should be respecting the value reported by
the server in the limits@openssh.com extension, which specifies the maximum
packet size and reads/writes explicitly (if supported).

[1] https://github.com/curl/curl/pull/11804

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
This commit is contained in:
Jakub Jelen
2023-09-09 08:49:43 +02:00
parent 4e56c5c956
commit 6cf5f0e340
2 changed files with 15 additions and 0 deletions

View File

@@ -550,6 +550,10 @@ LIBSSH_API int sftp_async_read(sftp_file file, void *data, uint32_t len, uint32_
/**
* @brief Write to a file using an opened sftp file handle.
*
* The maximum size of the SFTP packet payload is 32768 bytes so the count
* parameter is capped at this value. This is low-level function so it does not
* try to send more than this amount of data.
*
* @param file Open sftp file handle to write to.
*
* @param buf Pointer to buffer to write data.

View File

@@ -2211,6 +2211,17 @@ ssize_t sftp_write(sftp_file file, const void *buf, size_t count) {
id = sftp_get_new_id(file->sftp);
/* limit the writes to the maximum specified in Section 3 of
* https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-02
*
* FIXME: This value should be adjusted to the value from the
* limits@openssh.com extension if supported
* TODO: We should iterate over the blocks rather than writing less than
* requested to provide less surprises to the calling applications.
*/
count = count > 32768 ? 32768 : count;
rc = ssh_buffer_pack(buffer,
"dSqdP",
id,