Skip to content

Commit 25efbb2

Browse files
committed
poc: custom http transport for sentry-native to eliminate curl
1 parent c5965ab commit 25efbb2

6 files changed

Lines changed: 84 additions & 19 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
### Features
66

77
- Rename MemoryInfo.AllocatedBytes to MemoryInfo.TotalAllocatedBytes ([#4243](https://github.com/getsentry/sentry-dotnet/pull/4243))
8+
- Replace libcurl with .NET HttpClient for sentry-native ([#4222](https://github.com/getsentry/sentry-dotnet/pull/4222))
89

910
## 5.9.0
1011

scripts/build-sentry-native.ps1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ try
6969
-D SENTRY_SDK_NAME=sentry.native.dotnet `
7070
-D SENTRY_BUILD_SHARED_LIBS=0 `
7171
-D SENTRY_BACKEND=inproc `
72+
-D SENTRY_TRANSPORT=none `
7273
$additionalArgs
7374

7475
cmake `

src/Sentry/Http/HttpTransportBase.cs

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -187,20 +187,8 @@ protected internal virtual HttpRequestMessage CreateRequest(Envelope envelope)
187187
throw new InvalidOperationException("The DSN is expected to be set at this point.");
188188
}
189189

190-
var dsn = Dsn.Parse(_options.Dsn);
191-
var authHeader =
192-
$"Sentry sentry_version={_options.SentryVersion}," +
193-
$"sentry_client={SdkVersion.Instance.Name}/{SdkVersion.Instance.Version}," +
194-
$"sentry_key={dsn.PublicKey}" +
195-
(dsn.SecretKey is { } secretKey ? $",sentry_secret={secretKey}" : null);
196-
197-
return new HttpRequestMessage
198-
{
199-
RequestUri = dsn.GetEnvelopeEndpointUri(),
200-
Method = HttpMethod.Post,
201-
Headers = { { "X-Sentry-Auth", authHeader } },
202-
Content = new EnvelopeHttpContent(envelope, _options.DiagnosticLogger, _clock)
203-
};
190+
var content = new EnvelopeHttpContent(envelope, _options.DiagnosticLogger, _clock);
191+
return _options.CreateHttpRequest(content);
204192
}
205193

206194
/// <summary>

src/Sentry/Platforms/Native/CFunctions.cs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,14 @@ public static bool Init(SentryOptions options)
139139
}
140140
}
141141

142+
unsafe
143+
{
144+
var cTransport = sentry_transport_new(&nativeTransport);
145+
sentry_transport_set_state(cTransport, GCHandle.ToIntPtr(GCHandle.Alloc(options)));
146+
sentry_transport_set_free_func(cTransport, &nativeTransportFree);
147+
sentry_options_set_transport(cOptions, cTransport);
148+
}
149+
142150
options.DiagnosticLogger?.LogDebug("Initializing sentry native");
143151
return 0 == sentry_init(cOptions);
144152
}
@@ -364,6 +372,61 @@ internal struct sentry_value_t
364372
[DllImport("sentry-native")]
365373
private static extern void sentry_options_set_auto_session_tracking(IntPtr options, int debug);
366374

375+
[DllImport("sentry-native")]
376+
private static extern void sentry_options_set_transport(IntPtr options, IntPtr transport);
377+
378+
[DllImport("sentry-native")]
379+
private static extern unsafe IntPtr sentry_transport_new(delegate* unmanaged/*[Cdecl]*/<IntPtr, IntPtr, void> sendFunc);
380+
381+
[DllImport("sentry-native")]
382+
private static extern void sentry_transport_set_state(IntPtr transport, IntPtr state);
383+
384+
[DllImport("sentry-native")]
385+
private static extern unsafe void sentry_transport_set_free_func(IntPtr transport, delegate* unmanaged/*[Cdecl]*/<IntPtr, void> freeFunc);
386+
387+
[DllImport("sentry-native")]
388+
private static extern IntPtr sentry_envelope_serialize(IntPtr envelope, out UIntPtr sizeOut);
389+
390+
[DllImport("sentry-native")]
391+
private static extern void sentry_envelope_free(IntPtr envelope);
392+
393+
[DllImport("sentry-native")]
394+
private static extern void sentry_free(IntPtr ptr);
395+
396+
[UnmanagedCallersOnly]
397+
private static void nativeTransport(IntPtr envelope, IntPtr state)
398+
{
399+
try
400+
{
401+
var options = GCHandle.FromIntPtr(state).Target as SentryOptions;
402+
if (options is not null)
403+
{
404+
var data = sentry_envelope_serialize(envelope, out var size);
405+
var content = new StringContent(Marshal.PtrToStringAnsi(data, (int)size));
406+
sentry_free(data);
407+
408+
using var client = options.GetHttpClient();
409+
using var request = options.CreateHttpRequest(content);
410+
client.SendAsync(request).GetAwaiter().GetResult();
411+
}
412+
}
413+
catch
414+
{
415+
// never allow an exception back to native code - it would crash the app
416+
}
417+
finally
418+
{
419+
sentry_envelope_free(envelope);
420+
}
421+
}
422+
423+
[UnmanagedCallersOnly]
424+
private static void nativeTransportFree(IntPtr state)
425+
{
426+
var handle = GCHandle.FromIntPtr(state);
427+
handle.Free();
428+
}
429+
367430
[DllImport("sentry-native")]
368431
private static extern unsafe void sentry_options_set_logger(IntPtr options, delegate* unmanaged/*[Cdecl]*/<int, IntPtr, IntPtr, IntPtr, void> logger, IntPtr userData);
369432

src/Sentry/Platforms/Native/buildTransitive/Sentry.Native.targets

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@
3636
<ItemGroup Condition="'$(FrameworkSupportsNative)' == 'true' and ('$(RuntimeIdentifier)' == 'linux-x64' or '$(RuntimeIdentifier)' == 'linux-arm64')">
3737
<DirectPInvoke Include="sentry-native" />
3838
<NativeLibrary Include="$(MSBuildThisFileDirectory)..\sentry-native\$(RuntimeIdentifier)\libsentry-native.a" />
39-
<!-- See: https://github.com/dotnet/runtime/issues/97414 -->
40-
<NativeSystemLibrary Include="curl" />
4139
</ItemGroup>
4240

4341
<ItemGroup Condition="'$(FrameworkSupportsNative)' == 'true' and '$(RuntimeIdentifier)' == 'linux-musl-x64'">
@@ -46,13 +44,10 @@
4644
<LinkerArg Include="-Wl,-Bstatic -Wl,--whole-archive -lunwind -Wl,--no-whole-archive -Wl,-Bdynamic" />
4745
<NativeSystemLibrary Include="lzma" />
4846
<NativeLibrary Include="$(MSBuildThisFileDirectory)..\sentry-native\linux-musl-x64\libsentry-native.a" />
49-
<!-- See: https://github.com/dotnet/runtime/issues/97414 -->
50-
<NativeSystemLibrary Include="curl" />
5147
</ItemGroup>
5248

5349
<ItemGroup Condition="'$(FrameworkSupportsNative)' == 'true' and ('$(RuntimeIdentifier)' == 'osx-x64' or '$(RuntimeIdentifier)' == 'osx-arm64')">
5450
<DirectPInvoke Include="sentry-native" />
5551
<NativeLibrary Include="$(MSBuildThisFileDirectory)..\sentry-native\osx\libsentry-native.a" />
56-
<NativeSystemLibrary Include="curl" />
5752
</ItemGroup>
5853
</Project>

src/Sentry/SentryOptions.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,23 @@ internal HttpClient GetHttpClient()
245245
return factory.Create(this);
246246
}
247247

248+
internal HttpRequestMessage CreateHttpRequest(HttpContent content)
249+
{
250+
var authHeader =
251+
$"Sentry sentry_version={SentryVersion}," +
252+
$"sentry_client={SdkVersion.Instance.Name}/{SdkVersion.Instance.Version}," +
253+
$"sentry_key={ParsedDsn.PublicKey}" +
254+
(ParsedDsn.SecretKey is { } secretKey ? $",sentry_secret={secretKey}" : null);
255+
256+
return new HttpRequestMessage
257+
{
258+
RequestUri = ParsedDsn.GetEnvelopeEndpointUri(),
259+
Method = HttpMethod.Post,
260+
Headers = { { "X-Sentry-Auth", authHeader } },
261+
Content = content
262+
};
263+
}
264+
248265
/// <summary>
249266
/// Scope state processor.
250267
/// </summary>

0 commit comments

Comments
 (0)