Skip to content

Commit 8edeff9

Browse files
jpnurmiclaude
andauthored
feat(native): consent-aware offline caching (#1649)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 1a70e61 commit 8edeff9

14 files changed

Lines changed: 125 additions & 47 deletions

examples/example.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -699,7 +699,7 @@ main(int argc, char **argv)
699699
}
700700
if (has_arg(argc, argv, "cache-keep")) {
701701
sentry_options_set_cache_keep(options, true);
702-
sentry_options_set_cache_max_size(options, 4 * 1024 * 1024); // 4 MB
702+
sentry_options_set_cache_max_size(options, 16 * 1024 * 1024); // 16 MB
703703
sentry_options_set_cache_max_age(options, 5 * 24 * 60 * 60); // 5 days
704704
sentry_options_set_cache_max_items(options, 5);
705705
}

src/backends/native/sentry_crash_context.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,11 @@ typedef struct {
273273
bool debug_enabled; // Debug logging enabled in parent process
274274
bool attach_screenshot; // Screenshot attachment enabled in parent process
275275
bool cache_keep;
276+
bool require_user_consent;
277+
278+
// Atomic user consent (sentry_user_consent_t), updated whenever user
279+
// consent changes so the daemon can honor it at crash time.
280+
volatile long user_consent;
276281

277282
// Platform-specific crash context
278283
#if defined(SENTRY_PLATFORM_LINUX) || defined(SENTRY_PLATFORM_ANDROID)

src/backends/native/sentry_crash_daemon.c

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2911,6 +2911,11 @@ sentry__process_crash(const sentry_options_t *options, sentry_crash_ipc_t *ipc)
29112911
}
29122912
#endif
29132913

2914+
if (options->run) {
2915+
sentry__atomic_store(&options->run->user_consent,
2916+
sentry__atomic_fetch(&ctx->user_consent));
2917+
}
2918+
29142919
sentry_path_t *env_path = sentry__path_from_str(envelope_path);
29152920
if (!env_path) {
29162921
SENTRY_WARN("Failed to create envelope path");
@@ -2925,15 +2930,14 @@ sentry__process_crash(const sentry_options_t *options, sentry_crash_ipc_t *ipc)
29252930
goto cleanup;
29262931
}
29272932

2928-
SENTRY_DEBUG("Envelope loaded, sending via transport");
2933+
SENTRY_DEBUG("Envelope loaded, capturing");
29292934

