Skip to content
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- Add `Dynamic Sampling Context (DSC)` to events. ([#1254](https://github.com/getsentry/sentry-native/pull/1254))
- Add `sentry_value_new_feedback` and `sentry_capture_feedback` to allow capturing [User Feedback](https://develop.sentry.dev/sdk/data-model/envelope-items/#user-feedback). ([#1304](https://github.com/getsentry/sentry-native/pull/1304))
- Deprecate `sentry_value_new_user_feedback` and `sentry_capture_user_feedback` in favor of the new API.
- Add `sentry_envelope_read_from_file`, `sentry_envelope_get_header`, and `sentry_capture_envelope`. ([#1320](https://github.com/getsentry/sentry-native/pull/1320))

**Fixes**:

Expand Down
48 changes: 48 additions & 0 deletions include/sentry.h
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,16 @@ typedef struct sentry_envelope_s sentry_envelope_t;
*/
SENTRY_API void sentry_envelope_free(sentry_envelope_t *envelope);

/**
* Given an Envelope, returns the header if present.
*
* This returns a borrowed value to the headers in the Envelope.
*/
SENTRY_API sentry_value_t sentry_envelope_get_header(
const sentry_envelope_t *envelope, const char *key);
SENTRY_API sentry_value_t sentry_envelope_get_header_n(
const sentry_envelope_t *envelope, const char *key, size_t key_len);

/**
* Given an Envelope, returns the embedded Event if there is one.
*
Expand Down Expand Up @@ -698,6 +708,44 @@ SENTRY_API int sentry_envelope_write_to_file(
SENTRY_API int sentry_envelope_write_to_file_n(
const sentry_envelope_t *envelope, const char *path, size_t path_len);

/**
* De-serializes an envelope.
*
* The return value needs to be freed with sentry_envelope_free().
*
* Returns NULL on failure.
*/
SENTRY_API sentry_envelope_t *sentry_envelope_deserialize(
const char *buf, size_t buf_len);

/**
* De-serializes an envelope from a file.
*
* `path` is assumed to be in platform-specific filesystem path encoding.
*
* API Users on windows are encouraged to use `sentry_envelope_read_from_filew`
* instead.
*/
SENTRY_API sentry_envelope_t *sentry_envelope_read_from_file(const char *path);
SENTRY_API sentry_envelope_t *sentry_envelope_read_from_file_n(
const char *path, size_t path_len);

#ifdef SENTRY_PLATFORM_WINDOWS
/**
* Wide char versions of `sentry_envelope_read_from_file` and
* `sentry_envelope_read_from_file_n`.
*/
SENTRY_API sentry_envelope_t *sentry_envelope_read_from_filew(
const wchar_t *path);
SENTRY_API sentry_envelope_t *sentry_envelope_read_from_filew_n(
const wchar_t *path, size_t path_len);
#endif

/**
* Submits an envelope, first checking for consent.
*/
SENTRY_API void sentry_capture_envelope(sentry_envelope_t *envelope);

/**
* The Sentry Client Options.
*
Expand Down
11 changes: 11 additions & 0 deletions src/sentry_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,17 @@ sentry__capture_envelope(
sentry__transport_send_envelope(transport, envelope);
}

void
sentry_capture_envelope(sentry_envelope_t *envelope)
{
if (!envelope) {
return;
}
SENTRY_WITH_OPTIONS (options) {
sentry__capture_envelope(options->transport, envelope);
}
}

static bool
event_is_considered_error(sentry_value_t event)
{
Expand Down
189 changes: 189 additions & 0 deletions src/sentry_envelope.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "sentry_transport.h"
#include "sentry_value.h"
#include <assert.h>
#include <limits.h>
#include <string.h>

struct sentry_envelope_item_s {
Expand Down Expand Up @@ -65,6 +66,24 @@ envelope_item_cleanup(sentry_envelope_item_t *item)
sentry_free(item->payload);
}

sentry_value_t
sentry_envelope_get_header(const sentry_envelope_t *envelope, const char *key)
{
return sentry_envelope_get_header_n(
envelope, key, sentry__guarded_strlen(key));
}

sentry_value_t
sentry_envelope_get_header_n(
const sentry_envelope_t *envelope, const char *key, size_t key_len)
{
if (!envelope || envelope->is_raw) {
return sentry_value_new_null();
}
return sentry_value_get_by_key_n(
envelope->contents.items.headers, key, key_len);
}

void
sentry__envelope_item_set_header(
sentry_envelope_item_t *item, const char *key, sentry_value_t value)
Expand Down Expand Up @@ -726,6 +745,176 @@ sentry_envelope_write_to_file(
return sentry_envelope_write_to_file_n(envelope, path, strlen(path));
}

// https://develop.sentry.dev/sdk/data-model/envelopes/
sentry_envelope_t *
sentry_envelope_deserialize(const char *buf, size_t buf_len)
{
if (!buf || buf_len == 0) {
return NULL;
}

sentry_envelope_t *envelope = sentry__envelope_new();
if (!envelope) {
goto fail;
}

const char *ptr = buf;
const char *end = buf + buf_len;

// headers
const char *headers_end = memchr(ptr, '\n', (size_t)(end - ptr));
if (!headers_end) {
headers_end = end;
}
size_t headers_len = (size_t)(headers_end - ptr);
sentry_value_decref(envelope->contents.items.headers);
envelope->contents.items.headers
= sentry__value_from_json(ptr, headers_len);
if (sentry_value_get_type(envelope->contents.items.headers)
!= SENTRY_VALUE_TYPE_OBJECT) {
goto fail;
}

ptr = headers_end;
if (ptr < end) {
ptr++; // skip newline
}

// items
while (ptr < end) {
sentry_envelope_item_t *item = envelope_add_item(envelope);
if (!item) {
goto fail;
}

// item headers
const char *item_headers_end = memchr(ptr, '\n', (size_t)(end - ptr));
if (!item_headers_end) {
item_headers_end = end;
}
size_t item_headers_len = (size_t)(item_headers_end - ptr);
sentry_value_decref(item->headers);
item->headers = sentry__value_from_json(ptr, item_headers_len);
if (sentry_value_get_type(item->headers) != SENTRY_VALUE_TYPE_OBJECT) {
goto fail;
}
ptr = item_headers_end + 1; // skip newline

if (ptr > end) {
goto fail;
}

// item payload
sentry_value_t length
= sentry_value_get_by_key(item->headers, "length");
if (sentry_value_is_null(length)) {
// length omitted -> find newline or end of buffer
const char *payload_end = memchr(ptr, '\n', (size_t)(end - ptr));
if (!payload_end) {
payload_end = end;
}
item->payload_len = (size_t)(payload_end - ptr);
} else {
// TODO: sentry_value_as_uint64
// https://github.com/getsentry/sentry-native/pull/1301
int payload_len = sentry_value_as_int32(length);
if (payload_len < 0) {
goto fail;
}
item->payload_len = (size_t)payload_len;
}
if (item->payload_len > 0) {
// TODO: SIZE_MAX
// https://github.com/getsentry/sentry-native/pull/1301
if (ptr + item->payload_len > end
|| item->payload_len > INT32_MAX - 1) {
goto fail;
}
item->payload = sentry_malloc(item->payload_len + 1);
if (!item->payload) {
goto fail;
}
memcpy(item->payload, ptr, item->payload_len);
item->payload[item->payload_len] = '\0';

// item event/transaction
const char *type = sentry_value_as_string(
sentry_value_get_by_key(item->headers, "type"));
if (type
&& (sentry__string_eq(type, "event")
|| sentry__string_eq(type, "transaction"))) {
item->event
= sentry__value_from_json(item->payload, item->payload_len);
}

ptr += item->payload_len;
}

while (ptr < end && *ptr == '\n') {
ptr++;
}
}

return envelope;

fail:
sentry_envelope_free(envelope);
return NULL;
}

static sentry_envelope_t *
parse_envelope_from_file(sentry_path_t *path)
{
if (!path) {
return NULL;
}

size_t buf_len = 0;
char *buf = sentry__path_read_to_buffer(path, &buf_len);
sentry_envelope_t *envelope = sentry_envelope_deserialize(buf, buf_len);
sentry_free(buf);
sentry__path_free(path);
return envelope;
}

sentry_envelope_t *
sentry_envelope_read_from_file(const char *path)
{
if (!path) {
return NULL;
}
return parse_envelope_from_file(sentry__path_from_str(path));
}

sentry_envelope_t *
sentry_envelope_read_from_file_n(const char *path, size_t path_len)
{
if (!path || path_len == 0) {
return NULL;
}
return parse_envelope_from_file(sentry__path_from_str_n(path, path_len));
}

#ifdef SENTRY_PLATFORM_WINDOWS
sentry_envelope_t *
sentry_envelope_read_from_filew(const wchar_t *path)
{
if (!path) {
return NULL;
}
return parse_envelope_from_file(sentry__path_from_wstr(path));
}

sentry_envelope_t *
sentry_envelope_read_from_filew_n(const wchar_t *path, size_t path_len)
{
if (!path || path_len == 0) {
return NULL;
}
return parse_envelope_from_file(sentry__path_from_wstr_n(path, path_len));
}
#endif

#ifdef SENTRY_UNITTEST
size_t
sentry__envelope_get_item_count(const sentry_envelope_t *envelope)
Expand Down
Loading
Loading