aboutsummaryrefslogtreecommitdiff
path: root/src/zenhttp
diff options
context:
space:
mode:
authorDan Engelbrecht <[email protected]>2026-02-06 12:42:58 +0100
committerGitHub Enterprise <[email protected]>2026-02-06 12:42:58 +0100
commit8976a922705e6623404f8c4a3184624e56884029 (patch)
tree677c7d31227e32de81f42d58ae81fc704275935d /src/zenhttp
parentMerge pull request #723 from ue-foundation/lm/service-interactive-session (diff)
downloadzen-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.cpp104
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()};