enh(Net): SocketImpl::sendFile() sends entire contents by repeatedly calling sendfile() if necessary

This commit is contained in:
Günter Obiltschnig 2025-02-09 16:03:51 +01:00 committed by Matej Kenda
parent 356124a3f6
commit b9af97ceb3
4 changed files with 37 additions and 39 deletions

View File

@ -288,23 +288,27 @@ public:
/// is by enabling the SO_OOBINLINE option.
virtual std::streamsize sendFile(Poco::FileInputStream& FileInputStream, std::streamoff offset = 0, std::streamsize count = 0);
/// Sends the contents of a file in an optimized way, if possible.
/// Sends the contents of a file over the socket, using operating
/// system-specific APIs, if available. The socket must not have
/// been set to non-blocking.
///
/// If count is != 0, sends the given number of bytes, otherwise
/// sends all bytes, starting from the given offset.
///
/// On POSIX systems, this means using sendfile() or sendfile64().
/// On Windows, this means using TransmitFile().
/// On Linux, macOS and FreeBSD systems, the implementation
/// uses sendfile() or sendfile64().
/// On Windows, the implementation uses TransmitFile().
///
/// If neither is available, or the socket is a SecureSocketImpl()
/// (secure() returns true), falls back to reading the file
/// block by block and callind sendBytes().
/// If neither sendfile() nor TransmitFile() is available,
/// or the socket is a secure one (secure() returne true),
/// falls back to reading the file block by block and calling sendBytes().
///
/// Returns the number of bytes sent, which may be
/// less than the number of bytes specified.
/// Returns the number of bytes sent, which should be the same
/// as count, unless count is 0.
///
/// Throws NetException (or a subclass) in case of any errors.
/// Also throws if the socket is non-blocking.
/// Also throws a NetException if the socket has been set to
/// non-blocking.
virtual int available();
/// Returns the number of bytes available that can be read

View File

@ -269,23 +269,27 @@ public:
/// is by enabling the SO_OOBINLINE option.
std::streamsize sendFile(Poco::FileInputStream& FileInputStream, std::streamoff offset = 0, std::streamsize count = 0);
/// Sends the contents of a file in an optimized way, if possible.
/// Sends the contents of a file over the socket, using operating
/// system-specific APIs, if available. The socket must not have
/// been set to non-blocking.
///
/// If count is != 0, sends the given number of bytes, otherwise
/// sends all bytes, starting from the given offset.
///
/// On POSIX systems, this means using sendfile() or sendfile64().
/// On Windows, this means using TransmitFile().
/// On Linux, macOS and FreeBSD systems, the implementation
/// uses sendfile() or sendfile64().
/// On Windows, the implementation uses TransmitFile().
///
/// If neither is available, or the socket is a SecureSocketImpl()
/// (secure() returns true), falls back to reading the file
/// block by block and callind sendBytes().
/// If neither sendfile() nor TransmitFile() is available,
/// or the socket is a SecureStreamSocket (secure() returne true),
/// falls back to reading the file block by block and calling sendBytes().
///
/// Returns the number of bytes sent, which may be
/// less than the number of bytes specified.
/// Returns the number of bytes sent, which should be the same
/// as count, unless count is 0.
///
/// Throws NetException (or a subclass) in case of any errors.
/// Also throws if the socket is non-blocking.
/// Also throws a NetException if the socket has been set to
/// non-blocking.
StreamSocket(SocketImpl* pImpl);
/// Creates the Socket and attaches the given SocketImpl.

View File

@ -132,19 +132,8 @@ void HTTPServerResponseImpl::sendFile(const std::string& path, const std::string
write(*_pStream);
if (_pRequest && _pRequest->getMethod() != HTTPRequest::HTTP_HEAD)
{
#ifdef POCO_HAVE_SENDFILE
_pStream->flush(); // flush the HTTP headers to the socket, required by HTTP 1.0 and above
std::streamsize sent = 0;
std::streamoff offset = 0;
while (sent < length)
{
offset = sent;
sent += _session.socket().sendFile(istr, offset);
}
#else
StreamCopier::copyStream(istr, *_pStream);
#endif
_session.socket().sendFile(istr);
}
}
else throw OpenFileException(path);

View File

@ -1521,10 +1521,6 @@ namespace
throw Poco::NotImplementedException("native sendfile not implemented for this platform");
#endif
#endif
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
sent = 0;
}
return sent;
}
}
@ -1534,12 +1530,17 @@ std::streamsize SocketImpl::sendFileNative(FileInputStream& fileInputStream, std
{
FileIOS::NativeHandle fd = fileInputStream.nativeHandle();
if (count == 0) count = fileInputStream.size() - offset;
std::streamoff sent = 0;
while (sent == 0)
std::streamsize sent = 0;
while (count > 0)
{
errno = 0;
sent = sendFileUnix(_sockfd, fd, offset, count);
if (sent < 0)
std::streamoff rc = sendFileUnix(_sockfd, fd, offset, count);
if (rc >= 0)
{
sent += rc;
offset += rc;
count -= rc;
}
else
{
error(errno);
}