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**:

- Cache consent-revoked envelopes to disk when `cache_keep` or `http_retry` is enabled, instead of discarding them. With `http_retry`, the cached envelopes are sent automatically once consent is given. ([#1542](https://github.com/getsentry/sentry-native/pull/1542))

**Fixes**:

- Linux: handle `ENOSYS` in `read_safely` to fix empty module list in seccomp-restricted environments. ([#1655](https://github.com/getsentry/sentry-native/pull/1655))
Expand Down
13 changes: 12 additions & 1 deletion examples/example.c
Original file line number Diff line number Diff line change
Expand Up @@ -694,9 +694,12 @@ main(int argc, char **argv)
if (has_arg(argc, argv, "log-attributes")) {
sentry_options_set_logs_with_attributes(options, true);
}
if (has_arg(argc, argv, "require-user-consent")) {
sentry_options_set_require_user_consent(options, true);
}
if (has_arg(argc, argv, "cache-keep")) {
sentry_options_set_cache_keep(options, true);
sentry_options_set_cache_max_size(options, 4 * 1024 * 1024); // 4 MB
sentry_options_set_cache_max_size(options, 16 * 1024 * 1024); // 16 MB
sentry_options_set_cache_max_age(options, 5 * 24 * 60 * 60); // 5 days
sentry_options_set_cache_max_items(options, 5);
}
Expand Down Expand Up @@ -758,6 +761,10 @@ main(int argc, char **argv)
return EXIT_FAILURE;
}

if (has_arg(argc, argv, "user-consent-revoke")) {
sentry_user_consent_revoke();
}

if (has_arg(argc, argv, "set-global-attribute")) {
sentry_set_attribute("global.attribute.bool",
sentry_value_new_attribute(sentry_value_new_bool(true), NULL));
Expand Down Expand Up @@ -1049,6 +1056,10 @@ main(int argc, char **argv)
}
sentry_capture_event(event);
}
if (has_arg(argc, argv, "user-consent-give")) {
sentry_user_consent_give();
sentry_flush(10000);
}
if (has_arg(argc, argv, "capture-exception")) {
sentry_value_t exc = sentry_value_new_exception(
"ParseIntError", "invalid digit found in string");
Expand Down
12 changes: 12 additions & 0 deletions include/sentry.h
Original file line number Diff line number Diff line change
Expand Up @@ -1476,6 +1476,11 @@ SENTRY_API int sentry_options_get_auto_session_tracking(
* This disables uploads until the user has given the consent to the SDK.
* Consent itself is given with `sentry_user_consent_give` and
* `sentry_user_consent_revoke`.
*
* When combined with `cache_keep` or `http_retry`, envelopes captured
* while consent is revoked are written to the cache directory instead
* of being discarded. With `http_retry` enabled, cached envelopes are
* sent automatically once consent is given.
*/
SENTRY_API void sentry_options_set_require_user_consent(
sentry_options_t *opts, int val);
Expand Down Expand Up @@ -1511,6 +1516,10 @@ SENTRY_API int sentry_options_get_symbolize_stacktraces(
* subdirectory within the database directory. The cache is cleared on startup
* based on the cache_max_items, cache_max_size, and cache_max_age options.
*
* When combined with `sentry_options_set_require_user_consent`, envelopes
* captured while consent is revoked are also written to the cache. With
* `http_retry` enabled, they are sent once consent is given.
*
* Only applicable for HTTP transports.
*
* Disabled by default.
Expand Down Expand Up @@ -1960,6 +1969,9 @@ SENTRY_EXPERIMENTAL_API int sentry_reinstall_backend(void);

/**
* Gives user consent.
*
* Schedules a retry of any envelopes cached while consent was revoked,
* provided that `http_retry` is enabled.
*/
SENTRY_API void sentry_user_consent_give(void);

Expand Down
5 changes: 5 additions & 0 deletions src/backends/native/sentry_crash_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,11 @@ typedef struct {
bool debug_enabled; // Debug logging enabled in parent process
bool attach_screenshot; // Screenshot attachment enabled in parent process
bool cache_keep;
bool require_user_consent;

// Atomic user consent (sentry_user_consent_t), updated whenever user
// consent changes so the daemon can honor it at crash time.
volatile long user_consent;

// Platform-specific crash context
#if defined(SENTRY_PLATFORM_LINUX) || defined(SENTRY_PLATFORM_ANDROID)
Expand Down
28 changes: 18 additions & 10 deletions src/backends/native/sentry_crash_daemon.c
Original file line number Diff line number Diff line change
Expand Up @@ -2909,6 +2909,11 @@ sentry__process_crash(const sentry_options_t *options, sentry_crash_ipc_t *ipc)
}
#endif

if (options->run) {
sentry__atomic_store(&options->run->user_consent,
sentry__atomic_fetch(&ctx->user_consent));
}

sentry_path_t *env_path = sentry__path_from_str(envelope_path);
if (!env_path) {
SENTRY_WARN("Failed to create envelope path");
Expand All @@ -2923,15 +2928,14 @@ sentry__process_crash(const sentry_options_t *options, sentry_crash_ipc_t *ipc)
goto cleanup;
}

SENTRY_DEBUG("Envelope loaded, sending via transport");
SENTRY_DEBUG("Envelope loaded, capturing");

// Send directly via transport, or to external crash reporter
// Capture directly, or pass to external crash reporter
if (!sentry__launch_external_crash_reporter(options, envelope)) {
// Send directly via transport
if (options && options->transport) {
SENTRY_DEBUG("Calling transport send_envelope");
sentry__transport_send_envelope(options->transport, envelope);
SENTRY_DEBUG("Crash envelope sent to transport (queued)");
if (options && options->transport && options->run) {
SENTRY_DEBUG("Capturing crash envelope");
sentry__capture_envelope(options->transport, envelope, options);
SENTRY_DEBUG("Crash envelope captured (queued)");
} else {
SENTRY_WARN("No transport available for sending envelope");
sentry_envelope_free(envelope);
Expand All @@ -2952,7 +2956,7 @@ sentry__process_crash(const sentry_options_t *options, sentry_crash_ipc_t *ipc)

cleanup:
// Send all other envelopes from run folder (logs, etc.) before cleanup
if (run_folder && options && options->transport) {
if (run_folder && options && options->transport && options->run) {
SENTRY_DEBUG("Checking for additional envelopes in run folder");
sentry_pathiter_t *piter = sentry__path_iter_directory(run_folder);
if (piter) {
Expand All @@ -2969,8 +2973,8 @@ sentry__process_crash(const sentry_options_t *options, sentry_crash_ipc_t *ipc)
sentry_envelope_t *run_envelope
= sentry__envelope_from_path(file_path);
if (run_envelope) {
sentry__transport_send_envelope(
options->transport, run_envelope);
sentry__capture_envelope(
options->transport, run_envelope, options);
envelope_count++;
} else {
SENTRY_WARNF("Failed to load envelope: %s", path_str);
Expand Down Expand Up @@ -3214,6 +3218,10 @@ sentry__crash_daemon_main(pid_t app_pid, uint64_t app_tid, HANDLE event_handle,
sentry_path_t *db_path = sentry__path_from_str(ipc->shmem->database_path);
if (db_path) {
options->run = sentry__run_new(db_path);
if (options->run) {
options->run->require_user_consent
= ipc->shmem->require_user_consent;
}
sentry__path_free(db_path);
}

Expand Down
2 changes: 1 addition & 1 deletion src/backends/sentry_backend_breakpad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ breakpad_backend_callback(const google_breakpad::MinidumpDescriptor &descriptor,
// capture the envelope with the disk transport
sentry_transport_t *disk_transport
= sentry_new_disk_transport(options->run);
sentry__capture_envelope(disk_transport, envelope);
sentry__capture_envelope(disk_transport, envelope, options);
sentry__transport_dump_queue(disk_transport, options->run);
sentry_transport_free(disk_transport);
}
Expand Down
2 changes: 1 addition & 1 deletion src/backends/sentry_backend_crashpad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ crashpad_handler(int signum, siginfo_t *info, ucontext_t *user_context)
// capture the envelope with the disk transport
sentry_transport_t *disk_transport
= sentry_new_disk_transport(options->run);
sentry__capture_envelope(disk_transport, envelope);
sentry__capture_envelope(disk_transport, envelope, options);
sentry__transport_dump_queue(disk_transport, options->run);
sentry_transport_free(disk_transport);
}
Expand Down
2 changes: 1 addition & 1 deletion src/backends/sentry_backend_inproc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1206,7 +1206,7 @@ process_ucontext_deferred(const sentry_ucontext_t *uctx,
// capture the envelope with the disk transport
sentry_transport_t *disk_transport
= sentry_new_disk_transport(options->run);
sentry__capture_envelope(disk_transport, envelope);
sentry__capture_envelope(disk_transport, envelope, options);
sentry__transport_dump_queue(disk_transport, options->run);
sentry_transport_free(disk_transport);
}
Expand Down
22 changes: 21 additions & 1 deletion src/backends/sentry_backend_native.c
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,9 @@ native_backend_startup(
ctx->debug_enabled = options->debug;
ctx->attach_screenshot = options->attach_screenshot;
ctx->cache_keep = options->cache_keep;
ctx->require_user_consent = options->require_user_consent;
sentry__atomic_store(
&ctx->user_consent, sentry__atomic_fetch(&options->run->user_consent));

// Set up event and breadcrumb paths
sentry_path_t *run_path = options->run->run_path;
Expand Down Expand Up @@ -549,6 +552,21 @@ native_backend_shutdown(sentry_backend_t *backend)
SENTRY_DEBUG("native backend shutdown complete");
}

static void
native_backend_user_consent_changed(sentry_backend_t *backend)
{
native_backend_state_t *state = (native_backend_state_t *)backend->data;
if (!state || !state->ipc || !state->ipc->shmem) {
return;
}
SENTRY_WITH_OPTIONS (options) {
if (options->run) {
sentry__atomic_store(&state->ipc->shmem->user_consent,
sentry__atomic_fetch(&options->run->user_consent));
}
}
}

static void
native_backend_free(sentry_backend_t *backend)
{
Expand Down Expand Up @@ -938,7 +956,8 @@ native_backend_except(sentry_backend_t *backend, const sentry_ucontext_t *uctx)
if (disk_transport) {
// sentry__capture_envelope takes ownership of
// envelope
sentry__capture_envelope(disk_transport, envelope);
sentry__capture_envelope(
disk_transport, envelope, options);
sentry__transport_dump_queue(
disk_transport, options->run);
sentry_transport_free(disk_transport);
Expand Down Expand Up @@ -985,6 +1004,7 @@ sentry__backend_new(void)
backend->flush_scope_func = native_backend_flush_scope;
backend->add_breadcrumb_func = native_backend_add_breadcrumb;
backend->add_attachment_func = native_backend_add_attachment;
backend->user_consent_changed_func = native_backend_user_consent_changed;
backend->can_capture_after_shutdown = false;

return backend;
Expand Down
35 changes: 23 additions & 12 deletions src/sentry_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,8 @@ set_user_consent(sentry_user_consent_t new_val)
switch (new_val) {
case SENTRY_USER_CONSENT_GIVEN:
sentry__path_write_buffer(consent_path, "1\n", 2);
// flush any envelopes cached while consent was revoked
sentry_transport_retry(options->transport);
break;
case SENTRY_USER_CONSENT_REVOKED:
sentry__path_write_buffer(consent_path, "0\n", 2);
Expand Down Expand Up @@ -480,16 +482,25 @@ sentry_user_consent_is_required(void)
}

void
sentry__capture_envelope(
sentry_transport_t *transport, sentry_envelope_t *envelope)
sentry__capture_envelope(sentry_transport_t *transport,
sentry_envelope_t *envelope, const sentry_options_t *options)
{
bool has_consent = !sentry__should_skip_upload();
if (!has_consent) {
SENTRY_INFO("discarding envelope due to missing user consent");
sentry_envelope_free(envelope);
if (!sentry__run_should_skip_upload(options->run)) {
sentry__transport_send_envelope(transport, envelope);
return;
}
sentry__transport_send_envelope(transport, envelope);
bool cached = false;
if (options->cache_keep || options->http_retry) {
cached = sentry__run_write_cache(options->run, envelope, 0);
if (cached && !sentry__run_should_skip_upload(options->run)) {
// consent given meanwhile -> trigger retry to avoid waiting
// until the next retry poll
sentry_transport_retry(options->transport);
}
}
SENTRY_INFO(cached ? "caching envelope due to missing user consent"
: "discarding envelope due to missing user consent");
sentry_envelope_free(envelope);
}

void
Expand All @@ -499,7 +510,7 @@ sentry_capture_envelope(sentry_envelope_t *envelope)
return;
}
SENTRY_WITH_OPTIONS (options) {
sentry__capture_envelope(options->transport, envelope);
sentry__capture_envelope(options->transport, envelope, options);
}
}

Expand Down Expand Up @@ -608,7 +619,7 @@ sentry__capture_event(sentry_value_t event, sentry_scope_t *local_scope)
SENTRY_DATA_CATEGORY_ERROR, 1);
sentry_envelope_free(envelope);
} else {
sentry__capture_envelope(options->transport, envelope);
sentry__capture_envelope(options->transport, envelope, options);
was_sent = true;
}
}
Expand Down Expand Up @@ -1617,7 +1628,7 @@ sentry_capture_user_feedback(sentry_value_t user_report)
SENTRY_WITH_OPTIONS (options) {
envelope = prepare_user_report(user_report);
if (envelope) {
sentry__capture_envelope(options->transport, envelope);
sentry__capture_envelope(options->transport, envelope, options);
}
}
sentry_value_decref(user_report);
Expand All @@ -1639,7 +1650,7 @@ sentry_capture_feedback_with_hint(
SENTRY_WITH_OPTIONS (options) {
envelope = prepare_user_feedback(user_feedback, hint);
if (envelope) {
sentry__capture_envelope(options->transport, envelope);
sentry__capture_envelope(options->transport, envelope, options);
}
}

Expand Down Expand Up @@ -1752,7 +1763,7 @@ sentry_capture_minidump_n(const char *path, size_t path_len)
sentry__envelope_item_set_header(item, "filename",
sentry_value_new_string(sentry__path_filename(dump_path)));

sentry__capture_envelope(options->transport, envelope);
sentry__capture_envelope(options->transport, envelope, options);

SENTRY_INFOF(
"Minidump has been captured: \"%s\"", dump_path->path);
Expand Down
4 changes: 2 additions & 2 deletions src/sentry_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ sentry_envelope_t *sentry__prepare_transaction(const sentry_options_t *options,
* This function will submit the `envelope` to the given `transport`, first
* checking for consent.
*/
void sentry__capture_envelope(
sentry_transport_t *transport, sentry_envelope_t *envelope);
void sentry__capture_envelope(sentry_transport_t *transport,
sentry_envelope_t *envelope, const sentry_options_t *options);

/**
* Generates a new random UUID for events.
Expand Down
11 changes: 8 additions & 3 deletions src/sentry_database.c
Original file line number Diff line number Diff line change
Expand Up @@ -451,14 +451,17 @@ sentry__process_old_runs(const sentry_options_t *options, uint64_t last_crash)
sentry__session_free(session);
if ((++session_num) >= SENTRY_MAX_ENVELOPE_SESSIONS) {
sentry__capture_envelope(
options->transport, session_envelope);
options->transport, session_envelope, options);
session_envelope = NULL;
session_num = 0;
}
}
} else if (sentry__path_ends_with(file, ".envelope")) {
sentry_envelope_t *envelope = sentry__envelope_from_path(file);
sentry__capture_envelope(options->transport, envelope);
if (envelope) {
sentry__capture_envelope(
options->transport, envelope, options);
}
}

sentry__path_remove(file);
Expand All @@ -470,7 +473,9 @@ sentry__process_old_runs(const sentry_options_t *options, uint64_t last_crash)
}
sentry__pathiter_free(db_iter);

sentry__capture_envelope(options->transport, session_envelope);
if (session_envelope) {
sentry__capture_envelope(options->transport, session_envelope, options);
}
}

// Cache Pruning below is based on prune_crash_reports.cc from Crashpad
Expand Down
4 changes: 4 additions & 0 deletions src/sentry_retry.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,10 @@ size_t
sentry__retry_send(sentry_retry_t *retry, uint64_t before,
sentry_retry_send_func_t send_cb, void *data)
{
if (sentry__run_should_skip_upload(retry->run)) {
return 1; // keep the poll alive until consent is given
}

sentry_pathiter_t *piter
= sentry__path_iter_directory(retry->run->cache_path);
if (!piter) {
Expand Down
2 changes: 1 addition & 1 deletion src/sentry_session.c
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ sentry__capture_session(sentry_session_t *session)
sentry__envelope_add_session(envelope, session);

SENTRY_WITH_OPTIONS (options) {
sentry__capture_envelope(options->transport, envelope);
sentry__capture_envelope(options->transport, envelope, options);
}
}

Expand Down
Loading
Loading