From 509ae8a063af6c081f55ed187a3fd047bec5c4b9 Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Fri, 21 Apr 2023 11:19:00 +0200 Subject: [PATCH 01/10] Allow setting sdk_name at runtime --- include/sentry.h | 26 +++++++++- src/backends/sentry_backend_crashpad.cpp | 3 +- src/sentry_options.c | 35 +++++++++++++ src/sentry_options.h | 2 + src/sentry_scope.c | 6 ++- src/sentry_transport.c | 4 +- src/sentry_utils.c | 17 ++++--- src/sentry_utils.h | 6 ++- tests/unit/CMakeLists.txt | 1 + tests/unit/test_options.c | 65 ++++++++++++++++++++++++ tests/unit/test_utils.c | 18 +++++-- tests/unit/tests.inc | 4 ++ 12 files changed, 168 insertions(+), 19 deletions(-) create mode 100644 tests/unit/test_options.c diff --git a/include/sentry.h b/include/sentry.h index 088f81dffc..caf973f1eb 100644 --- a/include/sentry.h +++ b/include/sentry.h @@ -971,6 +971,26 @@ SENTRY_API void sentry_options_set_transport_thread_name( SENTRY_API const char *sentry_options_get_transport_thread_name( const sentry_options_t *opts); +/* + * Configures the name of the sentry SDK. Returns 0 on success. + */ +SENTRY_API int sentry_options_set_sdk_name( + sentry_options_t *opts, const char *sdk_name); + +/** + * Returns the configured sentry SDK name. Unless overwritten this defaults to + * SENTRY_SDK_NAME. + */ +SENTRY_API const char *sentry_options_get_sdk_name( + const sentry_options_t *opts); + +/** + * Returns the user agent. Unless overwritten this defaults to + * "SENTRY_SDK_NAME / SENTRY_SDK_VERSION". + */ +SENTRY_API const char *sentry_options_get_user_agent( + const sentry_options_t *opts); + /** * Enables or disables debug printing mode. */ @@ -1883,12 +1903,14 @@ SENTRY_EXPERIMENTAL_API int sentry_clear_crashed_last_run(void); SENTRY_EXPERIMENTAL_API const char *sentry_sdk_version(void); /** - * Sentry SDK name. + * Sentry SDK name set during build time. + * Deprecated: Please use sentry_options_get_sdk_name instead. */ SENTRY_EXPERIMENTAL_API const char *sentry_sdk_name(void); /** - * Sentry SDK User-Agent. + * Sentry SDK User-Agent set during build time. + * Deprecated: Please use sentry_options_get_user_agent instead. */ SENTRY_EXPERIMENTAL_API const char *sentry_sdk_user_agent(void); diff --git a/src/backends/sentry_backend_crashpad.cpp b/src/backends/sentry_backend_crashpad.cpp index c44672341e..381779296c 100644 --- a/src/backends/sentry_backend_crashpad.cpp +++ b/src/backends/sentry_backend_crashpad.cpp @@ -311,7 +311,8 @@ sentry__crashpad_backend_startup( data->db = crashpad::CrashReportDatabase::Initialize(database).release(); crashpad::CrashpadClient client; - char *minidump_url = sentry__dsn_get_minidump_url(options->dsn); + char *minidump_url + = sentry__dsn_get_minidump_url(options->dsn, options->user_agent); SENTRY_TRACEF("using minidump url \"%s\"", minidump_url); std::string url = minidump_url ? std::string(minidump_url) : std::string(); sentry_free(minidump_url); diff --git a/src/sentry_options.c b/src/sentry_options.c index b0a6fe8aa6..10ab4cb913 100644 --- a/src/sentry_options.c +++ b/src/sentry_options.c @@ -36,6 +36,7 @@ sentry_options_new(void) if (!opts->environment) { opts->environment = sentry__string_clone("production"); } + sentry_options_set_sdk_name(opts, SENTRY_SDK_NAME); opts->max_breadcrumbs = SENTRY_BREADCRUMBS_MAX; opts->user_consent = SENTRY_USER_CONSENT_UNKNOWN; opts->auto_session_tracking = true; @@ -239,6 +240,40 @@ sentry_options_get_transport_thread_name(const sentry_options_t *opts) return opts->transport_thread_name; } +int +sentry_options_set_sdk_name(sentry_options_t *opts, const char *name) +{ + if (!opts || !name) { + return 1; + } + + sentry_free(opts->sdk_name); + opts->sdk_name = sentry__string_clone(name); + + sentry_stringbuilder_t sb; + sentry__stringbuilder_init(&sb); + sentry__stringbuilder_append(&sb, name); + sentry__stringbuilder_append(&sb, "/"); + sentry__stringbuilder_append(&sb, SENTRY_SDK_VERSION); + + sentry_free(opts->user_agent); + opts->user_agent = sentry__stringbuilder_into_string(&sb); + + return 0; +} + +const char * +sentry_options_get_sdk_name(const sentry_options_t *opts) +{ + return opts->sdk_name; +} + +const char * +sentry_options_get_user_agent(const sentry_options_t *opts) +{ + return opts->user_agent; +} + void sentry_options_set_debug(sentry_options_t *opts, int debug) { diff --git a/src/sentry_options.h b/src/sentry_options.h index c6b3c10dc8..060b17f708 100644 --- a/src/sentry_options.h +++ b/src/sentry_options.h @@ -38,6 +38,8 @@ typedef struct sentry_options_s { char *http_proxy; char *ca_certs; char *transport_thread_name; + char *sdk_name; + char *user_agent; sentry_path_t *database_path; sentry_path_t *handler_path; sentry_logger_t logger; diff --git a/src/sentry_scope.c b/src/sentry_scope.c index 0201a673bb..b72cd42db5 100644 --- a/src/sentry_scope.c +++ b/src/sentry_scope.c @@ -29,8 +29,10 @@ get_client_sdk(void) { sentry_value_t client_sdk = sentry_value_new_object(); - sentry_value_t name = sentry_value_new_string(SENTRY_SDK_NAME); - sentry_value_set_by_key(client_sdk, "name", name); + SENTRY_WITH_OPTIONS (options) { + sentry_value_t sdk_name = sentry_value_new_string(options->sdk_name); + sentry_value_set_by_key(client_sdk, "name", sdk_name); + } sentry_value_t version = sentry_value_new_string(SENTRY_SDK_VERSION); sentry_value_set_by_key(client_sdk, "version", version); diff --git a/src/sentry_transport.c b/src/sentry_transport.c index 4ff909e03b..004d707fb2 100644 --- a/src/sentry_transport.c +++ b/src/sentry_transport.c @@ -189,7 +189,9 @@ sentry__prepare_http_request(sentry_envelope_t *envelope, sentry_prepared_http_header_t *h; h = &req->headers[req->headers_len++]; h->key = "x-sentry-auth"; - h->value = sentry__dsn_get_auth_header(dsn); + SENTRY_WITH_OPTIONS (options) { + h->value = sentry__dsn_get_auth_header(dsn, options->user_agent); + } h = &req->headers[req->headers_len++]; h->key = "content-type"; diff --git a/src/sentry_utils.c b/src/sentry_utils.c index 2319fc9889..e16f405932 100644 --- a/src/sentry_utils.c +++ b/src/sentry_utils.c @@ -302,17 +302,17 @@ sentry__dsn_decref(sentry_dsn_t *dsn) } char * -sentry__dsn_get_auth_header(const sentry_dsn_t *dsn) +sentry__dsn_get_auth_header(const sentry_dsn_t *dsn, const char *user_agent) { - if (!dsn || !dsn->is_valid) { + if (!dsn || !dsn->is_valid || !user_agent) { return NULL; } sentry_stringbuilder_t sb; sentry__stringbuilder_init(&sb); sentry__stringbuilder_append(&sb, "Sentry sentry_key="); sentry__stringbuilder_append(&sb, dsn->public_key); - sentry__stringbuilder_append( - &sb, ", sentry_version=7, sentry_client=" SENTRY_SDK_USER_AGENT); + sentry__stringbuilder_append(&sb, ", sentry_version=7, sentry_client="); + sentry__stringbuilder_append(&sb, user_agent); return sentry__stringbuilder_into_string(&sb); } @@ -343,15 +343,16 @@ sentry__dsn_get_envelope_url(const sentry_dsn_t *dsn) } char * -sentry__dsn_get_minidump_url(const sentry_dsn_t *dsn) +sentry__dsn_get_minidump_url(const sentry_dsn_t *dsn, const char *user_agent) { - if (!dsn || !dsn->is_valid) { + if (!dsn || !dsn->is_valid || !user_agent) { return NULL; } sentry_stringbuilder_t sb; init_string_builder_for_url(&sb, dsn); - sentry__stringbuilder_append( - &sb, "/minidump/?sentry_client=" SENTRY_SDK_USER_AGENT "&sentry_key="); + sentry__stringbuilder_append(&sb, "/minidump/?sentry_client="); + sentry__stringbuilder_append(&sb, user_agent); + sentry__stringbuilder_append(&sb, "&sentry_key="); sentry__stringbuilder_append(&sb, dsn->public_key); return sentry__stringbuilder_into_string(&sb); } diff --git a/src/sentry_utils.h b/src/sentry_utils.h index 703b53c3f2..6d0f0b6908 100644 --- a/src/sentry_utils.h +++ b/src/sentry_utils.h @@ -79,7 +79,8 @@ void sentry__dsn_decref(sentry_dsn_t *dsn); * described here: * https://docs.sentry.io/development/sdk-dev/overview/#authentication */ -char *sentry__dsn_get_auth_header(const sentry_dsn_t *dsn); +char *sentry__dsn_get_auth_header( + const sentry_dsn_t *dsn, const char *user_agent); /** * Returns the envelope endpoint url used for normal uploads as a newly @@ -91,7 +92,8 @@ char *sentry__dsn_get_envelope_url(const sentry_dsn_t *dsn); * Returns the minidump endpoint url used for uploads done by the out-of-process * crashpad backend as a newly allocated string. */ -char *sentry__dsn_get_minidump_url(const sentry_dsn_t *dsn); +char *sentry__dsn_get_minidump_url( + const sentry_dsn_t *dsn, const char *user_agent); /** * Returns the number of milliseconds since the unix epoch. diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 93acedf270..840c855619 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -28,6 +28,7 @@ add_executable(sentry_test_unit test_logger.c test_modulefinder.c test_mpack.c + test_options.c test_path.c test_ratelimiter.c test_sampling.c diff --git a/tests/unit/test_options.c b/tests/unit/test_options.c new file mode 100644 index 0000000000..3c1c877268 --- /dev/null +++ b/tests/unit/test_options.c @@ -0,0 +1,65 @@ +#include "sentry_options.h" +#include "sentry_string.h" +#include "sentry_testsupport.h" + +#include "sentry_options.h" +#include "sentry_string.h" +#include "sentry_testsupport.h" + +SENTRY_TEST(options_sdk_name_defaults) +{ + sentry_options_t *options = sentry_options_new(); + // when nothing is set + + // then both sdk name and user agent should default to the build time + // directives + TEST_CHECK_STRING_EQUAL( + sentry_options_get_sdk_name(options), SENTRY_SDK_NAME); + TEST_CHECK_STRING_EQUAL( + sentry_options_get_user_agent(options), SENTRY_SDK_USER_AGENT); + + sentry_options_free(options); +} + +SENTRY_TEST(options_sdk_name_custom) +{ + sentry_options_t *options = sentry_options_new(); + + // when the sdk name is set to a custom string + const char *sdk_name = "sentry.native.android.flutter"; + const int result = sentry_options_set_sdk_name(options, sdk_name); + + // both the sdk_name and user_agent should reflect this change + TEST_CHECK_INT_EQUAL(result, 0); + TEST_CHECK_STRING_EQUAL(sentry_options_get_sdk_name(options), sdk_name); + + sentry_stringbuilder_t sb; + sentry__stringbuilder_init(&sb); + sentry__stringbuilder_append(&sb, sdk_name); + sentry__stringbuilder_append(&sb, "/"); + sentry__stringbuilder_append(&sb, SENTRY_SDK_VERSION); + const char *expected_user_agent = sentry__stringbuilder_into_string(&sb); + + TEST_CHECK_STRING_EQUAL( + sentry_options_get_user_agent(options), expected_user_agent); + + sentry_options_free(options); +} + +SENTRY_TEST(options_sdk_name_invalid) +{ + sentry_options_t *options = sentry_options_new(); + + // when the sdk name is set to an invalid value + const char *sdk_name = NULL; + const int result = sentry_options_set_sdk_name(options, sdk_name); + + // then the value should should be ignored + TEST_CHECK_INT_EQUAL(result, 1); + TEST_CHECK_STRING_EQUAL( + sentry_options_get_sdk_name(options), SENTRY_SDK_NAME); + TEST_CHECK_STRING_EQUAL( + sentry_options_get_user_agent(options), SENTRY_SDK_USER_AGENT); + + sentry_options_free(options); +} diff --git a/tests/unit/test_utils.c b/tests/unit/test_utils.c index 855f59d3d7..00903eee7d 100644 --- a/tests/unit/test_utils.c +++ b/tests/unit/test_utils.c @@ -152,7 +152,7 @@ SENTRY_TEST(dsn_store_url_with_path) TEST_CHECK_STRING_EQUAL( url, "http://example.com:80/foo/bar/api/42/envelope/"); sentry_free(url); - url = sentry__dsn_get_minidump_url(dsn); + url = sentry__dsn_get_minidump_url(dsn, SENTRY_SDK_USER_AGENT); TEST_CHECK_STRING_EQUAL(url, "http://example.com:80/foo/bar/api/42/minidump/" "?sentry_client=" SENTRY_SDK_USER_AGENT "&sentry_key=username"); @@ -168,7 +168,7 @@ SENTRY_TEST(dsn_store_url_without_path) url = sentry__dsn_get_envelope_url(dsn); TEST_CHECK_STRING_EQUAL(url, "http://example.com:80/api/42/envelope/"); sentry_free(url); - url = sentry__dsn_get_minidump_url(dsn); + url = sentry__dsn_get_minidump_url(dsn, SENTRY_SDK_USER_AGENT); TEST_CHECK_STRING_EQUAL(url, "http://example.com:80/api/42/minidump/" "?sentry_client=" SENTRY_SDK_USER_AGENT "&sentry_key=username"); @@ -176,6 +176,18 @@ SENTRY_TEST(dsn_store_url_without_path) sentry__dsn_decref(dsn); } +SENTRY_TEST(dsn_store_url_custom_agent) +{ + sentry_dsn_t *dsn + = sentry__dsn_new("http://username:password@example.com/42?x=y#z"); + char *url = sentry__dsn_get_minidump_url(dsn, "custom_user_agent"); + TEST_CHECK_STRING_EQUAL(url, + "http://example.com:80/api/42/minidump/" + "?sentry_client=custom_user_agent&sentry_key=username"); + sentry_free(url); + sentry__dsn_decref(dsn); +} + SENTRY_TEST(page_allocator) { #ifndef SENTRY_PLATFORM_UNIX @@ -249,4 +261,4 @@ SENTRY_TEST(check_version) TEST_CHECK(!sentry__check_min_version( (sentry_version_t) { .major = 7, .minor = 10, .patch = 6 }, (sentry_version_t) { .major = 7, .minor = 10, .patch = 7 })); -} \ No newline at end of file +} diff --git a/tests/unit/tests.inc b/tests/unit/tests.inc index c60d465545..8dea789685 100644 --- a/tests/unit/tests.inc +++ b/tests/unit/tests.inc @@ -29,6 +29,7 @@ XX(dsn_parsing_complete) XX(dsn_parsing_invalid) XX(dsn_store_url_with_path) XX(dsn_store_url_without_path) +XX(dsn_store_url_custom_agent) XX(empty_transport) XX(fuzz_json) XX(init_failure) @@ -95,3 +96,6 @@ XX(value_set_stacktrace) XX(value_string) XX(value_unicode) XX(value_wrong_type) +XX(options_sdk_name_defaults) +XX(options_sdk_name_custom) +XX(options_sdk_name_invalid) From e0acb2d2df62dd568d091a8307c86e69ec197b70 Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Fri, 21 Apr 2023 11:24:22 +0200 Subject: [PATCH 02/10] Update Changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 69c253cc5a..3d0d4997b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +**Features**: + +- Allow setting sdk_name at runtime ([#834](https://github.com/getsentry/sentry-native/pull/834)) + ## 0.6.1 **Fixes**: From 83cd9465219ba3fe3191bd75beedd04d26585dd8 Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Wed, 26 Apr 2023 10:24:32 +0200 Subject: [PATCH 03/10] Add sentry_options_set_sdk_name_n API --- include/sentry.h | 6 ++++++ src/sentry_options.c | 19 +++++++++++++++---- tests/unit/tests.inc | 4 ++-- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/include/sentry.h b/include/sentry.h index 565cf54cee..17760e24cc 100644 --- a/include/sentry.h +++ b/include/sentry.h @@ -1014,6 +1014,12 @@ SENTRY_API const char *sentry_options_get_transport_thread_name( SENTRY_API int sentry_options_set_sdk_name( sentry_options_t *opts, const char *sdk_name); +/* + * Configures the name of the sentry SDK. Returns 0 on success. + */ +SENTRY_API int sentry_options_set_sdk_name_n( + sentry_options_t *opts, const char *sdk_name, size_t sdk_name_len); + /** * Returns the configured sentry SDK name. Unless overwritten this defaults to * SENTRY_SDK_NAME. diff --git a/src/sentry_options.c b/src/sentry_options.c index 58515b0408..83185391f6 100644 --- a/src/sentry_options.c +++ b/src/sentry_options.c @@ -297,18 +297,29 @@ sentry_options_get_transport_thread_name(const sentry_options_t *opts) } int -sentry_options_set_sdk_name(sentry_options_t *opts, const char *name) +sentry_options_set_sdk_name(sentry_options_t *opts, const char *sdk_name) { - if (!opts || !name) { + if (!opts || !sdk_name) { + return 1; + } + const size_t sdk_name_len = strlen(sdk_name); + return sentry_options_set_sdk_name_n(opts, sdk_name, sdk_name_len); +} + +int +sentry_options_set_sdk_name_n( + sentry_options_t *opts, const char *sdk_name, size_t sdk_name_len) +{ + if (!opts || !sdk_name) { return 1; } sentry_free(opts->sdk_name); - opts->sdk_name = sentry__string_clone(name); + opts->sdk_name = sentry__string_clone_n(sdk_name, sdk_name_len); sentry_stringbuilder_t sb; sentry__stringbuilder_init(&sb); - sentry__stringbuilder_append(&sb, name); + sentry__stringbuilder_append(&sb, opts->sdk_name); sentry__stringbuilder_append(&sb, "/"); sentry__stringbuilder_append(&sb, SENTRY_SDK_VERSION); diff --git a/tests/unit/tests.inc b/tests/unit/tests.inc index d5271b81f9..712296f591 100644 --- a/tests/unit/tests.inc +++ b/tests/unit/tests.inc @@ -29,9 +29,9 @@ XX(distributed_headers) XX(drop_unfinished_spans) XX(dsn_parsing_complete) XX(dsn_parsing_invalid) +XX(dsn_store_url_custom_agent) XX(dsn_store_url_with_path) XX(dsn_store_url_without_path) -XX(dsn_store_url_custom_agent) XX(dsn_with_ending_forward_slash_will_be_cleaned) XX(dsn_with_non_http_scheme_is_invalid) XX(dsn_without_project_id_is_invalid) @@ -52,8 +52,8 @@ XX(mpack_newlines) XX(mpack_removed_tags) XX(multiple_inits) XX(multiple_transactions) -XX(options_sdk_name_defaults) XX(options_sdk_name_custom) +XX(options_sdk_name_defaults) XX(options_sdk_name_invalid) XX(os) XX(overflow_spans) From 40f54aa6578ade467b15329daade887af7b0069b Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Wed, 26 Apr 2023 21:02:59 +0200 Subject: [PATCH 04/10] Improve user_agent handling, add tests for auth header --- src/sentry_scope.c | 5 ++++ src/sentry_transport.c | 7 +++-- src/sentry_transport.h | 2 +- src/sentry_utils.c | 12 ++++++--- src/transports/sentry_transport_curl.c | 5 +++- src/transports/sentry_transport_winhttp.c | 2 +- tests/unit/test_envelopes.c | 8 +++--- tests/unit/test_options.c | 23 +++++------------ tests/unit/test_utils.c | 31 +++++++++++++++++++++++ tests/unit/tests.inc | 4 +++ 10 files changed, 68 insertions(+), 31 deletions(-) diff --git a/src/sentry_scope.c b/src/sentry_scope.c index b72cd42db5..a98a583ba3 100644 --- a/src/sentry_scope.c +++ b/src/sentry_scope.c @@ -33,6 +33,11 @@ get_client_sdk(void) sentry_value_t sdk_name = sentry_value_new_string(options->sdk_name); sentry_value_set_by_key(client_sdk, "name", sdk_name); } + // in case the SDK is not initialized yet, fallback to build-time value + if (sentry_value_is_null(sentry_value_get_by_key(client_sdk, "name"))) { + sentry_value_t sdk_name = sentry_value_new_string(SENTRY_SDK_NAME); + sentry_value_set_by_key(client_sdk, "name", sdk_name); + } sentry_value_t version = sentry_value_new_string(SENTRY_SDK_VERSION); sentry_value_set_by_key(client_sdk, "version", version); diff --git a/src/sentry_transport.c b/src/sentry_transport.c index 004d707fb2..ea62c56204 100644 --- a/src/sentry_transport.c +++ b/src/sentry_transport.c @@ -150,7 +150,8 @@ sentry_transport_free(sentry_transport_t *transport) sentry_prepared_http_request_t * sentry__prepare_http_request(sentry_envelope_t *envelope, - const sentry_dsn_t *dsn, const sentry_rate_limiter_t *rl) + const sentry_dsn_t *dsn, const sentry_rate_limiter_t *rl, + const char *user_agent) { if (!dsn || !dsn->is_valid) { return NULL; @@ -189,9 +190,7 @@ sentry__prepare_http_request(sentry_envelope_t *envelope, sentry_prepared_http_header_t *h; h = &req->headers[req->headers_len++]; h->key = "x-sentry-auth"; - SENTRY_WITH_OPTIONS (options) { - h->value = sentry__dsn_get_auth_header(dsn, options->user_agent); - } + h->value = sentry__dsn_get_auth_header(dsn, user_agent); h = &req->headers[req->headers_len++]; h->key = "content-type"; diff --git a/src/sentry_transport.h b/src/sentry_transport.h index f307881072..e29dc09f5b 100644 --- a/src/sentry_transport.h +++ b/src/sentry_transport.h @@ -82,7 +82,7 @@ typedef struct sentry_prepared_http_request_s { */ sentry_prepared_http_request_t *sentry__prepare_http_request( sentry_envelope_t *envelope, const sentry_dsn_t *dsn, - const sentry_rate_limiter_t *rl); + const sentry_rate_limiter_t *rl, const char *user_agent); /** * Free a previously allocated HTTP request. diff --git a/src/sentry_utils.c b/src/sentry_utils.c index 1179f8e7bd..45f32081e5 100644 --- a/src/sentry_utils.c +++ b/src/sentry_utils.c @@ -314,15 +314,21 @@ sentry__dsn_decref(sentry_dsn_t *dsn) char * sentry__dsn_get_auth_header(const sentry_dsn_t *dsn, const char *user_agent) { - if (!dsn || !dsn->is_valid || !user_agent) { + if (!dsn || !dsn->is_valid) { return NULL; } sentry_stringbuilder_t sb; sentry__stringbuilder_init(&sb); sentry__stringbuilder_append(&sb, "Sentry sentry_key="); sentry__stringbuilder_append(&sb, dsn->public_key); - sentry__stringbuilder_append(&sb, ", sentry_version=7, sentry_client="); - sentry__stringbuilder_append(&sb, user_agent); + sentry__stringbuilder_append(&sb, ", sentry_version=7"); + + sentry__stringbuilder_append(&sb, ", sentry_client="); + if (user_agent) { + sentry__stringbuilder_append(&sb, user_agent); + } else { + sentry__stringbuilder_append(&sb, SENTRY_SDK_USER_AGENT); + } return sentry__stringbuilder_into_string(&sb); } diff --git a/src/transports/sentry_transport_curl.c b/src/transports/sentry_transport_curl.c index b9f52c8813..11f87e5d2f 100644 --- a/src/transports/sentry_transport_curl.c +++ b/src/transports/sentry_transport_curl.c @@ -16,6 +16,7 @@ typedef struct curl_transport_state_s { sentry_dsn_t *dsn; CURL *curl_handle; + char *user_agent; char *http_proxy; char *ca_certs; sentry_rate_limiter_t *ratelimiter; @@ -52,6 +53,7 @@ sentry__curl_bgworker_state_free(void *_state) sentry__dsn_decref(state->dsn); sentry__rate_limiter_free(state->ratelimiter); sentry_free(state->ca_certs); + sentry_free(state->user_agent); sentry_free(state->http_proxy); sentry_free(state); } @@ -100,6 +102,7 @@ sentry__curl_transport_start( state->dsn = sentry__dsn_incref(options->dsn); state->http_proxy = sentry__string_clone(options->http_proxy); + state->user_agent = sentry__string_clone(options->user_agent); state->ca_certs = sentry__string_clone(options->ca_certs); state->curl_handle = curl_easy_init(); state->debug = options->debug; @@ -168,7 +171,7 @@ sentry__curl_send_task(void *_envelope, void *_state) curl_bgworker_state_t *state = (curl_bgworker_state_t *)_state; sentry_prepared_http_request_t *req = sentry__prepare_http_request( - envelope, state->dsn, state->ratelimiter); + envelope, state->dsn, state->ratelimiter, state->user_agent); if (!req) { return; } diff --git a/src/transports/sentry_transport_winhttp.c b/src/transports/sentry_transport_winhttp.c index 93848c3452..7ca20d8e85 100644 --- a/src/transports/sentry_transport_winhttp.c +++ b/src/transports/sentry_transport_winhttp.c @@ -153,7 +153,7 @@ sentry__winhttp_send_task(void *_envelope, void *_state) uint64_t started = sentry__monotonic_time(); sentry_prepared_http_request_t *req = sentry__prepare_http_request( - envelope, state->dsn, state->ratelimiter); + envelope, state->dsn, state->ratelimiter, state->user_agent); if (!req) { return; } diff --git a/tests/unit/test_envelopes.c b/tests/unit/test_envelopes.c index e0032706cd..7be59db4a5 100644 --- a/tests/unit/test_envelopes.c +++ b/tests/unit/test_envelopes.c @@ -29,7 +29,7 @@ SENTRY_TEST(basic_http_request_preparation_for_event) sentry__envelope_add_event(envelope, event); sentry_prepared_http_request_t *req - = sentry__prepare_http_request(envelope, dsn, NULL); + = sentry__prepare_http_request(envelope, dsn, NULL, NULL); TEST_CHECK_STRING_EQUAL(req->method, "POST"); TEST_CHECK_STRING_EQUAL( req->url, "https://sentry.invalid:443/api/42/envelope/"); @@ -58,7 +58,7 @@ SENTRY_TEST(basic_http_request_preparation_for_transaction) sentry__envelope_add_transaction(envelope, transaction); sentry_prepared_http_request_t *req - = sentry__prepare_http_request(envelope, dsn, NULL); + = sentry__prepare_http_request(envelope, dsn, NULL, NULL); TEST_CHECK_STRING_EQUAL(req->method, "POST"); TEST_CHECK_STRING_EQUAL( req->url, "https://sentry.invalid:443/api/42/envelope/"); @@ -91,7 +91,7 @@ SENTRY_TEST(basic_http_request_preparation_for_event_with_attachment) envelope, msg, sizeof(msg) - 1, "attachment"); sentry_prepared_http_request_t *req - = sentry__prepare_http_request(envelope, dsn, NULL); + = sentry__prepare_http_request(envelope, dsn, NULL, NULL); TEST_CHECK_STRING_EQUAL(req->method, "POST"); TEST_CHECK_STRING_EQUAL( req->url, "https://sentry.invalid:443/api/42/envelope/"); @@ -120,7 +120,7 @@ SENTRY_TEST(basic_http_request_preparation_for_minidump) envelope, msg, sizeof(msg) - 1, "attachment"); sentry_prepared_http_request_t *req - = sentry__prepare_http_request(envelope, dsn, NULL); + = sentry__prepare_http_request(envelope, dsn, NULL, NULL); TEST_CHECK_STRING_EQUAL(req->method, "POST"); TEST_CHECK_STRING_EQUAL( req->url, "https://sentry.invalid:443/api/42/envelope/"); diff --git a/tests/unit/test_options.c b/tests/unit/test_options.c index 3c1c877268..529b914725 100644 --- a/tests/unit/test_options.c +++ b/tests/unit/test_options.c @@ -1,9 +1,4 @@ #include "sentry_options.h" -#include "sentry_string.h" -#include "sentry_testsupport.h" - -#include "sentry_options.h" -#include "sentry_string.h" #include "sentry_testsupport.h" SENTRY_TEST(options_sdk_name_defaults) @@ -26,22 +21,16 @@ SENTRY_TEST(options_sdk_name_custom) sentry_options_t *options = sentry_options_new(); // when the sdk name is set to a custom string - const char *sdk_name = "sentry.native.android.flutter"; - const int result = sentry_options_set_sdk_name(options, sdk_name); + const int result + = sentry_options_set_sdk_name(options, "sentry.native.android.flutter"); // both the sdk_name and user_agent should reflect this change TEST_CHECK_INT_EQUAL(result, 0); - TEST_CHECK_STRING_EQUAL(sentry_options_get_sdk_name(options), sdk_name); - - sentry_stringbuilder_t sb; - sentry__stringbuilder_init(&sb); - sentry__stringbuilder_append(&sb, sdk_name); - sentry__stringbuilder_append(&sb, "/"); - sentry__stringbuilder_append(&sb, SENTRY_SDK_VERSION); - const char *expected_user_agent = sentry__stringbuilder_into_string(&sb); - TEST_CHECK_STRING_EQUAL( - sentry_options_get_user_agent(options), expected_user_agent); + sentry_options_get_sdk_name(options), "sentry.native.android.flutter"); + + TEST_CHECK_STRING_EQUAL(sentry_options_get_user_agent(options), + "sentry.native.android.flutter/" SENTRY_SDK_VERSION); sentry_options_free(options); } diff --git a/tests/unit/test_utils.c b/tests/unit/test_utils.c index 448eafe7a5..fd55d918f5 100644 --- a/tests/unit/test_utils.c +++ b/tests/unit/test_utils.c @@ -294,3 +294,34 @@ SENTRY_TEST(dsn_with_ending_forward_slash_will_be_cleaned) sentry__dsn_decref(dsn); } + +SENTRY_TEST(dsn_auth_header_no_user_agent) +{ + sentry_dsn_t *dsn = sentry__dsn_new("https://key@sentry.io/42"); + const char *auth_header = sentry__dsn_get_auth_header(dsn, NULL); + TEST_CHECK_STRING_EQUAL(auth_header, + "Sentry sentry_key=key, sentry_version=7, " + "sentry_client=" SENTRY_SDK_NAME "/" SENTRY_SDK_VERSION); +} + +SENTRY_TEST(dsn_auth_header_custom_user_agent) +{ + sentry_dsn_t *dsn = sentry__dsn_new("https://key@sentry.io/42"); + const char *auth_header = sentry__dsn_get_auth_header(dsn, "user_agent"); + TEST_CHECK_STRING_EQUAL(auth_header, + "Sentry sentry_key=key, sentry_version=7, " + "sentry_client=user_agent"); +} + +SENTRY_TEST(dsn_auth_header_null_dsn) +{ + const char *auth_header = sentry__dsn_get_auth_header(NULL, NULL); + TEST_CHECK(!auth_header); +} + +SENTRY_TEST(dsn_auth_header_invalid_dsn) +{ + sentry_dsn_t *dsn = sentry__dsn_new("whatever"); + const char *auth_header = sentry__dsn_get_auth_header(dsn, NULL); + TEST_CHECK(!auth_header); +} diff --git a/tests/unit/tests.inc b/tests/unit/tests.inc index 712296f591..1770edfc11 100644 --- a/tests/unit/tests.inc +++ b/tests/unit/tests.inc @@ -27,6 +27,10 @@ XX(custom_logger) XX(discarding_before_send) XX(distributed_headers) XX(drop_unfinished_spans) +XX(dsn_auth_header_custom_user_agent) +XX(dsn_auth_header_invalid_dsn) +XX(dsn_auth_header_no_user_agent) +XX(dsn_auth_header_null_dsn) XX(dsn_parsing_complete) XX(dsn_parsing_invalid) XX(dsn_store_url_custom_agent) From 2a1cffcc19385552e93e69b9e4069dbd7fde13dd Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Wed, 26 Apr 2023 21:24:04 +0200 Subject: [PATCH 05/10] Fix missing sentry_free calls sdk_name/user_agent --- src/sentry_options.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sentry_options.c b/src/sentry_options.c index 83185391f6..014ec491f4 100644 --- a/src/sentry_options.c +++ b/src/sentry_options.c @@ -85,6 +85,8 @@ sentry_options_free(sentry_options_t *opts) } sentry__dsn_decref(opts->dsn); sentry_free(opts->release); + sentry_free(opts->sdk_name); + sentry_free(opts->user_agent); sentry_free(opts->environment); sentry_free(opts->dist); sentry_free(opts->http_proxy); From 8c3a5be2e10680d70193cf686330e5f73f0ee5fd Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Thu, 27 Apr 2023 10:34:37 +0200 Subject: [PATCH 06/10] Fix type mismatch for winhttp user_agent --- src/transports/sentry_transport_winhttp.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/transports/sentry_transport_winhttp.c b/src/transports/sentry_transport_winhttp.c index 7ca20d8e85..a9ba3648b2 100644 --- a/src/transports/sentry_transport_winhttp.c +++ b/src/transports/sentry_transport_winhttp.c @@ -15,7 +15,8 @@ typedef struct { sentry_dsn_t *dsn; - wchar_t *user_agent; + char *sdk_user_agent; + wchar_t *winhttp_user_agent; wchar_t *proxy; sentry_rate_limiter_t *ratelimiter; HINTERNET session; @@ -50,7 +51,8 @@ sentry__winhttp_bgworker_state_free(void *_state) } sentry__dsn_decref(state->dsn); sentry__rate_limiter_free(state->ratelimiter); - sentry_free(state->user_agent); + sentry_free(state->sdk_user_agent); + sentry_free(state->winhttp_user_agent); sentry_free(state->proxy); sentry_free(state); } @@ -63,7 +65,8 @@ sentry__winhttp_transport_start( winhttp_bgworker_state_t *state = sentry__bgworker_get_state(bgworker); state->dsn = sentry__dsn_incref(opts->dsn); - state->user_agent = sentry__string_to_wstr(SENTRY_SDK_USER_AGENT); + state->sdk_user_agent = sentry__string_clone(opts->user_agent); + state->winhttp_user_agent = sentry__string_to_wstr(opts->user_agent); state->debug = opts->debug; sentry__bgworker_setname(bgworker, opts->transport_thread_name); @@ -83,19 +86,19 @@ sentry__winhttp_transport_start( } if (state->proxy) { - state->session - = WinHttpOpen(state->user_agent, WINHTTP_ACCESS_TYPE_NAMED_PROXY, - state->proxy, WINHTTP_NO_PROXY_BYPASS, 0); + state->session = WinHttpOpen(state->winhttp_user_agent, + WINHTTP_ACCESS_TYPE_NAMED_PROXY, state->proxy, + WINHTTP_NO_PROXY_BYPASS, 0); } else { #if _WIN32_WINNT >= 0x0603 - state->session = WinHttpOpen(state->user_agent, + state->session = WinHttpOpen(state->winhttp_user_agent, WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); #endif // On windows 8.0 or lower, WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY does // not work on error we fallback to WINHTTP_ACCESS_TYPE_DEFAULT_PROXY if (!state->session) { - state->session = WinHttpOpen(state->user_agent, + state->session = WinHttpOpen(state->winhttp_user_agent, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); } @@ -153,7 +156,7 @@ sentry__winhttp_send_task(void *_envelope, void *_state) uint64_t started = sentry__monotonic_time(); sentry_prepared_http_request_t *req = sentry__prepare_http_request( - envelope, state->dsn, state->ratelimiter, state->user_agent); + envelope, state->dsn, state->ratelimiter, state->sdk_user_agent); if (!req) { return; } From b75d2f902b15aef1d956e3364274c6353a929533 Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Thu, 27 Apr 2023 10:59:02 +0200 Subject: [PATCH 07/10] Fix missing free of allocated vars --- tests/unit/test_utils.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/unit/test_utils.c b/tests/unit/test_utils.c index fd55d918f5..d5e8c48c79 100644 --- a/tests/unit/test_utils.c +++ b/tests/unit/test_utils.c @@ -311,6 +311,9 @@ SENTRY_TEST(dsn_auth_header_custom_user_agent) TEST_CHECK_STRING_EQUAL(auth_header, "Sentry sentry_key=key, sentry_version=7, " "sentry_client=user_agent"); + + sentry_free(auth_header); + sentry__dsn_decref(dsn); } SENTRY_TEST(dsn_auth_header_null_dsn) @@ -324,4 +327,7 @@ SENTRY_TEST(dsn_auth_header_invalid_dsn) sentry_dsn_t *dsn = sentry__dsn_new("whatever"); const char *auth_header = sentry__dsn_get_auth_header(dsn, NULL); TEST_CHECK(!auth_header); + + sentry_free(auth_header); + sentry__dsn_decref(dsn); } From 616311bbd9955145a4b49af46d23ad552149cdfc Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Thu, 27 Apr 2023 12:00:34 +0200 Subject: [PATCH 08/10] Improve based on PR feedback --- src/transports/sentry_transport_winhttp.c | 25 +++++++++++------------ 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/transports/sentry_transport_winhttp.c b/src/transports/sentry_transport_winhttp.c index a9ba3648b2..a25b82b3cb 100644 --- a/src/transports/sentry_transport_winhttp.c +++ b/src/transports/sentry_transport_winhttp.c @@ -15,8 +15,7 @@ typedef struct { sentry_dsn_t *dsn; - char *sdk_user_agent; - wchar_t *winhttp_user_agent; + wchar_t *user_agent; wchar_t *proxy; sentry_rate_limiter_t *ratelimiter; HINTERNET session; @@ -51,8 +50,7 @@ sentry__winhttp_bgworker_state_free(void *_state) } sentry__dsn_decref(state->dsn); sentry__rate_limiter_free(state->ratelimiter); - sentry_free(state->sdk_user_agent); - sentry_free(state->winhttp_user_agent); + sentry_free(state->user_agent); sentry_free(state->proxy); sentry_free(state); } @@ -65,8 +63,7 @@ sentry__winhttp_transport_start( winhttp_bgworker_state_t *state = sentry__bgworker_get_state(bgworker); state->dsn = sentry__dsn_incref(opts->dsn); - state->sdk_user_agent = sentry__string_clone(opts->user_agent); - state->winhttp_user_agent = sentry__string_to_wstr(opts->user_agent); + state->user_agent = sentry__string_to_wstr(opts->user_agent); state->debug = opts->debug; sentry__bgworker_setname(bgworker, opts->transport_thread_name); @@ -86,19 +83,19 @@ sentry__winhttp_transport_start( } if (state->proxy) { - state->session = WinHttpOpen(state->winhttp_user_agent, - WINHTTP_ACCESS_TYPE_NAMED_PROXY, state->proxy, - WINHTTP_NO_PROXY_BYPASS, 0); + state->session + = WinHttpOpen(state->user_agent, WINHTTP_ACCESS_TYPE_NAMED_PROXY, + state->proxy, WINHTTP_NO_PROXY_BYPASS, 0); } else { #if _WIN32_WINNT >= 0x0603 - state->session = WinHttpOpen(state->winhttp_user_agent, + state->session = WinHttpOpen(state->user_agent, WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); #endif // On windows 8.0 or lower, WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY does // not work on error we fallback to WINHTTP_ACCESS_TYPE_DEFAULT_PROXY if (!state->session) { - state->session = WinHttpOpen(state->winhttp_user_agent, + state->session = WinHttpOpen(state->user_agent, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); } @@ -155,10 +152,11 @@ sentry__winhttp_send_task(void *_envelope, void *_state) uint64_t started = sentry__monotonic_time(); + const char *user_agent = sentry__string_from_wstr(state->user_agent); sentry_prepared_http_request_t *req = sentry__prepare_http_request( - envelope, state->dsn, state->ratelimiter, state->sdk_user_agent); + envelope, state->dsn, state->ratelimiter, user_agent); if (!req) { - return; + goto exit; } wchar_t *url = sentry__string_to_wstr(req->url); @@ -286,6 +284,7 @@ sentry__winhttp_send_task(void *_envelope, void *_state) state->request = NULL; WinHttpCloseHandle(request); } + sentry_free(user_agent); sentry_free(url); sentry_free(headers); sentry__prepared_http_request_free(req); From 8b0e317f65ebc4fde90616b03333662153027a63 Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Thu, 27 Apr 2023 12:13:00 +0200 Subject: [PATCH 09/10] Fix const qualifier errors --- src/transports/sentry_transport_winhttp.c | 2 +- tests/unit/test_utils.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/transports/sentry_transport_winhttp.c b/src/transports/sentry_transport_winhttp.c index a25b82b3cb..fc9422f59c 100644 --- a/src/transports/sentry_transport_winhttp.c +++ b/src/transports/sentry_transport_winhttp.c @@ -152,7 +152,7 @@ sentry__winhttp_send_task(void *_envelope, void *_state) uint64_t started = sentry__monotonic_time(); - const char *user_agent = sentry__string_from_wstr(state->user_agent); + char *user_agent = sentry__string_from_wstr(state->user_agent); sentry_prepared_http_request_t *req = sentry__prepare_http_request( envelope, state->dsn, state->ratelimiter, user_agent); if (!req) { diff --git a/tests/unit/test_utils.c b/tests/unit/test_utils.c index d5e8c48c79..18d382c409 100644 --- a/tests/unit/test_utils.c +++ b/tests/unit/test_utils.c @@ -298,7 +298,7 @@ SENTRY_TEST(dsn_with_ending_forward_slash_will_be_cleaned) SENTRY_TEST(dsn_auth_header_no_user_agent) { sentry_dsn_t *dsn = sentry__dsn_new("https://key@sentry.io/42"); - const char *auth_header = sentry__dsn_get_auth_header(dsn, NULL); + char *auth_header = sentry__dsn_get_auth_header(dsn, NULL); TEST_CHECK_STRING_EQUAL(auth_header, "Sentry sentry_key=key, sentry_version=7, " "sentry_client=" SENTRY_SDK_NAME "/" SENTRY_SDK_VERSION); @@ -307,7 +307,7 @@ SENTRY_TEST(dsn_auth_header_no_user_agent) SENTRY_TEST(dsn_auth_header_custom_user_agent) { sentry_dsn_t *dsn = sentry__dsn_new("https://key@sentry.io/42"); - const char *auth_header = sentry__dsn_get_auth_header(dsn, "user_agent"); + char *auth_header = sentry__dsn_get_auth_header(dsn, "user_agent"); TEST_CHECK_STRING_EQUAL(auth_header, "Sentry sentry_key=key, sentry_version=7, " "sentry_client=user_agent"); @@ -318,14 +318,14 @@ SENTRY_TEST(dsn_auth_header_custom_user_agent) SENTRY_TEST(dsn_auth_header_null_dsn) { - const char *auth_header = sentry__dsn_get_auth_header(NULL, NULL); + char *auth_header = sentry__dsn_get_auth_header(NULL, NULL); TEST_CHECK(!auth_header); } SENTRY_TEST(dsn_auth_header_invalid_dsn) { sentry_dsn_t *dsn = sentry__dsn_new("whatever"); - const char *auth_header = sentry__dsn_get_auth_header(dsn, NULL); + char *auth_header = sentry__dsn_get_auth_header(dsn, NULL); TEST_CHECK(!auth_header); sentry_free(auth_header); From 97b6bfcdab9fae6df5a350f5d7fec55d6b32d7af Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Thu, 27 Apr 2023 19:08:10 +0200 Subject: [PATCH 10/10] Fix missing free --- src/transports/sentry_transport_winhttp.c | 3 ++- tests/unit/test_utils.c | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/transports/sentry_transport_winhttp.c b/src/transports/sentry_transport_winhttp.c index fc9422f59c..ffb114eb9a 100644 --- a/src/transports/sentry_transport_winhttp.c +++ b/src/transports/sentry_transport_winhttp.c @@ -156,7 +156,8 @@ sentry__winhttp_send_task(void *_envelope, void *_state) sentry_prepared_http_request_t *req = sentry__prepare_http_request( envelope, state->dsn, state->ratelimiter, user_agent); if (!req) { - goto exit; + sentry_free(user_agent); + return; } wchar_t *url = sentry__string_to_wstr(req->url); diff --git a/tests/unit/test_utils.c b/tests/unit/test_utils.c index 18d382c409..2323034154 100644 --- a/tests/unit/test_utils.c +++ b/tests/unit/test_utils.c @@ -302,6 +302,9 @@ SENTRY_TEST(dsn_auth_header_no_user_agent) TEST_CHECK_STRING_EQUAL(auth_header, "Sentry sentry_key=key, sentry_version=7, " "sentry_client=" SENTRY_SDK_NAME "/" SENTRY_SDK_VERSION); + + sentry_free(auth_header); + sentry__dsn_decref(dsn); } SENTRY_TEST(dsn_auth_header_custom_user_agent)