2930-
// Send directly via transport, or to external crash reporter
2935+
// Capture directly, or pass to external crash reporter
29312936
if (!sentry__launch_external_crash_reporter(options, envelope)) {
2932-
// Send directly via transport
2933-
if (options && options->transport) {
2934-
SENTRY_DEBUG("Calling transport send_envelope");
2935-
sentry__transport_send_envelope(options->transport, envelope);
2936-
SENTRY_DEBUG("Crash envelope sent to transport (queued)");
2937+
if (options && options->transport && options->run) {
2938+
SENTRY_DEBUG("Capturing crash envelope");
2939+
sentry__capture_envelope(options->transport, envelope, options);
2940+
SENTRY_DEBUG("Crash envelope captured (queued)");
29372941
} else {
29382942
SENTRY_WARN("No transport available for sending envelope");
29392943
sentry_envelope_free(envelope);
@@ -2954,7 +2958,7 @@ sentry__process_crash(const sentry_options_t *options, sentry_crash_ipc_t *ipc)
29542958

29552959
cleanup:
29562960
// Send all other envelopes from run folder (logs, etc.) before cleanup
2957-
if (run_folder && options && options->transport) {
2961+
if (run_folder && options && options->transport && options->run) {
29582962
SENTRY_DEBUG("Checking for additional envelopes in run folder");
29592963
sentry_pathiter_t *piter = sentry__path_iter_directory(run_folder);
29602964
if (piter) {
@@ -2971,8 +2975,8 @@ sentry__process_crash(const sentry_options_t *options, sentry_crash_ipc_t *ipc)
29712975
sentry_envelope_t *run_envelope
29722976
= sentry__envelope_from_path(file_path);
29732977
if (run_envelope) {
2974-
sentry__transport_send_envelope(
2975-
options->transport, run_envelope);
2978+
sentry__capture_envelope(
2979+
options->transport, run_envelope, options);
29762980
envelope_count++;
29772981
} else {
29782982
SENTRY_WARNF("Failed to load envelope: %s", path_str);
@@ -3216,6 +3220,10 @@ sentry__crash_daemon_main(pid_t app_pid, uint64_t app_tid, HANDLE event_handle,
32163220
sentry_path_t *db_path = sentry__path_from_str(ipc->shmem->database_path);
32173221
if (db_path) {
32183222
options->run = sentry__run_new(db_path);
3223+
if (options->run) {
3224+
options->run->require_user_consent
3225+
= ipc->shmem->require_user_consent;
3226+
}
32193227
sentry__path_free(db_path);
32203228
}
32213229

src/backends/sentry_backend_breakpad.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ breakpad_backend_callback(const google_breakpad::MinidumpDescriptor &descriptor,
205205
// capture the envelope with the disk transport
206206
sentry_transport_t *disk_transport
207207
= sentry_new_disk_transport(options->run);
208-
sentry__capture_envelope(disk_transport, envelope);
208+
sentry__capture_envelope(disk_transport, envelope, options);
209209
sentry__transport_dump_queue(disk_transport, options->run);
210210
sentry_transport_free(disk_transport);
211211
}

src/backends/sentry_backend_crashpad.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ crashpad_handler(int signum, siginfo_t *info, ucontext_t *user_context)
382382
// capture the envelope with the disk transport
383383
sentry_transport_t *disk_transport
384384
= sentry_new_disk_transport(options->run);
385-
sentry__capture_envelope(disk_transport, envelope);
385+
sentry__capture_envelope(disk_transport, envelope, options);
386386
sentry__transport_dump_queue(disk_transport, options->run);
387387
sentry_transport_free(disk_transport);
388388
}

src/backends/sentry_backend_inproc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1206,7 +1206,7 @@ process_ucontext_deferred(const sentry_ucontext_t *uctx,
12061206
// capture the envelope with the disk transport
12071207
sentry_transport_t *disk_transport
12081208
= sentry_new_disk_transport(options->run);
1209-
sentry__capture_envelope(disk_transport, envelope);
1209+
sentry__capture_envelope(disk_transport, envelope, options);
12101210
sentry__transport_dump_queue(disk_transport, options->run);
12111211
sentry_transport_free(disk_transport);
12121212
}

src/backends/sentry_backend_native.c

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,9 @@ native_backend_startup(
193193
ctx->debug_enabled = options->debug;
194194
ctx->attach_screenshot = options->attach_screenshot;
195195
ctx->cache_keep = options->cache_keep;
196+
ctx->require_user_consent = options->require_user_consent;
197+
sentry__atomic_store(
198+
&ctx->user_consent, sentry__atomic_fetch(&options->run->user_consent));
196199

197200
// Set up event and breadcrumb paths
198201
sentry_path_t *run_path = options->run->run_path;
@@ -550,6 +553,21 @@ native_backend_shutdown(sentry_backend_t *backend)
550553
SENTRY_DEBUG("native backend shutdown complete");
551554
}
552555

556+
static void
557+
native_backend_user_consent_changed(sentry_backend_t *backend)
558+
{
559+
native_backend_state_t *state = (native_backend_state_t *)backend->data;
560+
if (!state || !state->ipc || !state->ipc->shmem) {
561+
return;
562+
}
563+
SENTRY_WITH_OPTIONS (options) {
564+
if (options->run) {
565+
sentry__atomic_store(&state->ipc->shmem->user_consent,
566+
sentry__atomic_fetch(&options->run->user_consent));
567+
}
568+
}
569+
}
570+
553571
static void
554572
native_backend_free(sentry_backend_t *backend)
555573
{
@@ -941,7 +959,8 @@ native_backend_except(sentry_backend_t *backend, const sentry_ucontext_t *uctx)
941959
if (disk_transport) {
942960
// sentry__capture_envelope takes ownership of
943961
// envelope
944-
sentry__capture_envelope(disk_transport, envelope);
962+
sentry__capture_envelope(
963+
disk_transport, envelope, options);
945964
sentry__transport_dump_queue(
946965
disk_transport, options->run);
947966
sentry_transport_free(disk_transport);
@@ -988,6 +1007,7 @@ sentry__backend_new(void)
9881007
backend->flush_scope_func = native_backend_flush_scope;
9891008
backend->add_breadcrumb_func = native_backend_add_breadcrumb;
9901009
backend->add_attachment_func = native_backend_add_attachment;
1010+
backend->user_consent_changed_func = native_backend_user_consent_changed;
9911011
backend->can_capture_after_shutdown = false;
9921012

9931013
return backend;

src/sentry_core.c

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -482,22 +482,20 @@ sentry_user_consent_is_required(void)
482482
}
483483

484484
void
485-
sentry__capture_envelope(
486-
sentry_transport_t *transport, sentry_envelope_t *envelope)
485+
sentry__capture_envelope(sentry_transport_t *transport,
486+
sentry_envelope_t *envelope, const sentry_options_t *options)
487487
{
488-
if (!sentry__should_skip_upload()) {
488+
if (!sentry__run_should_skip_upload(options->run)) {
489489
sentry__transport_send_envelope(transport, envelope);
490490
return;
491491
}
492492
bool cached = false;
493-
SENTRY_WITH_OPTIONS (options) {
494-
if (options->cache_keep || options->http_retry) {
495-
cached = sentry__run_write_cache(options->run, envelope, 0);
496-
if (cached && !sentry__run_should_skip_upload(options->run)) {
497-
// consent given meanwhile -> trigger retry to avoid waiting
498-
// until the next retry poll
499-
sentry_transport_retry(options->transport);
500-
}
493+
if (options->cache_keep || options->http_retry) {
494+
cached = sentry__run_write_cache(options->run, envelope, 0);
495+
if (cached && !sentry__run_should_skip_upload(options->run)) {
496+
// consent given meanwhile -> trigger retry to avoid waiting
497+
// until the next retry poll
498+
sentry_transport_retry(options->transport);
501499
}
502500
}
503501
SENTRY_INFO(cached ? "caching envelope due to missing user consent"
@@ -512,7 +510,7 @@ sentry_capture_envelope(sentry_envelope_t *envelope)
512510
return;
513511
}
514512
SENTRY_WITH_OPTIONS (options) {
515-
sentry__capture_envelope(options->transport, envelope);
513+
sentry__capture_envelope(options->transport, envelope, options);
516514
}
517515
}
518516

@@ -621,7 +619,7 @@ sentry__capture_event(sentry_value_t event, sentry_scope_t *local_scope)
621619
SENTRY_DATA_CATEGORY_ERROR, 1);
622620
sentry_envelope_free(envelope);
623621
} else {
624-
sentry__capture_envelope(options->transport, envelope);
622+
sentry__capture_envelope(options->transport, envelope, options);
625623
was_sent = true;
626624
}
627625
}
@@ -1630,7 +1628,7 @@ sentry_capture_user_feedback(sentry_value_t user_report)
16301628
SENTRY_WITH_OPTIONS (options) {
16311629
envelope = prepare_user_report(user_report);
16321630
if (envelope) {
1633-
sentry__capture_envelope(options->transport, envelope);
1631+
sentry__capture_envelope(options->transport, envelope, options);
16341632
}
16351633
}
16361634
sentry_value_decref(user_report);
@@ -1652,7 +1650,7 @@ sentry_capture_feedback_with_hint(
16521650
SENTRY_WITH_OPTIONS (options) {
16531651
envelope = prepare_user_feedback(user_feedback, hint);
16541652
if (envelope) {
1655-
sentry__capture_envelope(options->transport, envelope);
1653+
sentry__capture_envelope(options->transport, envelope, options);
16561654
}
16571655
}
16581656

@@ -1765,7 +1763,7 @@ sentry_capture_minidump_n(const char *path, size_t path_len)
17651763
sentry__envelope_item_set_header(item, "filename",
17661764
sentry_value_new_string(sentry__path_filename(dump_path)));
17671765

1768-
sentry__capture_envelope(options->transport, envelope);
1766+
sentry__capture_envelope(options->transport, envelope, options);
17691767

17701768
SENTRY_INFOF(
17711769
"Minidump has been captured: \"%s\"", dump_path->path);

src/sentry_core.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,8 @@ sentry_envelope_t *sentry__prepare_transaction(const sentry_options_t *options,
9393
* This function will submit the `envelope` to the given `transport`, first
9494
* checking for consent.
9595
*/
96-
void sentry__capture_envelope(
97-
sentry_transport_t *transport, sentry_envelope_t *envelope);
96+
void sentry__capture_envelope(sentry_transport_t *transport,
97+
sentry_envelope_t *envelope, const sentry_options_t *options);
9898

9999
/**
100100
* Generates a new random UUID for events.

src/sentry_database.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -451,15 +451,16 @@ sentry__process_old_runs(const sentry_options_t *options, uint64_t last_crash)
451451
sentry__session_free(session);
452452
if ((++session_num) >= SENTRY_MAX_ENVELOPE_SESSIONS) {
453453
sentry__capture_envelope(
454-
options->transport, session_envelope);
454+
options->transport, session_envelope, options);
455455
session_envelope = NULL;
456456
session_num = 0;
457457
}
458458
}
459459
} else if (sentry__path_ends_with(file, ".envelope")) {
460460
sentry_envelope_t *envelope = sentry__envelope_from_path(file);
461461
if (envelope) {
462-
sentry__capture_envelope(options->transport, envelope);
462+
sentry__capture_envelope(
463+
options->transport, envelope, options);
463464
}
464465
}
465466

@@ -473,7 +474,7 @@ sentry__process_old_runs(const sentry_options_t *options, uint64_t last_crash)
473474
sentry__pathiter_free(db_iter);
474475

475476
if (session_envelope) {
476-
sentry__capture_envelope(options->transport, session_envelope);
477+
sentry__capture_envelope(options->transport, session_envelope, options);
477478
}
478479
}
479480

0 commit comments

Comments
 (0)