diff options
| author | Dan Engelbrecht <[email protected]> | 2026-02-06 12:42:58 +0100 |
|---|---|---|
| committer | GitHub Enterprise <[email protected]> | 2026-02-06 12:42:58 +0100 |
| commit | 8976a922705e6623404f8c4a3184624e56884029 (patch) | |
| tree | 677c7d31227e32de81f42d58ae81fc704275935d /src/zenhttp | |
| parent | Merge pull request #723 from ue-foundation/lm/service-interactive-session (diff) | |
| download | zen-8976a922705e6623404f8c4a3184624e56884029.tar.xz zen-8976a922705e6623404f8c4a3184624e56884029.zip | |
only check file size for requested range in asio TransmitFileAsync in debug mode (#745)
* only check file size for requested range in asio TransmitFileAsync in debug mode
* only do Transmit file for whole files
Diffstat (limited to 'src/zenhttp')
| -rw-r--r-- | src/zenhttp/servers/httpasio.cpp | 104 |
1 files changed, 63 insertions, 41 deletions
diff --git a/src/zenhttp/servers/httpasio.cpp b/src/zenhttp/servers/httpasio.cpp index 734c452ae..18a0f6a40 100644 --- a/src/zenhttp/servers/httpasio.cpp +++ b/src/zenhttp/servers/httpasio.cpp @@ -175,12 +175,7 @@ template<typename Handler> void TransmitFileAsync(asio::ip::tcp::socket& Socket, HANDLE FileHandle, uint64_t ByteOffset, uint32_t ByteSize, Handler&& Cb) { - // We need to establish a new handle here to avoid running into random errors - // during TransmitFile. I'm not entirely sure why it's necessary yet. - - HANDLE hReopenedFile = - ReOpenFile(FileHandle, FILE_GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_FLAG_OVERLAPPED); - +# if ZEN_BUILD_DEBUG const uint64_t FileSize = FileSizeFromHandle(FileHandle); const uint64_t SendEndOffset = ByteOffset + ByteSize; @@ -195,25 +190,23 @@ TransmitFileAsync(asio::ip::tcp::socket& Socket, HANDLE FileHandle, uint64_t Byt FileSizeFromHandle(FileHandle), SendEndOffset - FileSize); } +# endif // ZEN_BUILD_DEBUG asio::windows::overlapped_ptr OverlappedPtr( Socket.get_executor(), - [WrappedCb = std::move(Cb), ExpectedBytes = ByteSize, FileHandle, ByteOffset, ByteSize, hReopenedFile]( - const std::error_code& Ec, - std::size_t ActualBytesTransferred) { + [WrappedCb = std::move(Cb), ExpectedBytes = ByteSize, FileHandle, ByteOffset, ByteSize](const std::error_code& Ec, + std::size_t ActualBytesTransferred) { if (Ec) { std::error_code DummyEc; ZEN_WARN("NOTE: TransmitFileAsync (offset {:#x}, size {:#x}) file: '{}' (size {:#x})) error '{}', transmitted {} bytes", ByteOffset, ByteSize, - PathFromHandle(hReopenedFile, DummyEc), - FileSizeFromHandle(hReopenedFile), + PathFromHandle(FileHandle, DummyEc), + FileSizeFromHandle(FileHandle), Ec.message(), ActualBytesTransferred); } - - CloseHandle(hReopenedFile); WrappedCb(Ec, ActualBytesTransferred); }); @@ -224,7 +217,7 @@ TransmitFileAsync(asio::ip::tcp::socket& Socket, HANDLE FileHandle, uint64_t Byt const DWORD NumberOfBytesPerSend = 0; // let TransmitFile decide const BOOL Ok = - ::TransmitFile(Socket.native_handle(), hReopenedFile, ByteSize, NumberOfBytesPerSend, RawOverlapped, nullptr, /* dwReserved */ 0); + ::TransmitFile(Socket.native_handle(), FileHandle, ByteSize, NumberOfBytesPerSend, RawOverlapped, nullptr, /* dwReserved */ 0); const DWORD LastError = ::GetLastError(); // Check if the operation completed immediately. @@ -613,51 +606,80 @@ public: LocalDataSize += BufferDataSize; IoBuffer OwnedBuffer = std::move(Buffer); - OwnedBuffer.MakeOwned(); bool ChunkHandled = false; #if ZEN_USE_TRANSMITFILE || ZEN_USE_ASYNC_SENDFILE - if (IoBufferFileReference FileRef; OwnedBuffer.GetFileReference(/* out */ FileRef)) + if (OwnedBuffer.IsWholeFile()) { - // Since there's a limit to how much data TransmitFile can send in one go, - // we may need to split this into multiple IoVec entries. In this case we'll - // end up reallocating the IoVec array, but this should be rare. - - uint64_t RemainingChunkBytes = FileRef.FileChunkSize; - uint64_t ChunkOffset = FileRef.FileChunkOffset; - - const uint32_t MaxTransmitSize = 1 * 1024 * 1024 * 1024; // 1 GB - - while (RemainingChunkBytes) + if (IoBufferFileReference FileRef; OwnedBuffer.GetFileReference(/* out */ FileRef)) { - IoVec Io{.IsFileRef = true}; +# if ZEN_USE_TRANSMITFILE + // We establish a new handle here to add the FILE_FLAG_OVERLAPPED flag for use during TransmitFile - Io.Ref.FileRef.FileHandle = FileRef.FileHandle; - Io.Ref.FileRef.FileChunkOffset = ChunkOffset; + HANDLE WinFileHandle = ReOpenFile(FileRef.FileHandle, + FILE_GENERIC_READ, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_FLAG_OVERLAPPED); - if (RemainingChunkBytes > MaxTransmitSize) + if (WinFileHandle == INVALID_HANDLE_VALUE) { - Io.Ref.FileRef.FileChunkSize = MaxTransmitSize; - RemainingChunkBytes -= MaxTransmitSize; + HRESULT hRes = HRESULT_FROM_WIN32(GetLastError()); + std::error_code DummyEc; + ThrowSystemException(hRes, + fmt::format("Failed to ReOpenFile file {}", PathFromHandle(FileRef.FileHandle, DummyEc))); } - else + + void* FileHandle = (void*)WinFileHandle; + + OwnedBuffer = IoBufferBuilder::MakeFromFileHandle(FileHandle, FileRef.FileChunkOffset, FileRef.FileChunkSize); +# else // ZEN_USE_TRANSMITFILE + void* FileHandle = FileRef.FileHandle; + + OwnedBuffer.MakeOwned(); +# endif // ZEN_USE_TRANSMITFILE + + // Since there's a limit to how much data TransmitFile can send in one go, + // we may need to split this into multiple IoVec entries. In this case we'll + // end up reallocating the IoVec array, but this should be rare. + + uint64_t RemainingChunkBytes = FileRef.FileChunkSize; + uint64_t ChunkOffset = FileRef.FileChunkOffset; + + const uint32_t MaxTransmitSize = 1 * 1024 * 1024 * 1024; // 1 GB + + while (RemainingChunkBytes) { - Io.Ref.FileRef.FileChunkSize = gsl::narrow<uint32_t>(RemainingChunkBytes); - RemainingChunkBytes = 0; - } + IoVec Io{.IsFileRef = true}; - ChunkOffset += Io.Ref.FileRef.FileChunkSize; + Io.Ref.FileRef.FileHandle = FileHandle; + Io.Ref.FileRef.FileChunkOffset = ChunkOffset; - m_IoVecs.push_back(Io); - } + if (RemainingChunkBytes > MaxTransmitSize) + { + Io.Ref.FileRef.FileChunkSize = MaxTransmitSize; + RemainingChunkBytes -= MaxTransmitSize; + } + else + { + Io.Ref.FileRef.FileChunkSize = gsl::narrow<uint32_t>(RemainingChunkBytes); + RemainingChunkBytes = 0; + } + + ChunkOffset += Io.Ref.FileRef.FileChunkSize; - ChunkHandled = true; + m_IoVecs.push_back(Io); + } + + ChunkHandled = true; + } } -#endif +#endif // ZEN_USE_TRANSMITFILE || ZEN_USE_ASYNC_SENDFILE if (!ChunkHandled) { + OwnedBuffer.MakeOwned(); + IoVec Io{.IsFileRef = false}; Io.Ref.MemoryRef = {.Data = OwnedBuffer.Data(), .Size = OwnedBuffer.Size()}; |