diff --git a/Build/libHttpClient.GDK/libHttpClient.GDK.def b/Build/libHttpClient.GDK/libHttpClient.GDK.def
index 0d2d7a96..112095fa 100644
--- a/Build/libHttpClient.GDK/libHttpClient.GDK.def
+++ b/Build/libHttpClient.GDK/libHttpClient.GDK.def
@@ -57,6 +57,12 @@ EXPORTS
HCHttpCallResponseSetResponseBodyBytes
HCHttpCallResponseSetResponseBodyWriteFunction
HCHttpCallResponseSetStatusCode
+ HCHttpCallRequestSetDynamicSize
+ HCHttpCallRequestAddDynamicBytesWritten
+ HCHttpCallRequestGetDynamicBytesWritten
+ HCHttpCallResponseSetDynamicSize
+ HCHttpCallResponseAddDynamicBytesWritten
+ HCHttpCallResponseGetDynamicBytesWritten
HCHttpCallSetContext
HCHttpCallSetTracing
HCHttpDisableAssertsForSSLValidationInDevSandboxes
diff --git a/Build/libHttpClient.Win32/libHttpClient.Win32.def b/Build/libHttpClient.Win32/libHttpClient.Win32.def
index cff0099e..a82f615b 100644
--- a/Build/libHttpClient.Win32/libHttpClient.Win32.def
+++ b/Build/libHttpClient.Win32/libHttpClient.Win32.def
@@ -57,6 +57,12 @@ EXPORTS
HCHttpCallResponseSetResponseBodyBytes
HCHttpCallResponseSetResponseBodyWriteFunction
HCHttpCallResponseSetStatusCode
+ HCHttpCallRequestSetDynamicSize
+ HCHttpCallRequestAddDynamicBytesWritten
+ HCHttpCallRequestGetDynamicBytesWritten
+ HCHttpCallResponseSetDynamicSize
+ HCHttpCallResponseAddDynamicBytesWritten
+ HCHttpCallResponseGetDynamicBytesWritten
HCHttpCallSetContext
HCHttpCallSetTracing
HCInitialize
diff --git a/Include/httpClient/httpClient.h b/Include/httpClient/httpClient.h
index 09391b50..62888402 100644
--- a/Include/httpClient/httpClient.h
+++ b/Include/httpClient/httpClient.h
@@ -328,6 +328,29 @@ STDAPI HCHttpCallRequestSetUrl(
_In_z_ const char* url
) noexcept;
+///
+/// Mark the HTTP call as having a dynamic size request body for progress reporting. Report the bytes written in the custom callback using
+/// HCHttpCallRequestAddDynamicBytesWritten.
+///
+/// The handle of the HTTP call.
+/// The length in bytes to use for reporting.
+/// Result code for this API operation. Possible values are S_OK, E_INVALIDARG, E_OUTOFMEMORY, or E_FAIL.
+STDAPI HCHttpCallRequestSetDynamicSize(
+ _In_ HCCallHandle call,
+ _In_ uint64_t dynamicBodySize
+) noexcept;
+
+///
+/// Report a custom amount of bytes written when the body size is dynamic. HCHttpCallRequestSetDynamicSize must be set.
+///
+/// The handle of the HTTP call.
+/// The number of bytes written.
+/// Result code for this API operation. Possible values are S_OK, E_INVALIDARG, E_OUTOFMEMORY, or E_FAIL.
+STDAPI HCHttpCallRequestAddDynamicBytesWritten(
+ _In_ HCCallHandle call,
+ _In_ uint64_t bytesWritten
+) noexcept;
+
///
/// Set the request body bytes of the HTTP call. This API operation is mutually exclusive with
/// HCHttpCallRequestSetRequestBodyReadFunction and will result in any custom read callbacks that were
diff --git a/Include/httpClient/httpProvider.h b/Include/httpClient/httpProvider.h
index a2ba1034..f6ae9924 100644
--- a/Include/httpClient/httpProvider.h
+++ b/Include/httpClient/httpProvider.h
@@ -150,6 +150,19 @@ STDAPI HCHttpCallRequestGetRequestBodyReadFunction(
_Out_ void** context
) noexcept;
+///
+/// Get the custom bytes written and total body size for an HTTP call with a dynamic body size. Use standard request body info if dynamicBodySize is 0.
+///
+/// The handle of the HTTP call.
+/// The custom size to use for reporting
+/// The custom bytes written to use for reporting
+/// Result code for this API operation. Possible values are S_OK, E_INVALIDARG, or E_FAIL.
+STDAPI HCHttpCallRequestGetDynamicBytesWritten(
+ _In_ HCCallHandle call,
+ _Out_ size_t* dynamicBodySize,
+ _Out_ size_t* dynamicBodyBytesWritten
+) noexcept;
+
///
/// Get the function used by the HTTP call to get progress updates
///
@@ -316,10 +329,46 @@ STDAPI HCHttpCallResponseGetResponseBodyWriteFunction(
_Out_ void** context
) noexcept;
+///
+/// Get the custom bytes written and total body size for an HTTP call with a dynamic body size. Use standard response body info if dynamicBodySize is 0.
+///
+/// The handle of the HTTP call.
+/// The custom size to use for reporting
+/// The custom bytes written to use for reporting
+///
+STDAPI HCHttpCallResponseGetDynamicBytesWritten(
+ _In_ HCCallHandle call,
+ _Out_ size_t* dynamicBodySize,
+ _Out_ size_t* dynamicBodyBytesWritten
+) noexcept;
+
/////////////////////////////////////////////////////////////////////////////////////////
// HttpCallResponse Set APIs
//
+///
+/// Mark the HTTP call as having a dynamic size response body for progress reporting. Report the bytes written in the custom callback using
+/// HCHttpCallResponseAddDynamicBytesWritten.
+///
+/// The handle of the HTTP call.
+/// The length in bytes of the body being set.
+/// Result code for this API operation. Possible values are S_OK, E_INVALIDARG, E_OUTOFMEMORY, or E_FAIL.
+STDAPI HCHttpCallResponseSetDynamicSize(
+ _In_ HCCallHandle call,
+ _In_ uint64_t dynamicBodySize
+) noexcept;
+
+///
+/// Report a custom amount of bytes written when the body size is dynamic. HCHttpCallRequestSetDynamicSize must be set.
+///
+/// The handle of the HTTP call.
+/// The number of bytes written.
+/// Result code for this API operation. Possible values are S_OK, E_INVALIDARG, E_OUTOFMEMORY, or E_FAIL.
+STDAPI HCHttpCallResponseAddDynamicBytesWritten(
+ _In_ HCCallHandle call,
+ _In_ uint64_t bytesWritten
+) noexcept;
+
///
/// Set the response body byte buffer of the HTTP call. If a custom write callback was previously set
/// on this call handle using HCHttpCallResponseSetResponseBodyWriteFunction, this operation will fail
diff --git a/Source/HTTP/Curl/CurlEasyRequest.cpp b/Source/HTTP/Curl/CurlEasyRequest.cpp
index c41facc9..ddc75b34 100644
--- a/Source/HTTP/Curl/CurlEasyRequest.cpp
+++ b/Source/HTTP/Curl/CurlEasyRequest.cpp
@@ -267,12 +267,24 @@ size_t CurlEasyRequest::ReadCallback(char* buffer, size_t size, size_t nitems, v
return 1;
}
+ uint64_t dynamicBodySize{};
+ uint64_t dynamicBodyBytesWritten{};
+ HCHttpCallRequestGetDynamicBytesWritten(request->m_hcCallHandle, &dynamicBodySize, &dynamicBodyBytesWritten);
+
+ uint64_t reportBytesWritten = request->m_requestBodyOffset;
+ uint64_t reportTotalBytes = bodySize;
+ if (dynamicBodySize > 0)
+ {
+ reportBytesWritten = dynamicBodyBytesWritten;
+ reportTotalBytes = dynamicBodySize;
+ }
+
ReportProgress(
request->m_hcCallHandle,
uploadProgressReportFunction,
request->m_hcCallHandle->uploadMinimumProgressReportInterval,
- request->m_requestBodyOffset,
- bodySize,
+ reportBytesWritten,
+ reportTotalBytes,
uploadProgressReportCallbackContext,
&request->m_hcCallHandle->uploadLastProgressReport
);
@@ -405,12 +417,24 @@ size_t CurlEasyRequest::WriteDataCallback(char* buffer, size_t size, size_t nmem
return 1;
}
+ uint64_t dynamicBodySize{};
+ uint64_t dynamicBodyBytesWritten{};
+ HCHttpCallResponseGetDynamicBytesWritten(request->m_hcCallHandle, &dynamicBodySize, &dynamicBodyBytesWritten);
+
+ uint64_t reportBytesWritten = request->m_responseBodySize - request->m_responseBodyRemainingToRead;
+ uint64_t reportTotalBytes = request->m_responseBodySize;
+ if (dynamicBodySize > 0)
+ {
+ reportBytesWritten = dynamicBodyBytesWritten;
+ reportTotalBytes = dynamicBodySize;
+ }
+
ReportProgress(
request->m_hcCallHandle,
downloadProgressReportFunction,
request->m_hcCallHandle->downloadMinimumProgressReportInterval,
- request->m_responseBodySize - request->m_responseBodyRemainingToRead,
- request->m_responseBodySize,
+ reportBytesWritten,
+ reportTotalBytes,
downloadProgressReportCallbackContext,
&request->m_hcCallHandle->downloadLastProgressReport
);
@@ -486,12 +510,24 @@ int CurlEasyRequest::ProgressReportCallback(void* context, curl_off_t dltotal, c
return 1;
}
+ uint64_t dynamicBodySize{};
+ uint64_t dynamicBodyBytesWritten{};
+ HCHttpCallRequestGetDynamicBytesWritten(request->m_hcCallHandle, &dynamicBodySize, &dynamicBodyBytesWritten);
+
+ uint64_t reportBytesWritten = ulnow;
+ uint64_t reportTotalBytes = ultotal;
+ if (dynamicBodySize > 0)
+ {
+ reportBytesWritten = dynamicBodyBytesWritten;
+ reportTotalBytes = dynamicBodySize;
+ }
+
ReportProgress(
request->m_hcCallHandle,
uploadProgressReportFunction,
request->m_hcCallHandle->uploadMinimumProgressReportInterval,
- ulnow,
- ultotal,
+ reportBytesWritten,
+ reportTotalBytes,
uploadProgressReportCallbackContext,
&request->m_hcCallHandle->uploadLastProgressReport
);
@@ -509,12 +545,24 @@ int CurlEasyRequest::ProgressReportCallback(void* context, curl_off_t dltotal, c
return 1;
}
+ uint64_t dynamicBodySize{};
+ uint64_t dynamicBodyBytesWritten{};
+ HCHttpCallResponseGetDynamicBytesWritten(request->m_hcCallHandle, &dynamicBodySize, &dynamicBodyBytesWritten);
+
+ uint64_t reportBytesWritten = ulnow;
+ uint64_t reportTotalBytes = ultotal;
+ if (dynamicBodySize > 0)
+ {
+ reportBytesWritten = dynamicBodyBytesWritten;
+ reportTotalBytes = dynamicBodySize;
+ }
+
ReportProgress(
request->m_hcCallHandle,
downloadProgressReportFunction,
request->m_hcCallHandle->downloadMinimumProgressReportInterval,
- dlnow,
- dltotal,
+ reportBytesWritten,
+ reportTotalBytes,
downloadProgressReportCallbackContext,
&request->m_hcCallHandle->downloadLastProgressReport);
}
diff --git a/Source/HTTP/WinHttp/winhttp_connection.cpp b/Source/HTTP/WinHttp/winhttp_connection.cpp
index f8703196..f5e360ab 100644
--- a/Source/HTTP/WinHttp/winhttp_connection.cpp
+++ b/Source/HTTP/WinHttp/winhttp_connection.cpp
@@ -525,13 +525,39 @@ void WinHttpConnection::ReportProgress(_In_ WinHttpConnection* pRequestContext,
if (isUpload)
{
- current = pRequestContext->m_requestBodyOffset;
+ uint64_t dynamicBodySize{};
+ uint64_t dynamicBodyBytesWritten{};
+ HCHttpCallRequestGetDynamicBytesWritten(pRequestContext->m_call, &dynamicBodySize, &dynamicBodyBytesWritten);
+
+ if (dynamicBodySize > 0)
+ {
+ bodySize = dynamicBodySize;
+ current = dynamicBodyBytesWritten;
+ }
+ else
+ {
+ current = bodySize - pRequestContext->m_responseBodyRemainingToRead;
+ }
+
lastProgressReport = pRequestContext->m_call->uploadLastProgressReport;
minimumProgressReportIntervalInMs = static_cast(pRequestContext->m_call->uploadMinimumProgressReportInterval * 1000);
}
else
{
- current = bodySize - pRequestContext->m_responseBodyRemainingToRead;
+ uint64_t dynamicBodySize{};
+ uint64_t dynamicBodyBytesWritten{};
+ HCHttpCallResponseGetDynamicBytesWritten(pRequestContext->m_call, &dynamicBodySize, &dynamicBodyBytesWritten);
+
+ if (dynamicBodySize > 0)
+ {
+ bodySize = dynamicBodySize;
+ current = dynamicBodyBytesWritten;
+ }
+ else
+ {
+ current = bodySize - pRequestContext->m_responseBodyRemainingToRead;
+ }
+
lastProgressReport = pRequestContext->m_call->downloadLastProgressReport;
minimumProgressReportIntervalInMs = static_cast(pRequestContext->m_call->downloadMinimumProgressReportInterval * 1000);
}
diff --git a/Source/HTTP/httpcall.h b/Source/HTTP/httpcall.h
index 7883ab0b..5fdf2a07 100644
--- a/Source/HTTP/httpcall.h
+++ b/Source/HTTP/httpcall.h
@@ -95,6 +95,11 @@ struct HC_CALL
std::chrono::steady_clock::time_point downloadLastProgressReport{};
void* downloadProgressReportFunctionContext{ nullptr };
+ // Dynamic size properties
+ uint64_t dynamicRequestBodySize{ 0 };
+ uint64_t dynamicRequestBodyBytesWritten{ 0 };
+ uint64_t dynamicResponseBodySize{ 0 };
+ uint64_t dynamicResponseBodyBytesWritten{ 0 };
static HRESULT CALLBACK ReadRequestBody(
_In_ HCCallHandle call,
diff --git a/Source/HTTP/httpcall_request.cpp b/Source/HTTP/httpcall_request.cpp
index ed05b7b0..d8a2d5c2 100644
--- a/Source/HTTP/httpcall_request.cpp
+++ b/Source/HTTP/httpcall_request.cpp
@@ -65,6 +65,64 @@ try
}
CATCH_RETURN()
+STDAPI
+HCHttpCallRequestSetDynamicSize(
+ _In_ HCCallHandle call,
+ _In_ uint64_t dynamicBodySize
+) noexcept
+try
+{
+ if (call == nullptr || dynamicBodySize == 0)
+ {
+ return E_INVALIDARG;
+ }
+ RETURN_IF_PERFORM_CALLED(call);
+
+ auto httpSingleton = get_http_singleton();
+ if (nullptr == httpSingleton)
+ {
+ return E_HC_NOT_INITIALISED;
+ }
+
+ call->dynamicRequestBodySize = dynamicBodySize;
+
+ if (call->traceCall) { HC_TRACE_INFORMATION(HTTPCLIENT, "HCHttpCallRequestSetDynamicSize [ID %llu]: dynamicBodySize=%llu", TO_ULL(call->id), TO_ULL(dynamicBodySize)); }
+
+ return S_OK;
+}
+CATCH_RETURN()
+
+STDAPI
+HCHttpCallRequestAddDynamicBytesWritten(
+ _In_ HCCallHandle call,
+ _In_ uint64_t bytesWritten
+) noexcept
+try
+{
+ if (call == nullptr)
+ {
+ return E_INVALIDARG;
+ }
+
+ if (call->dynamicRequestBodySize == 0)
+ {
+ return E_UNEXPECTED;
+ }
+
+ call->dynamicRequestBodyBytesWritten += bytesWritten;
+
+ if (call->dynamicRequestBodyBytesWritten > call->dynamicRequestBodySize)
+ {
+ HC_TRACE_WARNING(HTTPCLIENT, "HCHttpCallRequestAddDynamicBytesWritten [ID %llu]: Reducing excessive bytesWritten=%llu to dynamicBodySize=%llu", TO_ULL(call->id), TO_ULL(call->dynamicRequestBodyBytesWritten), TO_ULL(call->dynamicRequestBodySize));
+ call->dynamicRequestBodyBytesWritten = call->dynamicRequestBodySize;
+ }
+
+ if (call->traceCall) { HC_TRACE_INFORMATION(HTTPCLIENT, "HCHttpCallRequestAddDynamicBytesWritten [ID %llu]: bytesWritten=%llu", TO_ULL(call->id), TO_ULL(bytesWritten)); }
+
+ return S_OK;
+}
+CATCH_RETURN()
+
STDAPI
HCHttpCallRequestSetRequestBodyBytes(
_In_ HCCallHandle call,
@@ -319,6 +377,24 @@ try
}
CATCH_RETURN()
+STDAPI HCHttpCallRequestGetDynamicBytesWritten(
+ _In_ HCCallHandle call,
+ _Out_ size_t* dynamicBodySize,
+ _Out_ size_t* dynamicBodyBytesWritten
+) noexcept
+try
+{
+ if (call == nullptr || dynamicBodySize == nullptr || dynamicBodyBytesWritten == nullptr)
+ {
+ return E_INVALIDARG;
+ }
+
+ *dynamicBodySize = call->dynamicRequestBodySize;
+ *dynamicBodyBytesWritten = call->dynamicRequestBodyBytesWritten;
+
+ return S_OK;
+}
+CATCH_RETURN()
STDAPI
HCHttpCallRequestGetProgressReportFunction(
diff --git a/Source/HTTP/httpcall_response.cpp b/Source/HTTP/httpcall_response.cpp
index 2c69dd6a..6d41661a 100644
--- a/Source/HTTP/httpcall_response.cpp
+++ b/Source/HTTP/httpcall_response.cpp
@@ -27,6 +27,26 @@ try
}
CATCH_RETURN()
+STDAPI HCHttpCallResponseGetDynamicBytesWritten(
+ _In_ HCCallHandle call,
+ _Out_ size_t* dynamicBodySize,
+ _Out_ size_t* dynamicBodyBytesWritten
+) noexcept
+try
+{
+ if (call == nullptr || dynamicBodySize == nullptr || dynamicBodyBytesWritten == nullptr)
+ {
+ return E_INVALIDARG;
+ }
+
+ *dynamicBodySize = call->dynamicResponseBodySize;
+ *dynamicBodyBytesWritten = call->dynamicResponseBodyBytesWritten;
+
+ return S_OK;
+
+}
+CATCH_RETURN()
+
STDAPI
HCHttpCallResponseSetResponseBodyWriteFunction(
_In_ HCCallHandle call,
@@ -141,6 +161,64 @@ try
}
CATCH_RETURN()
+STDAPI
+HCHttpCallResponseSetDynamicSize(
+ _In_ HCCallHandle call,
+ _In_ uint64_t dynamicBodySize
+) noexcept
+try
+{
+ if (call == nullptr || dynamicBodySize == 0)
+ {
+ return E_INVALIDARG;
+ }
+ RETURN_IF_PERFORM_CALLED(call);
+
+ auto httpSingleton = get_http_singleton();
+ if (nullptr == httpSingleton)
+ {
+ return E_HC_NOT_INITIALISED;
+ }
+
+ call->dynamicResponseBodySize = dynamicBodySize;
+
+ if (call->traceCall) { HC_TRACE_INFORMATION(HTTPCLIENT, "HCHttpCallResponseSetDynamicSize [ID %llu]: dynamicBodySize=%llu", TO_ULL(call->id), TO_ULL(dynamicBodySize)); }
+
+ return S_OK;
+}
+CATCH_RETURN()
+
+STDAPI
+HCHttpCallResponseAddDynamicBytesWritten(
+ _In_ HCCallHandle call,
+ _In_ uint64_t bytesWritten
+) noexcept
+try
+{
+ if (call == nullptr)
+ {
+ return E_INVALIDARG;
+ }
+
+ if (call->dynamicResponseBodySize == 0)
+ {
+ return E_UNEXPECTED;
+ }
+
+ call->dynamicResponseBodyBytesWritten += bytesWritten;
+
+ if (call->dynamicResponseBodyBytesWritten > call->dynamicResponseBodySize)
+ {
+ HC_TRACE_WARNING(HTTPCLIENT, "HCHttpCallResponseAddDynamicBytesWritten [ID %llu]: Reducing excessive bytesWritten=%llu to dynamicBodySize=%llu", TO_ULL(call->id), TO_ULL(call->dynamicResponseBodyBytesWritten), TO_ULL(call->dynamicResponseBodySize));
+ call->dynamicResponseBodyBytesWritten = call->dynamicResponseBodySize;
+ }
+
+ if (call->traceCall) { HC_TRACE_INFORMATION(HTTPCLIENT, "HCHttpCallResponseAddDynamicBytesWritten [ID %llu]: bytesWritten=%llu", TO_ULL(call->id), TO_ULL(bytesWritten)); }
+
+ return S_OK;
+}
+CATCH_RETURN()
+
STDAPI
HCHttpCallResponseSetResponseBodyBytes(
_In_ HCCallHandle call,