Skip to content

Commit 7595ef9

Browse files
jpnurmiclaude
andcommitted
feat(cache): cache revoked envelopes when cache_keep is true
Instead of discarding envelopes when user consent is not given, write them to <database>/cache/ when cache_keep is enabled. For old runs, extend can_cache to also apply when consent is missing, so envelopes are moved to cache instead of being discarded. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent a3c584c commit 7595ef9

4 files changed

Lines changed: 146 additions & 7 deletions

File tree

src/sentry_core.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -504,13 +504,19 @@ void
504504
sentry__capture_envelope(
505505
sentry_transport_t *transport, sentry_envelope_t *envelope)
506506
{
507-
bool has_consent = !sentry__should_skip_upload();
508-
if (!has_consent) {
509-
SENTRY_INFO("discarding envelope due to missing user consent");
510-
sentry_envelope_free(envelope);
507+
if (!sentry__should_skip_upload()) {
508+
sentry__transport_send_envelope(transport, envelope);
511509
return;
512510
}
513-
sentry__transport_send_envelope(transport, envelope);
511+
bool cached = false;
512+
SENTRY_WITH_OPTIONS (options) {
513+
if (options->cache_keep) {
514+
cached = sentry__run_write_cache(options->run, envelope, 0);
515+
}
516+
}
517+
SENTRY_INFO(cached ? "caching envelope due to missing user consent"
518+
: "discarding envelope due to missing user consent");
519+
sentry_envelope_free(envelope);
514520
}
515521

516522
void

src/sentry_database.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "sentry_database.h"
22
#include "sentry_alloc.h"
3+
#include "sentry_core.h"
34
#include "sentry_envelope.h"
45
#include "sentry_json.h"
56
#include "sentry_options.h"
@@ -369,7 +370,7 @@ sentry__process_old_runs(const sentry_options_t *options, uint64_t last_crash)
369370
}
370371

371372
bool can_cache = options->cache_keep
372-
&& (!options->http_retry
373+
&& (sentry__should_skip_upload() || !options->http_retry
373374
|| !sentry__transport_can_retry(options->transport));
374375

375376
sentry_pathiter_t *run_iter = sentry__path_iter_directory(run_dir);
@@ -432,7 +433,9 @@ sentry__process_old_runs(const sentry_options_t *options, uint64_t last_crash)
432433
}
433434
sentry__pathiter_free(db_iter);
434435

435-
sentry__capture_envelope(options->transport, session_envelope);
436+
if (session_envelope) {
437+
sentry__capture_envelope(options->transport, session_envelope);
438+
}
436439
}
437440

438441
// Cache Pruning below is based on prune_crash_reports.cc from Crashpad

tests/unit/test_cache.c

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,133 @@ SENTRY_TEST(cache_max_items_with_retry)
307307
sentry_close();
308308
}
309309

