Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

**Features**:

- Add a `transfer_timeout` option for SDK-managed HTTP transports. ([#1741](https://github.com/getsentry/sentry-native/pull/1741))

**Fixes**:

- Native/macOS: fix module `image_size` computation, which could have caused the symbolicator to misattribute every frame to the lowest-addressed image (typically `dyld` or `libsystem`). ([#1740](https://github.com/getsentry/sentry-native/pull/1740))
Expand Down
6 changes: 6 additions & 0 deletions examples/example.c
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,12 @@ main(int argc, char **argv)
sentry_options_set_shutdown_timeout(
options, strtoull(shutdown_timeout, NULL, 10));
}
const char *transfer_timeout
= get_arg_value(argc, argv, "transfer-timeout");
if (transfer_timeout) {
sentry_options_set_transfer_timeout(
options, strtoull(transfer_timeout, NULL, 10));
}

sentry_options_set_environment(options, "development");
// sentry defaults this to the `SENTRY_RELEASE` env variable
Expand Down
20 changes: 20 additions & 0 deletions include/sentry.h
Original file line number Diff line number Diff line change
Expand Up @@ -1921,6 +1921,26 @@ SENTRY_API void sentry_options_set_shutdown_timeout(
*/
SENTRY_API uint64_t sentry_options_get_shutdown_timeout(sentry_options_t *opts);

/**
* Sets the timeout (in milliseconds) for HTTP transfer operations.
*
* On curl, this limits the total time an HTTP request is allowed to take. On
* WinHTTP, this is applied to send and receive operations, which WinHTTP
* applies to individual packets.
*
* This setting applies to the SDK-managed HTTP transports. It is not supported
* by Crashpad's crash report upload.
*
* The default value is 0, which disables the transfer timeout.
*/
SENTRY_API void sentry_options_set_transfer_timeout(
sentry_options_t *opts, uint64_t transfer_timeout);

/**
* Gets the timeout (in milliseconds) for HTTP transfer operations.
*/
SENTRY_API uint64_t sentry_options_get_transfer_timeout(sentry_options_t *opts);

/**
* Sets a user-defined backend.
*
Expand Down
1 change: 1 addition & 0 deletions src/backends/native/sentry_crash_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ typedef struct {
bool enable_large_attachments;
bool http_retry;
uint64_t shutdown_timeout;
uint64_t transfer_timeout;

// Atomic user consent (sentry_user_consent_t), updated whenever user
// consent changes so the daemon can honor it at crash time.
Expand Down
1 change: 1 addition & 0 deletions src/backends/native/sentry_crash_daemon.c
Original file line number Diff line number Diff line change
Expand Up @@ -3361,6 +3361,7 @@ sentry__crash_daemon_main(pid_t app_pid, uint64_t app_tid, HANDLE event_handle,
options->enable_large_attachments = ipc->shmem->enable_large_attachments;
options->http_retry = false;
options->shutdown_timeout = ipc->shmem->shutdown_timeout;
options->transfer_timeout = ipc->shmem->transfer_timeout;

// Set custom logger that writes to file
if (log_file) {
Expand Down
1 change: 1 addition & 0 deletions src/backends/sentry_backend_native.c
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ native_backend_startup(
ctx->enable_large_attachments = options->enable_large_attachments;
ctx->http_retry = options->http_retry;
ctx->shutdown_timeout = options->shutdown_timeout;
ctx->transfer_timeout = options->transfer_timeout;
sentry__atomic_store(
&ctx->user_consent, sentry__atomic_fetch(&options->run->user_consent));

Expand Down
14 changes: 14 additions & 0 deletions src/sentry_options.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ sentry_options_new(void)
opts->transport = sentry__transport_new_default();
opts->refcount = 1;
opts->shutdown_timeout = SENTRY_DEFAULT_SHUTDOWN_TIMEOUT;
opts->transfer_timeout = SENTRY_DEFAULT_TRANSFER_TIMEOUT;
sentry_options_set_sample_rate(
opts, sentry__getenv_double("SENTRY_SAMPLE_RATE", 1.0));
sentry_options_set_traces_sample_rate(
Expand Down Expand Up @@ -642,6 +643,19 @@ sentry_options_get_shutdown_timeout(sentry_options_t *opts)
return opts->shutdown_timeout;
}

void
sentry_options_set_transfer_timeout(
sentry_options_t *opts, uint64_t transfer_timeout)
{
opts->transfer_timeout = transfer_timeout;
}

uint64_t
sentry_options_get_transfer_timeout(sentry_options_t *opts)
{
return opts->transfer_timeout;
}

void
sentry_options_add_attachment(sentry_options_t *opts, const char *path)
{
Expand Down
2 changes: 2 additions & 0 deletions src/sentry_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// Defaults to 2s as per
// https://docs.sentry.io/error-reporting/configuration/?platform=native#shutdown-timeout
#define SENTRY_DEFAULT_SHUTDOWN_TIMEOUT 2000
#define SENTRY_DEFAULT_TRANSFER_TIMEOUT 0

struct sentry_backend_s;

Expand Down Expand Up @@ -95,6 +96,7 @@ struct sentry_options_s {

long refcount;
uint64_t shutdown_timeout;
uint64_t transfer_timeout;
sentry_handler_strategy_t handler_strategy;
int minidump_mode; // 0=stack_only, 1=smart, 2=full (see
// sentry_crash_context.h)
Expand Down
11 changes: 11 additions & 0 deletions src/transports/sentry_http_transport_curl.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <curl/curl.h>
#include <curl/easy.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>

Expand All @@ -23,6 +24,7 @@ typedef struct {
char *proxy;
char *ca_certs;
bool debug;
uint64_t transfer_timeout;
long shutdown;
#ifdef SENTRY_PLATFORM_NX
void *nx_state;
Expand Down Expand Up @@ -108,6 +110,7 @@ curl_client_start(void *_client, const sentry_options_t *options)
client->ca_certs = sentry__string_clone(options->ca_certs);
client->curl_handle = curl_easy_init();
client->debug = options->debug;
client->transfer_timeout = options->transfer_timeout;

if (!client->curl_handle) {
// In this case we don't start the worker at all, which means we can
Expand All @@ -125,6 +128,12 @@ curl_client_start(void *_client, const sentry_options_t *options)
return 0;
}

static long
curl_timeout_ms(uint64_t timeout)
{
return timeout > (uint64_t)LONG_MAX ? LONG_MAX : (long)timeout;
}

static void
curl_client_shutdown(void *_client)
{
Expand Down Expand Up @@ -235,6 +244,8 @@ curl_send_task(void *_client, sentry_prepared_http_request_t *req,
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_USERAGENT, SENTRY_SDK_USER_AGENT);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, 15000L);
curl_easy_setopt(
curl, CURLOPT_TIMEOUT_MS, curl_timeout_ms(client->transfer_timeout));
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback);
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, client);
Expand Down
15 changes: 13 additions & 2 deletions src/transports/sentry_http_transport_winhttp.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# include "sentry_transport_xbox.h"
#endif

#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <winhttp.h>
Expand All @@ -24,6 +25,7 @@ typedef struct {
HINTERNET connect;
HINTERNET request;
bool debug;
uint64_t transfer_timeout;
long shutdown;
} winhttp_client_t;

Expand Down Expand Up @@ -79,13 +81,20 @@ set_proxy_credentials(winhttp_client_t *state, const char *proxy)
sentry__url_cleanup(&url);
}

static int
winhttp_timeout_ms(uint64_t timeout)
{
return timeout > (uint64_t)INT_MAX ? INT_MAX : (int)timeout;
}

static int
winhttp_client_start(void *_client, const sentry_options_t *opts)
{
winhttp_client_t *client = _client;

wchar_t *user_agent = sentry__string_to_wstr(opts->user_agent);
client->debug = opts->debug;
client->transfer_timeout = opts->transfer_timeout;

const char *env_proxy = opts->dsn
? getenv(opts->dsn->is_secure ? "https_proxy" : "http_proxy")
Expand Down Expand Up @@ -135,8 +144,10 @@ winhttp_client_start(void *_client, const sentry_options_t *opts)
return 1;
}

// 15s resolve/connect, 30s send/receive (WinHTTP defaults)
WinHttpSetTimeouts(client->session, 15000, 15000, 30000, 30000);
// 15s for resolve/connect, transfer_timeout for send/receive per packet
int transfer_timeout = winhttp_timeout_ms(client->transfer_timeout);
WinHttpSetTimeouts(
client->session, 15000, 15000, transfer_timeout, transfer_timeout);
Comment thread
cursor[bot] marked this conversation as resolved.

return 0;
}
Expand Down
6 changes: 6 additions & 0 deletions tests/unit/test_native_backend.c
Original file line number Diff line number Diff line change
Expand Up @@ -362,13 +362,16 @@ SENTRY_TEST(crash_context_transport_fields)

ctx->shutdown_timeout = 12345;
TEST_CHECK_UINT64_EQUAL(ctx->shutdown_timeout, 12345);
ctx->transfer_timeout = 45000;
TEST_CHECK_UINT64_EQUAL(ctx->transfer_timeout, 45000);

// Verify fields are zero-initialized when memset to 0
memset(ctx, 0, sizeof(*ctx));
TEST_CHECK(ctx->ca_certs[0] == '\0');
TEST_CHECK(ctx->proxy[0] == '\0');
TEST_CHECK(ctx->user_agent[0] == '\0');
TEST_CHECK_UINT64_EQUAL(ctx->shutdown_timeout, 0);
TEST_CHECK_UINT64_EQUAL(ctx->transfer_timeout, 0);

sentry_free(ctx);
#else
Expand All @@ -390,6 +393,7 @@ SENTRY_TEST(crash_context_options_propagation)
sentry_options_set_ca_certs(options, "/path/to/ca-bundle.crt");
sentry_options_set_proxy(options, "http://myproxy:3128");
sentry_options_set_shutdown_timeout(options, 12345);
sentry_options_set_transfer_timeout(options, 45000);

// Verify options were set correctly
TEST_CHECK_STRING_EQUAL(
Expand Down Expand Up @@ -417,13 +421,15 @@ SENTRY_TEST(crash_context_options_propagation)
ctx->user_agent[sizeof(ctx->user_agent) - 1] = '\0';
}
ctx->shutdown_timeout = options->shutdown_timeout;
ctx->transfer_timeout = options->transfer_timeout;

// Verify crash context received the values
TEST_CHECK_STRING_EQUAL(ctx->ca_certs, "/path/to/ca-bundle.crt");
TEST_CHECK_STRING_EQUAL(ctx->proxy, "http://myproxy:3128");
// user_agent should have the default SDK user agent
TEST_CHECK(ctx->user_agent[0] != '\0');
TEST_CHECK_UINT64_EQUAL(ctx->shutdown_timeout, 12345);
TEST_CHECK_UINT64_EQUAL(ctx->transfer_timeout, 45000);

sentry_free(ctx);
sentry_options_free(options);
Expand Down
Loading