|
2 | 2 |
|
3 | 3 | #include "minidump/sentry_minidump_writer.h" |
4 | 4 | #include "sentry_alloc.h" |
| 5 | +#include "sentry_attachment.h" |
5 | 6 | #include "sentry_core.h" |
6 | 7 | #include "sentry_crash_ipc.h" |
7 | 8 | #include "sentry_database.h" |
@@ -195,6 +196,123 @@ write_attachment_to_envelope(int fd, const char *file_path, |
195 | 196 | return true; |
196 | 197 | } |
197 | 198 |
|
| 199 | +// Returns true if the attachment at `file_path` should be staged to the cache |
| 200 | +// and emitted as an attachment-ref item rather than inlined into the envelope. |
| 201 | +static bool |
| 202 | +attachment_is_external(const char *file_path) |
| 203 | +{ |
| 204 | + sentry_path_t *src = sentry__path_from_str(file_path); |
| 205 | + size_t file_size = src ? sentry__path_get_size(src) : 0; |
| 206 | + sentry__path_free(src); |
| 207 | + return file_size >= SENTRY_LARGE_ATTACHMENT_SIZE; |
| 208 | +} |
| 209 | + |
| 210 | +// Stage `src_path` as a sibling of the cached envelope at |
| 211 | +// <db>/cache/<event_id>-<filename> (with `-N` collision suffix). Returns the |
| 212 | +// chosen basename (caller frees) or NULL on failure. |
| 213 | +static char * |
| 214 | +stage_external_attachment(const char *src_path, const char *filename, |
| 215 | + const char *event_id, const char *db_dir) |
| 216 | +{ |
| 217 | + char cache_dir_buf[SENTRY_CRASH_MAX_PATH]; |
| 218 | + int n = snprintf(cache_dir_buf, sizeof(cache_dir_buf), "%s/cache", db_dir); |
| 219 | + if (n <= 0 || (size_t)n >= sizeof(cache_dir_buf)) { |
| 220 | + return NULL; |
| 221 | + } |
| 222 | + sentry_path_t *cache_path = sentry__path_from_str(cache_dir_buf); |
| 223 | + if (!cache_path || sentry__path_create_dir_all(cache_path) != 0) { |
| 224 | + sentry__path_free(cache_path); |
| 225 | + return NULL; |
| 226 | + } |
| 227 | + char buf[256]; |
| 228 | + snprintf(buf, sizeof(buf), "%s-%s", event_id, filename); |
| 229 | + char *basename = sentry__path_unique_name(cache_path, buf); |
| 230 | + if (!basename) { |
| 231 | + sentry__path_free(cache_path); |
| 232 | + return NULL; |
| 233 | + } |
| 234 | + sentry_path_t *dst = sentry__path_join_str(cache_path, basename); |
| 235 | + sentry__path_free(cache_path); |
| 236 | + sentry_path_t *src = sentry__path_from_str(src_path); |
| 237 | + int rv = (src && dst) ? sentry__path_copy(src, dst) : -1; |
| 238 | + sentry__path_free(src); |
| 239 | + sentry__path_free(dst); |
| 240 | + if (rv != 0) { |
| 241 | + sentry_free(basename); |
| 242 | + return NULL; |
| 243 | + } |
| 244 | + return basename; |
| 245 | +} |
| 246 | + |
| 247 | +// For each large attachment listed in `<run_folder>/__sentry-attachments`, |
| 248 | +// stage it to <db>/cache and append an `attachment-ref` item to `envelope`. |
| 249 | +// The transport then uploads via TUS at send time. Small attachments were |
| 250 | +// already inlined during envelope writing. |
| 251 | +static void |
| 252 | +add_external_attachment_refs(sentry_envelope_t *envelope, |
| 253 | + const sentry_path_t *run_folder, const char *db_dir) |
| 254 | +{ |
| 255 | + if (!envelope || !run_folder || !db_dir) { |
| 256 | + return; |
| 257 | + } |
| 258 | + sentry_path_t *attach_list_path |
| 259 | + = sentry__path_join_str(run_folder, "__sentry-attachments"); |
| 260 | + if (!attach_list_path) { |
| 261 | + return; |
| 262 | + } |
| 263 | + size_t attach_json_len = 0; |
| 264 | + char *attach_json |
| 265 | + = sentry__path_read_to_buffer(attach_list_path, &attach_json_len); |
| 266 | + sentry__path_free(attach_list_path); |
| 267 | + if (!attach_json) { |
| 268 | + return; |
| 269 | + } |
| 270 | + sentry_value_t list = attach_json_len > 0 |
| 271 | + ? sentry__value_from_json(attach_json, attach_json_len) |
| 272 | + : sentry_value_new_null(); |
| 273 | + sentry_free(attach_json); |
| 274 | + if (sentry_value_is_null(list)) { |
| 275 | + return; |
| 276 | + } |
| 277 | + |
| 278 | + sentry_uuid_t event_id = sentry__envelope_get_event_id(envelope); |
| 279 | + if (sentry_uuid_is_nil(&event_id)) { |
| 280 | + sentry_value_decref(list); |
| 281 | + return; |
| 282 | + } |
| 283 | + char event_id_str[37]; |
| 284 | + sentry_uuid_as_string(&event_id, event_id_str); |
| 285 | + |
| 286 | + size_t len = sentry_value_get_length(list); |
| 287 | + for (size_t i = 0; i < len; i++) { |
| 288 | + sentry_value_t info = sentry_value_get_by_index(list, i); |
| 289 | + const char *path |
| 290 | + = sentry_value_as_string(sentry_value_get_by_key(info, "path")); |
| 291 | + const char *filename |
| 292 | + = sentry_value_as_string(sentry_value_get_by_key(info, "filename")); |
| 293 | + const char *content_type = sentry_value_as_string( |
| 294 | + sentry_value_get_by_key(info, "content_type")); |
| 295 | + if (!path || !*path || !filename || !*filename |
| 296 | + || !attachment_is_external(path)) { |
| 297 | + continue; |
| 298 | + } |
| 299 | + sentry_path_t *src = sentry__path_from_str(path); |
| 300 | + size_t file_size = src ? sentry__path_get_size(src) : 0; |
| 301 | + sentry__path_free(src); |
| 302 | + char *basename |
| 303 | + = stage_external_attachment(path, filename, event_id_str, db_dir); |
| 304 | + if (!basename) { |
| 305 | + SENTRY_WARNF("Failed to stage large attachment: %s", path); |
| 306 | + continue; |
| 307 | + } |
| 308 | + sentry__envelope_add_attachment_ref(envelope, basename, NULL, filename, |
| 309 | + (content_type && *content_type) ? content_type : NULL, ATTACHMENT, |
| 310 | + sentry_value_new_uint64((uint64_t)file_size)); |
| 311 | + sentry_free(basename); |
| 312 | + } |
| 313 | + sentry_value_decref(list); |
| 314 | +} |
| 315 | + |
198 | 316 | #if defined(SENTRY_PLATFORM_UNIX) |
199 | 317 | /** |
200 | 318 | * Get signal name from signal number (Unix platforms only) |
@@ -2382,7 +2500,7 @@ write_envelope_with_native_stacktrace(const sentry_options_t *options, |
2382 | 2500 | const char *content_type |
2383 | 2501 | = sentry_value_as_string(content_type_val); |
2384 | 2502 |
|
2385 | | - if (path && filename) { |
| 2503 | + if (path && filename && !attachment_is_external(path)) { |
2386 | 2504 | write_attachment_to_envelope( |
2387 | 2505 | fd, path, filename, content_type); |
2388 | 2506 | } |
@@ -2617,7 +2735,7 @@ write_envelope_with_minidump(const sentry_options_t *options, |
2617 | 2735 | const char *content_type |
2618 | 2736 | = sentry_value_as_string(content_type_val); |
2619 | 2737 |
|
2620 | | - if (path && filename) { |
| 2738 | + if (path && filename && !attachment_is_external(path)) { |
2621 | 2739 | write_attachment_to_envelope( |
2622 | 2740 | fd, path, filename, content_type); |
2623 | 2741 | } |
@@ -2923,6 +3041,8 @@ sentry__process_crash(const sentry_options_t *options, sentry_crash_ipc_t *ipc) |
2923 | 3041 | goto cleanup; |
2924 | 3042 | } |
2925 | 3043 |
|
| 3044 | + add_external_attachment_refs(envelope, run_folder, db_dir); |
| 3045 | + |
2926 | 3046 | SENTRY_DEBUG("Envelope loaded, sending via transport"); |
2927 | 3047 |
|
2928 | 3048 | // Send directly via transport, or to external crash reporter |
|
0 commit comments