310+
SENTRY_TEST(cache_consent_revoked)
311+
{
312+
#if defined(SENTRY_PLATFORM_NX) || defined(SENTRY_PLATFORM_PS)
313+
SKIP_TEST();
314+
#endif
315+
SENTRY_TEST_OPTIONS_NEW(options);
316+
sentry_options_set_dsn(options, "https://foo@sentry.invalid/42");
317+
sentry_options_set_cache_keep(options, true);
318+
sentry_options_set_require_user_consent(options, true);
319+
sentry_init(options);
320+
sentry_user_consent_revoke();
321+
322+
sentry_path_t *cache_path
323+
= sentry__path_join_str(options->database_path, "cache");
324+
TEST_ASSERT(!!cache_path);
325+
sentry__path_remove_all(cache_path);
326+
327+
sentry_capture_event(
328+
sentry_value_new_message_event(SENTRY_LEVEL_INFO, "test", "revoked"));
329+
330+
int count = 0;
331+
sentry_pathiter_t *iter = sentry__path_iter_directory(cache_path);
332+
const sentry_path_t *entry;
333+
while (iter && (entry = sentry__pathiter_next(iter)) != NULL) {
334+
if (sentry__path_ends_with(entry, ".envelope")) {
335+
count++;
336+
}
337+
}
338+
sentry__pathiter_free(iter);
339+
TEST_CHECK_INT_EQUAL(count, 1);
340+
341+
sentry__path_free(cache_path);
342+
sentry_close();
343+
}
344+
345+
SENTRY_TEST(cache_consent_revoked_nocache)
346+
{
347+
#if defined(SENTRY_PLATFORM_NX) || defined(SENTRY_PLATFORM_PS)
348+
SKIP_TEST();
349+
#endif
350+
SENTRY_TEST_OPTIONS_NEW(options);
351+
sentry_options_set_dsn(options, "https://foo@sentry.invalid/42");
352+
sentry_options_set_cache_keep(options, false);
353+
sentry_options_set_require_user_consent(options, true);
354+
sentry_init(options);
355+
sentry_user_consent_revoke();
356+
357+
sentry_path_t *cache_path
358+
= sentry__path_join_str(options->database_path, "cache");
359+
TEST_ASSERT(!!cache_path);
360+
sentry__path_remove_all(cache_path);
361+
362+
sentry_capture_event(
363+
sentry_value_new_message_event(SENTRY_LEVEL_INFO, "test", "revoked"));
364+
365+
int count = 0;
366+
sentry_pathiter_t *iter = sentry__path_iter_directory(cache_path);
367+
const sentry_path_t *entry;
368+
while (iter && (entry = sentry__pathiter_next(iter)) != NULL) {
369+
if (sentry__path_ends_with(entry, ".envelope")) {
370+
count++;
371+
}
372+
}
373+
sentry__pathiter_free(iter);
374+
TEST_CHECK_INT_EQUAL(count, 0);
375+
376+
sentry__path_free(cache_path);
377+
sentry_close();
378+
}
379+
380+
SENTRY_TEST(cache_consent_revoked_old_run)
381+
{
382+
#if defined(SENTRY_PLATFORM_NX) || defined(SENTRY_PLATFORM_PS)
383+
SKIP_TEST();
384+
#endif
385+
SENTRY_TEST_OPTIONS_NEW(options);
386+
sentry_options_set_dsn(options, "https://foo@sentry.invalid/42");
387+
sentry_options_set_cache_keep(options, true);
388+
sentry_options_set_require_user_consent(options, true);
389+
sentry_init(options);
390+
sentry_user_consent_revoke();
391+
392+
sentry_path_t *cache_path
393+
= sentry__path_join_str(options->database_path, "cache");
394+
TEST_ASSERT(!!cache_path);
395+
sentry__path_remove_all(cache_path);
396+
397+
sentry_path_t *old_run_path
398+
= sentry__path_join_str(options->database_path, "old.run");
399+
TEST_ASSERT(!!old_run_path);
400+
TEST_ASSERT(sentry__path_create_dir_all(old_run_path) == 0);
401+
402+
sentry_envelope_t *envelope = sentry__envelope_new();
403+
TEST_ASSERT(!!envelope);
404+
sentry_uuid_t event_id = sentry_uuid_new_v4();
405+
sentry_value_t event = sentry__value_new_event_with_id(&event_id);
406+
sentry__envelope_add_event(envelope, event);
407+
408+
char *envelope_filename = sentry__uuid_as_filename(&event_id, ".envelope");
409+
TEST_ASSERT(!!envelope_filename);
410+
sentry_path_t *old_envelope_path
411+
= sentry__path_join_str(old_run_path, envelope_filename);
412+
TEST_ASSERT(
413+
sentry_envelope_write_to_path(envelope, old_envelope_path) == 0);
414+
sentry_envelope_free(envelope);
415+
416+
sentry_path_t *cached_envelope_path
417+
= sentry__path_join_str(cache_path, envelope_filename);
418+
TEST_ASSERT(!!cached_envelope_path);
419+
420+
TEST_ASSERT(sentry__path_is_file(old_envelope_path));
421+
TEST_ASSERT(!sentry__path_is_file(cached_envelope_path));
422+
423+
sentry__process_old_runs(options, 0);
424+
425+
TEST_ASSERT(!sentry__path_is_file(old_envelope_path));
426+
TEST_ASSERT(sentry__path_is_file(cached_envelope_path));
427+
TEST_ASSERT(!sentry__path_is_dir(old_run_path));
428+
429+
sentry__path_free(old_envelope_path);
430+
sentry__path_free(cached_envelope_path);
431+
sentry__path_free(old_run_path);
432+
sentry__path_free(cache_path);
433+
sentry_free(envelope_filename);
434+
sentry_close();
435+
}
436+
310437
SENTRY_TEST(cache_max_size_and_age)
311438
{
312439
#if defined(SENTRY_PLATFORM_NX) || defined(SENTRY_PLATFORM_PS)

tests/unit/tests.inc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ XX(bgworker_flush)
4040
XX(bgworker_task_delay)
4141
XX(breadcrumb_without_type_or_message_still_valid)
4242
XX(build_id_parser)
43+
XX(cache_consent_revoked)
44+
XX(cache_consent_revoked_nocache)
45+
XX(cache_consent_revoked_old_run)
4346
XX(cache_keep)
4447
XX(cache_max_age)
4548
XX(cache_max_items)

0 commit comments

Comments
 (0)