From 8cf45b1fb59c05af7807b144185fa908615c2e65 Mon Sep 17 00:00:00 2001 From: Ian Thomas Date: Fri, 27 Mar 2026 11:55:31 +0000 Subject: [PATCH] Add user-configurable timeout to wasm http requests --- CMakeLists.txt | 3 +++ src/wasm/constants.hpp | 11 +++++++++++ src/wasm/stream.cpp | 3 +++ src/wasm/subtransport.cpp | 4 +++- src/wasm/subtransport.hpp | 3 ++- src/wasm/utils.cpp | 38 ++++++++++++++++++++++++++++++++++++++ src/wasm/utils.hpp | 8 ++++++++ 7 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 src/wasm/constants.hpp create mode 100644 src/wasm/utils.cpp create mode 100644 src/wasm/utils.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 940e418..b29128e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,6 +98,7 @@ set(GIT2CPP_SRC ${GIT2CPP_SOURCE_DIR}/utils/progress.hpp ${GIT2CPP_SOURCE_DIR}/utils/terminal_pager.cpp ${GIT2CPP_SOURCE_DIR}/utils/terminal_pager.hpp + ${GIT2CPP_SOURCE_DIR}/wasm/constants.hpp ${GIT2CPP_SOURCE_DIR}/wasm/libgit2_internals.cpp ${GIT2CPP_SOURCE_DIR}/wasm/libgit2_internals.hpp ${GIT2CPP_SOURCE_DIR}/wasm/response.cpp @@ -110,6 +111,8 @@ set(GIT2CPP_SRC ${GIT2CPP_SOURCE_DIR}/wasm/subtransport.hpp ${GIT2CPP_SOURCE_DIR}/wasm/transport.cpp ${GIT2CPP_SOURCE_DIR}/wasm/transport.hpp + ${GIT2CPP_SOURCE_DIR}/wasm/utils.cpp + ${GIT2CPP_SOURCE_DIR}/wasm/utils.hpp ${GIT2CPP_SOURCE_DIR}/wrapper/annotated_commit_wrapper.cpp ${GIT2CPP_SOURCE_DIR}/wrapper/annotated_commit_wrapper.hpp ${GIT2CPP_SOURCE_DIR}/wrapper/branch_wrapper.cpp diff --git a/src/wasm/constants.hpp b/src/wasm/constants.hpp new file mode 100644 index 0000000..2159538 --- /dev/null +++ b/src/wasm/constants.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include + +// Constants used in wasm transport layer. +// Exposed to non-emscripten builds so that they can be used in help. + +// Environment variable for http transport timeout. +// Must be a positive number as a timeout of 0 will block forever. +inline constexpr std::string_view WASM_HTTP_TRANSPORT_TIMEOUT_NAME = "GIT_HTTP_TIMEOUT"; +inline constexpr unsigned int WASM_HTTP_TRANSPORT_TIMEOUT_DEFAULT = 10; diff --git a/src/wasm/stream.cpp b/src/wasm/stream.cpp index db69766..52db4ed 100644 --- a/src/wasm/stream.cpp +++ b/src/wasm/stream.cpp @@ -44,6 +44,7 @@ EM_JS( const char* method, const char* content_type_header, const char* authorization_header, + unsigned long request_timeout_ms, size_t buffer_size), { const url_js = UTF8ToString(url); @@ -65,6 +66,7 @@ EM_JS( // Should this only be set if using https? What about CORS via http? xhr.setRequestHeader("Authorization", authorization_header_js); } + xhr.timeout = request_timeout_ms; // Cache request info on JavaScript side so that it is available in subsequent calls // without having to pass it back and forth to/from C++. @@ -257,6 +259,7 @@ static int create_request(wasm_http_stream* stream, std::string_view content_hea name_for_method(stream->m_service.m_method).c_str(), content_header.data(), stream->m_subtransport->m_authorization_header.c_str(), + stream->m_subtransport->m_request_timeout_ms, EMFORGE_BUFSIZE ); return stream->m_request_index; diff --git a/src/wasm/subtransport.cpp b/src/wasm/subtransport.cpp index bdf0202..609f73c 100644 --- a/src/wasm/subtransport.cpp +++ b/src/wasm/subtransport.cpp @@ -2,15 +2,16 @@ # include "subtransport.hpp" +# include # include # include -# include # include # include # include "libgit2_internals.hpp" # include "stream.hpp" +# include "utils.hpp" // C functions. @@ -93,6 +94,7 @@ int create_wasm_http_subtransport(git_smart_subtransport** out, git_transport* o subtransport->m_owner = owner; subtransport->m_base_url = ""; subtransport->m_credential = nullptr; + subtransport->m_request_timeout_ms = get_request_timeout_ms(); *out = &subtransport->m_parent; return 0; diff --git a/src/wasm/subtransport.hpp b/src/wasm/subtransport.hpp index 1bb3bb6..6dd58df 100644 --- a/src/wasm/subtransport.hpp +++ b/src/wasm/subtransport.hpp @@ -17,7 +17,8 @@ struct wasm_http_subtransport // Data stored for reuse on other streams of this transport: std::string m_base_url; std::string m_authorization_header; - git_credential* m_credential; // libgit2 creates this, we are responsible for deleting it. + git_credential* m_credential; // libgit2 creates this, we are responsible for deleting it. + unsigned long m_request_timeout_ms; // Timeout for http(s) requests in milliseconds. }; // git_smart_subtransport_cb diff --git a/src/wasm/utils.cpp b/src/wasm/utils.cpp new file mode 100644 index 0000000..390b3f2 --- /dev/null +++ b/src/wasm/utils.cpp @@ -0,0 +1,38 @@ +#ifdef EMSCRIPTEN + +# include "utils.hpp" + +# include + +# include "constants.hpp" + +unsigned long get_request_timeout_ms() +{ + double timeout_seconds = WASM_HTTP_TRANSPORT_TIMEOUT_DEFAULT; + auto env_var = std::getenv(WASM_HTTP_TRANSPORT_TIMEOUT_NAME.data()); + if (env_var != nullptr) + { + try + { + auto value = std::stod(env_var); + if (value <= 0) + { + throw std::runtime_error("negative or zero"); + } + timeout_seconds = value; + } + catch (std::exception& e) + { + // Catch failures from (1) stod and (2) timeout <= 0. + // Print warning and use default value. + std::cout << termcolor::yellow << "Warning: environment variable " + << WASM_HTTP_TRANSPORT_TIMEOUT_NAME + << " must be a positive number of seconds, using default value of " + << WASM_HTTP_TRANSPORT_TIMEOUT_DEFAULT << " seconds instead." << termcolor::reset + << std::endl; + } + } + return 1000 * timeout_seconds; +} + +#endif // EMSCRIPTEN diff --git a/src/wasm/utils.hpp b/src/wasm/utils.hpp new file mode 100644 index 0000000..2325479 --- /dev/null +++ b/src/wasm/utils.hpp @@ -0,0 +1,8 @@ +#pragma once + +#ifdef EMSCRIPTEN + +// Get wasm http request timeout in milliseconds from environment variable or default value. +unsigned long get_request_timeout_ms(); + +#endif // EMSCRIPTEN