From 5112a047e45b94fb09bbfde14d3e196ad970f166 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 22 Jul 2024 16:33:29 +0200 Subject: [PATCH 01/34] string based proxy config --- dart/lib/src/http_client/io_proxy_client.dart | 18 ++++++++++ dart/lib/src/http_client/proxy_client.dart | 12 +++++++ dart/lib/src/sentry_options.dart | 4 +++ dart/lib/src/transport/http_transport.dart | 8 +++-- .../transport/io_http_transport_test.dart | 36 +++++++++++++++++++ 5 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 dart/lib/src/http_client/io_proxy_client.dart create mode 100644 dart/lib/src/http_client/proxy_client.dart create mode 100644 dart/test/transport/io_http_transport_test.dart diff --git a/dart/lib/src/http_client/io_proxy_client.dart b/dart/lib/src/http_client/io_proxy_client.dart new file mode 100644 index 0000000000..e6cf822671 --- /dev/null +++ b/dart/lib/src/http_client/io_proxy_client.dart @@ -0,0 +1,18 @@ +import 'dart:io'; + +import 'package:http/http.dart'; +import 'package:http/io_client.dart'; + +import '../protocol.dart'; +import '../sentry_options.dart'; + +Client proxyClient(String httpProxy, SentryOptions options) { + options.logger( + SentryLevel.info, + "Setting proxy '$httpProxy'", + ); + final httpClient = HttpClient(); + httpClient.findProxy = (url) => httpProxy; + final ioClient = IOClient(httpClient); + return ioClient; +} diff --git a/dart/lib/src/http_client/proxy_client.dart b/dart/lib/src/http_client/proxy_client.dart new file mode 100644 index 0000000000..af0250d792 --- /dev/null +++ b/dart/lib/src/http_client/proxy_client.dart @@ -0,0 +1,12 @@ +import 'package:http/http.dart'; + +import '../protocol.dart'; +import '../sentry_options.dart'; + +Client proxyClient(String httpProxy, SentryOptions options) { + options.logger( + SentryLevel.warning, + "Setting proxy '$httpProxy' only supported on io platforms.", + ); + return Client(); +} diff --git a/dart/lib/src/sentry_options.dart b/dart/lib/src/sentry_options.dart index f3f3c65a50..780f165eb3 100644 --- a/dart/lib/src/sentry_options.dart +++ b/dart/lib/src/sentry_options.dart @@ -443,6 +443,10 @@ class SentryOptions { /// ``` Spotlight spotlight = Spotlight(enabled: false); + /// Set an http proxy during options configuration with format "PROXY xxxx:xxxx" + /// This is only supported on io platforms without native integrations (dart, linux, windows). + String? httpProxy; + SentryOptions({this.dsn, PlatformChecker? checker}) { if (checker != null) { platformChecker = checker; diff --git a/dart/lib/src/transport/http_transport.dart b/dart/lib/src/transport/http_transport.dart index 90dd8949ce..ce6db4947a 100644 --- a/dart/lib/src/transport/http_transport.dart +++ b/dart/lib/src/transport/http_transport.dart @@ -11,6 +11,8 @@ import '../sentry_options.dart'; import '../sentry_envelope.dart'; import 'transport.dart'; import 'rate_limiter.dart'; +import '../http_client/proxy_client.dart' + if (dart.library.io) '../http_client/io_proxy_client.dart' as proxy; /// A transport is in charge of sending the event to the Sentry server. class HttpTransport implements Transport { @@ -21,10 +23,12 @@ class HttpTransport implements Transport { final HttpTransportRequestHandler _requestHandler; factory HttpTransport(SentryOptions options, RateLimiter rateLimiter) { - if (options.httpClient is NoOpClient) { + final httpProxy = options.httpProxy; + if (httpProxy != null) { + options.httpClient = proxy.proxyClient(httpProxy, options); + } else if (options.httpClient is NoOpClient) { options.httpClient = Client(); } - return HttpTransport._(options, rateLimiter); } diff --git a/dart/test/transport/io_http_transport_test.dart b/dart/test/transport/io_http_transport_test.dart new file mode 100644 index 0000000000..1191b4a5bd --- /dev/null +++ b/dart/test/transport/io_http_transport_test.dart @@ -0,0 +1,36 @@ +@TestOn('vm') +library dart_test; + +import 'package:http/io_client.dart' show IOClient; +import 'package:sentry/sentry.dart'; +import 'package:sentry/src/transport/http_transport.dart'; +import 'package:sentry/src/transport/rate_limiter.dart'; +import 'package:test/test.dart'; + +import '../mocks.dart'; + +void main() { + group('proxy', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + test('options.httpProxy should set client to IoClient', () async { + fixture.options.httpProxy = "PROXY xxxx:xxxx"; + fixture.getSut(); + + expect(fixture.options.httpClient is IOClient, true); + }); + }); +} + +class Fixture { + final options = SentryOptions(dsn: fakeDsn); + + HttpTransport getSut() { + final rateLimiter = RateLimiter(options); + return HttpTransport(options, rateLimiter); + } +} From 0eae983a27761e06113d617b02b68d740d865d67 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 22 Jul 2024 16:46:11 +0200 Subject: [PATCH 02/34] add Proxy class --- dart/lib/src/proxy.dart | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 dart/lib/src/proxy.dart diff --git a/dart/lib/src/proxy.dart b/dart/lib/src/proxy.dart new file mode 100644 index 0000000000..37f5489f8e --- /dev/null +++ b/dart/lib/src/proxy.dart @@ -0,0 +1,26 @@ +class Proxy { + final String? host; + final String? port; + final ProxyType? type; + final String? user; + final String? pass; + + Proxy({this.host, this.port, this.type, this.user, this.pass}); + + /// Produces a [Map] that can be serialized to JSON. + Map toJson() { + return { + if (host != null) 'host': host, + if (port != null) 'port': port, + if (type != null) 'type': type.toString().split('.').last.toUpperCase(), + if (user != null) 'user': user, + if (pass != null) 'pass': pass, + }; + } +} + +enum ProxyType { + direct, + http, + socks; +} From f65672db03632665808be1f7d563a4d0a9946ff4 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 23 Jul 2024 12:05:56 +0200 Subject: [PATCH 03/34] Use proxy class, Sync to android native --- dart/lib/sentry.dart | 2 + dart/lib/src/proxy.dart | 42 +++++++- dart/lib/src/sentry_options.dart | 6 +- dart/lib/src/transport/http_transport.dart | 9 +- dart/test/protocol/proxy_test.dart | 100 ++++++++++++++++++ .../transport/io_http_transport_test.dart | 4 +- .../kotlin/io/sentry/flutter/SentryFlutter.kt | 17 +++ .../io/sentry/flutter/SentryFlutterTest.kt | 14 +++ .../lib/src/native/sentry_native_channel.dart | 4 +- .../integrations/init_native_sdk_test.dart | 16 ++- 10 files changed, 199 insertions(+), 15 deletions(-) create mode 100644 dart/test/protocol/proxy_test.dart diff --git a/dart/lib/sentry.dart b/dart/lib/sentry.dart index fd88a49fc5..6b635a85b6 100644 --- a/dart/lib/sentry.dart +++ b/dart/lib/sentry.dart @@ -55,3 +55,5 @@ export 'src/sentry_span_operations.dart'; export 'src/utils.dart'; // spotlight debugging export 'src/spotlight.dart'; +// proxy +export 'src/proxy.dart'; diff --git a/dart/lib/src/proxy.dart b/dart/lib/src/proxy.dart index 37f5489f8e..50cfaa324a 100644 --- a/dart/lib/src/proxy.dart +++ b/dart/lib/src/proxy.dart @@ -1,22 +1,58 @@ class Proxy { + final ProxyType type; final String? host; final String? port; - final ProxyType? type; final String? user; final String? pass; - Proxy({this.host, this.port, this.type, this.user, this.pass}); + Proxy({required this.type, this.host, this.port, this.user, this.pass}); + + String toPacString() { + String type = 'DIRECT'; + switch (this.type) { + case ProxyType.direct: + return 'DIRECT'; + case ProxyType.http: + type = 'PROXY'; + break; + case ProxyType.socks: + type = 'SOCKS'; + break; + } + if (host != null && port != null) { + return '$type $host:$port'; + } else if (host != null) { + return '$type $host'; + } else { + return 'DIRECT'; + } + } /// Produces a [Map] that can be serialized to JSON. Map toJson() { return { if (host != null) 'host': host, if (port != null) 'port': port, - if (type != null) 'type': type.toString().split('.').last.toUpperCase(), + 'type': type.toString().split('.').last.toUpperCase(), if (user != null) 'user': user, if (pass != null) 'pass': pass, }; } + + Proxy copyWith({ + String? host, + String? port, + ProxyType? type, + String? user, + String? pass, + }) => + Proxy( + host: host ?? this.host, + port: port ?? this.port, + type: type ?? this.type, + user: user ?? this.user, + pass: pass ?? this.pass, + ); } enum ProxyType { diff --git a/dart/lib/src/sentry_options.dart b/dart/lib/src/sentry_options.dart index 780f165eb3..a5128f9afc 100644 --- a/dart/lib/src/sentry_options.dart +++ b/dart/lib/src/sentry_options.dart @@ -443,9 +443,9 @@ class SentryOptions { /// ``` Spotlight spotlight = Spotlight(enabled: false); - /// Set an http proxy during options configuration with format "PROXY xxxx:xxxx" - /// This is only supported on io platforms without native integrations (dart, linux, windows). - String? httpProxy; + /// Set proxy during options configuration. + /// This is supported on io platforms without native integrations (dart, linux, windows) and Android. + Proxy? proxy; SentryOptions({this.dsn, PlatformChecker? checker}) { if (checker != null) { diff --git a/dart/lib/src/transport/http_transport.dart b/dart/lib/src/transport/http_transport.dart index ce6db4947a..2adbd67b54 100644 --- a/dart/lib/src/transport/http_transport.dart +++ b/dart/lib/src/transport/http_transport.dart @@ -12,7 +12,7 @@ import '../sentry_envelope.dart'; import 'transport.dart'; import 'rate_limiter.dart'; import '../http_client/proxy_client.dart' - if (dart.library.io) '../http_client/io_proxy_client.dart' as proxy; + if (dart.library.io) '../http_client/io_proxy_client.dart' as proxyClient; /// A transport is in charge of sending the event to the Sentry server. class HttpTransport implements Transport { @@ -23,9 +23,10 @@ class HttpTransport implements Transport { final HttpTransportRequestHandler _requestHandler; factory HttpTransport(SentryOptions options, RateLimiter rateLimiter) { - final httpProxy = options.httpProxy; - if (httpProxy != null) { - options.httpClient = proxy.proxyClient(httpProxy, options); + final proxy = options.proxy; + if (proxy != null) { + options.httpClient = + proxyClient.proxyClient(proxy.toPacString(), options); } else if (options.httpClient is NoOpClient) { options.httpClient = Client(); } diff --git a/dart/test/protocol/proxy_test.dart b/dart/test/protocol/proxy_test.dart new file mode 100644 index 0000000000..15f4908b5b --- /dev/null +++ b/dart/test/protocol/proxy_test.dart @@ -0,0 +1,100 @@ +import 'package:collection/collection.dart'; +import 'package:sentry/sentry.dart'; +import 'package:test/test.dart'; + +void main() { + final proxy = Proxy( + host: 'localhost', + port: '8080', + type: ProxyType.http, + user: 'admin', + pass: '0000', + ); + + final proxyJson = { + 'host': 'localhost', + 'port': '8080', + 'type': 'HTTP', + 'user': 'admin', + 'pass': '0000', + }; + + group('toPacString', () { + test('returns "DIRECT" for ProxyType.direct', () { + Proxy proxy = Proxy(type: ProxyType.direct); + expect(proxy.toPacString(), equals('DIRECT')); + }); + + test('returns "PROXY host:port" for ProxyType.http with host and port', () { + Proxy proxy = + Proxy(type: ProxyType.http, host: 'localhost', port: '8080'); + expect(proxy.toPacString(), equals('PROXY localhost:8080')); + }); + + test('returns "PROXY host" for ProxyType.http with host only', () { + Proxy proxy = Proxy(type: ProxyType.http, host: 'localhost'); + expect(proxy.toPacString(), equals('PROXY localhost')); + }); + + test('returns "SOCKS host:port" for ProxyType.socks with host and port', + () { + Proxy proxy = + Proxy(type: ProxyType.socks, host: 'localhost', port: '1080'); + expect(proxy.toPacString(), equals('SOCKS localhost:1080')); + }); + + test('returns "SOCKS host" for ProxyType.socks with host only', () { + Proxy proxy = Proxy(type: ProxyType.socks, host: 'localhost'); + expect(proxy.toPacString(), equals('SOCKS localhost')); + }); + + test('falls back to "DIRECT" if http is missing host', () { + Proxy proxy = Proxy(type: ProxyType.http); + expect(proxy.toPacString(), equals('DIRECT')); + }); + + test('falls back to "DIRECT" if socks is missing host', () { + Proxy proxy = Proxy(type: ProxyType.socks); + expect(proxy.toPacString(), equals('DIRECT')); + }); + }); + + group('json', () { + test('toJson', () { + final json = proxy.toJson(); + + expect( + DeepCollectionEquality().equals(proxyJson, json), + true, + ); + }); + }); + + group('copyWith', () { + test('copyWith keeps unchanged', () { + final data = proxy; + + final copy = data.copyWith(); + + expect(data.toJson(), copy.toJson()); + }); + + test('copyWith takes new values', () { + final data = proxy; + + final copy = data.copyWith( + host: 'localhost-2', + port: '8000', + type: ProxyType.socks, + user: 'user', + pass: '1234', + ); + + expect('localhost-2', copy.host); + expect('8000', copy.port); + expect(ProxyType.socks, copy.type); + expect('user', copy.user); + expect('1234', copy.pass); + }); + }); +} diff --git a/dart/test/transport/io_http_transport_test.dart b/dart/test/transport/io_http_transport_test.dart index 1191b4a5bd..c6b1791fcf 100644 --- a/dart/test/transport/io_http_transport_test.dart +++ b/dart/test/transport/io_http_transport_test.dart @@ -18,9 +18,9 @@ void main() { }); test('options.httpProxy should set client to IoClient', () async { - fixture.options.httpProxy = "PROXY xxxx:xxxx"; + fixture.options.proxy = + Proxy(type: ProxyType.http, host: 'localhost', port: '8080'); fixture.getSut(); - expect(fixture.options.httpClient is IOClient, true); }); }); diff --git a/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt b/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt index c06a8b0dc2..97850cae55 100644 --- a/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt +++ b/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt @@ -1,10 +1,12 @@ package io.sentry.flutter import io.sentry.SentryLevel +import io.sentry.SentryOptions.Proxy import io.sentry.android.core.BuildConfig import io.sentry.android.core.SentryAndroidOptions import io.sentry.protocol.SdkVersion import java.util.Locale +import java.net.Proxy.Type; class SentryFlutter( private val androidSdk: String, @@ -119,6 +121,21 @@ class SentryFlutter( data.getIfNotNull("readTimeoutMillis") { options.readTimeoutMillis = it } + data.getIfNotNull>("proxy") { proxyJson -> + options.proxy = Proxy().apply { + host = proxyJson["host"] as? String + port = proxyJson["port"] as? String + (proxyJson["type"] as? String)?.let { + type = try { + Type.valueOf(it.uppercase()) + } catch (e: IllegalArgumentException) { + null + } + } + user = proxyJson["user"] as? String + pass = proxyJson["pass"] as? String + } + } } } diff --git a/flutter/android/src/test/kotlin/io/sentry/flutter/SentryFlutterTest.kt b/flutter/android/src/test/kotlin/io/sentry/flutter/SentryFlutterTest.kt index 724559bb76..0430d264d2 100644 --- a/flutter/android/src/test/kotlin/io/sentry/flutter/SentryFlutterTest.kt +++ b/flutter/android/src/test/kotlin/io/sentry/flutter/SentryFlutterTest.kt @@ -6,6 +6,7 @@ import io.sentry.android.core.SentryAndroidOptions import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test +import java.net.Proxy class SentryFlutterTest { private lateinit var fixture: Fixture @@ -60,6 +61,12 @@ class SentryFlutterTest { assertEquals(9006, fixture.options.connectionTimeoutMillis) assertEquals(9007, fixture.options.readTimeoutMillis) + + assertEquals("localhost", fixture.options.proxy?.host) + assertEquals("8080", fixture.options.proxy?.port) + assertEquals(Proxy.Type.HTTP, fixture.options.proxy?.type) + assertEquals("admin", fixture.options.proxy?.user) + assertEquals("0000", fixture.options.proxy?.pass) } @Test @@ -127,6 +134,13 @@ class Fixture { "enableAutoPerformanceTracing" to true, "connectionTimeoutMillis" to 9006, "readTimeoutMillis" to 9007, + "proxy" to mapOf( + "host" to "localhost", + "port" to "8080", + "type" to "http", // lowercase to check enum mapping + "user" to "admin", + "pass" to "0000", + ) ) fun getSut(): SentryFlutter { diff --git a/flutter/lib/src/native/sentry_native_channel.dart b/flutter/lib/src/native/sentry_native_channel.dart index 0a3b97820d..330d711dfa 100644 --- a/flutter/lib/src/native/sentry_native_channel.dart +++ b/flutter/lib/src/native/sentry_native_channel.dart @@ -64,8 +64,8 @@ class SentryNativeChannel 'enableAppHangTracking': options.enableAppHangTracking, 'connectionTimeoutMillis': options.connectionTimeout.inMilliseconds, 'readTimeoutMillis': options.readTimeout.inMilliseconds, - 'appHangTimeoutIntervalMillis': - options.appHangTimeoutInterval.inMilliseconds, + 'appHangTimeoutIntervalMillis': options.appHangTimeoutInterval.inMilliseconds, + if (options.proxy != null) 'proxy': options.proxy?.toJson(), }); } diff --git a/flutter/test/integrations/init_native_sdk_test.dart b/flutter/test/integrations/init_native_sdk_test.dart index 0dcf3af502..07427e6ea3 100644 --- a/flutter/test/integrations/init_native_sdk_test.dart +++ b/flutter/test/integrations/init_native_sdk_test.dart @@ -104,7 +104,14 @@ void main() { ..enableAppHangTracking = false ..connectionTimeout = Duration(milliseconds: 9001) ..readTimeout = Duration(milliseconds: 9002) - ..appHangTimeoutInterval = Duration(milliseconds: 9003); + ..appHangTimeoutInterval = Duration(milliseconds: 9003) + ..proxy = Proxy( + host: "localhost", + port: '8080', + type: ProxyType.http, + user: 'admin', + pass: '0000', + ); fixture.options.sdk.addIntegration('foo'); fixture.options.sdk.addPackage('bar', '1'); @@ -149,6 +156,13 @@ void main() { 'connectionTimeoutMillis': 9001, 'readTimeoutMillis': 9002, 'appHangTimeoutIntervalMillis': 9003, + 'proxy': { + 'host': 'localhost', + 'port': '8080', + 'type': 'HTTP', + 'user': 'admin', + 'pass': '0000', + } }); }); } From eac8ee644adfe1e6e6182b9da06d00c3f0e4c161 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 23 Jul 2024 14:21:16 +0200 Subject: [PATCH 04/34] test io client provider --- dart/lib/src/http_client/client_provider.dart | 13 + dart/lib/src/http_client/io_proxy_client.dart | 18 -- .../http_client/io_proxy_client_provider.dart | 64 +++++ dart/lib/src/http_client/proxy_client.dart | 12 - dart/lib/src/proxy.dart | 4 +- dart/lib/src/sentry_options.dart | 12 +- dart/lib/src/transport/http_transport.dart | 12 +- .../http_client/io_client_provider_test.dart | 266 ++++++++++++++++++ dart/test/protocol/proxy_test.dart | 16 +- .../transport/io_http_transport_test.dart | 36 --- 10 files changed, 366 insertions(+), 87 deletions(-) create mode 100644 dart/lib/src/http_client/client_provider.dart delete mode 100644 dart/lib/src/http_client/io_proxy_client.dart create mode 100644 dart/lib/src/http_client/io_proxy_client_provider.dart delete mode 100644 dart/lib/src/http_client/proxy_client.dart create mode 100644 dart/test/http_client/io_client_provider_test.dart delete mode 100644 dart/test/transport/io_http_transport_test.dart diff --git a/dart/lib/src/http_client/client_provider.dart b/dart/lib/src/http_client/client_provider.dart new file mode 100644 index 0000000000..25fcfe6b47 --- /dev/null +++ b/dart/lib/src/http_client/client_provider.dart @@ -0,0 +1,13 @@ +import 'package:http/http.dart'; + +import '../sentry_options.dart'; + +ClientProvider getClientProvider() { + return ClientProvider(); +} + +class ClientProvider { + Client getClient(SentryOptions options) { + return Client(); + } +} diff --git a/dart/lib/src/http_client/io_proxy_client.dart b/dart/lib/src/http_client/io_proxy_client.dart deleted file mode 100644 index e6cf822671..0000000000 --- a/dart/lib/src/http_client/io_proxy_client.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'dart:io'; - -import 'package:http/http.dart'; -import 'package:http/io_client.dart'; - -import '../protocol.dart'; -import '../sentry_options.dart'; - -Client proxyClient(String httpProxy, SentryOptions options) { - options.logger( - SentryLevel.info, - "Setting proxy '$httpProxy'", - ); - final httpClient = HttpClient(); - httpClient.findProxy = (url) => httpProxy; - final ioClient = IOClient(httpClient); - return ioClient; -} diff --git a/dart/lib/src/http_client/io_proxy_client_provider.dart b/dart/lib/src/http_client/io_proxy_client_provider.dart new file mode 100644 index 0000000000..4f56f1a94a --- /dev/null +++ b/dart/lib/src/http_client/io_proxy_client_provider.dart @@ -0,0 +1,64 @@ +import 'dart:io'; + +import 'package:http/http.dart'; +import 'package:http/io_client.dart'; + +import '../protocol.dart'; +import '../proxy.dart'; +import '../sentry_options.dart'; +import 'client_provider.dart'; + +ClientProvider getClientProvider() { + return IoClientProvider( + () { + return HttpClient(); + }, + (user, pass) { + return HttpClientBasicCredentials(user, pass); + }, + ); +} + +class IoClientProvider implements ClientProvider { + final HttpClient Function() _httpClient; + final HttpClientCredentials Function(String, String) _httpClientCredentials; + + IoClientProvider(this._httpClient, this._httpClientCredentials); + + @override + Client getClient(SentryOptions options) { + final proxy = options.proxy; + if (proxy == null) { + return Client(); + } + final pac = proxy.toPacString(); + if (proxy.type == ProxyType.socks) { + options.logger( + SentryLevel.warning, + "Setting proxy '$pac' is not supported.", + ); + return Client(); + } + options.logger( + SentryLevel.info, + "Setting proxy '$pac'", + ); + final httpClient = _httpClient(); + httpClient.findProxy = (url) => pac; + + final host = proxy.host; + final port = proxy.port; + final user = proxy.user; + final pass = proxy.pass; + + if (host != null && port != null && user != null && pass != null) { + httpClient.addProxyCredentials( + host, + port, + '', + _httpClientCredentials(user, pass), + ); + } + return IOClient(httpClient); + } +} diff --git a/dart/lib/src/http_client/proxy_client.dart b/dart/lib/src/http_client/proxy_client.dart deleted file mode 100644 index af0250d792..0000000000 --- a/dart/lib/src/http_client/proxy_client.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:http/http.dart'; - -import '../protocol.dart'; -import '../sentry_options.dart'; - -Client proxyClient(String httpProxy, SentryOptions options) { - options.logger( - SentryLevel.warning, - "Setting proxy '$httpProxy' only supported on io platforms.", - ); - return Client(); -} diff --git a/dart/lib/src/proxy.dart b/dart/lib/src/proxy.dart index 50cfaa324a..9f0393f25e 100644 --- a/dart/lib/src/proxy.dart +++ b/dart/lib/src/proxy.dart @@ -1,7 +1,7 @@ class Proxy { final ProxyType type; final String? host; - final String? port; + final int? port; final String? user; final String? pass; @@ -41,7 +41,7 @@ class Proxy { Proxy copyWith({ String? host, - String? port, + int? port, ProxyType? type, String? user, String? pass, diff --git a/dart/lib/src/sentry_options.dart b/dart/lib/src/sentry_options.dart index a5128f9afc..7d3608393b 100644 --- a/dart/lib/src/sentry_options.dart +++ b/dart/lib/src/sentry_options.dart @@ -443,8 +443,16 @@ class SentryOptions { /// ``` Spotlight spotlight = Spotlight(enabled: false); - /// Set proxy during options configuration. - /// This is supported on io platforms without native integrations (dart, linux, windows) and Android. + /// Configure a proxy to use for SDK API calls. + /// + /// On io platforms (dart, linux, windows), this will use an 'HTTPClient' for + /// http communication. A http proxy will be set in returned for + /// 'HttpClient.findProxy' in the form 'PROXY :'. + /// When setting 'user' and 'pass', the 'HttpClient.addProxyCredentials' + /// method will be called wit empty 'realm'. + /// + /// On Android, the proxy settings are handled by the native SDK. + /// iOS and macOS native SDKs do not support proxy settings. Proxy? proxy; SentryOptions({this.dsn, PlatformChecker? checker}) { diff --git a/dart/lib/src/transport/http_transport.dart b/dart/lib/src/transport/http_transport.dart index 2adbd67b54..c441e238bb 100644 --- a/dart/lib/src/transport/http_transport.dart +++ b/dart/lib/src/transport/http_transport.dart @@ -11,8 +11,8 @@ import '../sentry_options.dart'; import '../sentry_envelope.dart'; import 'transport.dart'; import 'rate_limiter.dart'; -import '../http_client/proxy_client.dart' - if (dart.library.io) '../http_client/io_proxy_client.dart' as proxyClient; +import '../http_client/client_provider.dart' + if (dart.library.io) '../http_client/io_proxy_client_provider.dart'; /// A transport is in charge of sending the event to the Sentry server. class HttpTransport implements Transport { @@ -23,12 +23,8 @@ class HttpTransport implements Transport { final HttpTransportRequestHandler _requestHandler; factory HttpTransport(SentryOptions options, RateLimiter rateLimiter) { - final proxy = options.proxy; - if (proxy != null) { - options.httpClient = - proxyClient.proxyClient(proxy.toPacString(), options); - } else if (options.httpClient is NoOpClient) { - options.httpClient = Client(); + if (options.httpClient is NoOpClient) { + options.httpClient = getClientProvider().getClient(options); } return HttpTransport._(options, rateLimiter); } diff --git a/dart/test/http_client/io_client_provider_test.dart b/dart/test/http_client/io_client_provider_test.dart new file mode 100644 index 0000000000..caca66d5d5 --- /dev/null +++ b/dart/test/http_client/io_client_provider_test.dart @@ -0,0 +1,266 @@ +@TestOn('vm') +library dart_test; + +import 'dart:io'; + +import 'package:sentry/sentry.dart'; +import 'package:sentry/src/http_client/io_proxy_client_provider.dart'; +import 'package:test/test.dart'; + +import '../mocks.dart'; + +void main() { + group('getClient', () { + late Fixture fixture; + + setUp(() { + fixture = Fixture(); + }); + + test('http proxy should call findProxyResult', () async { + fixture.options.proxy = Proxy( + type: ProxyType.http, + host: 'localhost', + port: 8080, + ); + + final sut = fixture.getSut(); + sut.getClient(fixture.options); + + expect(fixture.mockHttpClient.findProxyResult, + equals(fixture.options.proxy?.toPacString())); + }); + + test('direct proxy should call findProxyResult', () async { + fixture.options.proxy = Proxy(type: ProxyType.direct); + + final sut = fixture.getSut(); + sut.getClient(fixture.options); + + expect(fixture.mockHttpClient.findProxyResult, + equals(fixture.options.proxy?.toPacString())); + }); + + test('socks proxy should not call findProxyResult', () async { + fixture.options.proxy = + Proxy(type: ProxyType.socks, host: 'localhost', port: 8080); + + final sut = fixture.getSut(); + sut.getClient(fixture.options); + + expect(fixture.mockHttpClient.findProxyResult, isNull); + }); + + test('authenticated proxy http should call addProxyCredentials', () async { + fixture.options.proxy = Proxy( + type: ProxyType.http, + host: 'localhost', + port: 8080, + user: 'admin', + pass: '0000', + ); + + final sut = fixture.getSut(); + + sut.getClient(fixture.options); + + expect(fixture.mockHttpClient.addProxyCredentialsHost, + fixture.options.proxy?.host); + expect(fixture.mockHttpClient.addProxyCredentialsPort, + fixture.options.proxy?.port); + expect(fixture.mockHttpClient.addProxyCredentialsRealm, ''); + expect(fixture.mockUser, fixture.options.proxy?.user); + expect(fixture.mockPass, fixture.options.proxy?.pass); + }); + }); +} + +class Fixture { + final options = SentryOptions(dsn: fakeDsn); + final mockHttpClient = MockHttpClient(); + + String? mockUser; + String? mockPass; + + IoClientProvider getSut() { + return IoClientProvider( + () { + return mockHttpClient; + }, + (user, pass) { + mockUser = user; + mockPass = pass; + return HttpClientBasicCredentials(user, pass); + }, + ); + } +} + +class MockHttpClient implements HttpClient { + @override + bool autoUncompress = false; + + @override + Duration? connectionTimeout; + + @override + Duration idleTimeout = Duration(seconds: 1); + + @override + int? maxConnectionsPerHost; + + @override + String? userAgent; + + @override + void addCredentials( + Uri url, String realm, HttpClientCredentials credentials) { + // TODO: implement addCredentials + } + + String? addProxyCredentialsHost; + int? addProxyCredentialsPort; + String? addProxyCredentialsRealm; + HttpClientBasicCredentials? addProxyCredentialsBasic; + + @override + void addProxyCredentials( + String host, int port, String realm, HttpClientCredentials credentials) { + addProxyCredentialsHost = host; + addProxyCredentialsPort = port; + addProxyCredentialsRealm = realm; + if (credentials is HttpClientBasicCredentials) { + addProxyCredentialsBasic = credentials; + } + } + + @override + set authenticate( + Future Function(Uri url, String scheme, String? realm)? f) { + // TODO: implement authenticate + } + + @override + set authenticateProxy( + Future Function( + String host, int port, String scheme, String? realm)? + f) { + // TODO: implement authenticateProxy + } + + @override + set badCertificateCallback( + bool Function(X509Certificate cert, String host, int port)? callback) { + // TODO: implement badCertificateCallback + } + + @override + void close({bool force = false}) { + // TODO: implement close + } + + @override + set connectionFactory( + Future> Function( + Uri url, String? proxyHost, int? proxyPort)? + f) { + // TODO: implement connectionFactory + } + + @override + Future delete(String host, int port, String path) { + // TODO: implement delete + throw UnimplementedError(); + } + + @override + Future deleteUrl(Uri url) { + // TODO: implement deleteUrl + throw UnimplementedError(); + } + + String? findProxyResult; + + @override + set findProxy(String Function(Uri url)? f) { + findProxyResult = f!(Uri(scheme: "http", host: "localhost", port: 8080)); + } + + @override + Future get(String host, int port, String path) { + // TODO: implement get + throw UnimplementedError(); + } + + @override + Future getUrl(Uri url) { + // TODO: implement getUrl + throw UnimplementedError(); + } + + @override + Future head(String host, int port, String path) { + // TODO: implement head + throw UnimplementedError(); + } + + @override + Future headUrl(Uri url) { + // TODO: implement headUrl + throw UnimplementedError(); + } + + @override + set keyLog(Function(String line)? callback) { + // TODO: implement keyLog + } + + @override + Future open( + String method, String host, int port, String path) { + // TODO: implement open + throw UnimplementedError(); + } + + @override + Future openUrl(String method, Uri url) { + // TODO: implement openUrl + throw UnimplementedError(); + } + + @override + Future patch(String host, int port, String path) { + // TODO: implement patch + throw UnimplementedError(); + } + + @override + Future patchUrl(Uri url) { + // TODO: implement patchUrl + throw UnimplementedError(); + } + + @override + Future post(String host, int port, String path) { + // TODO: implement post + throw UnimplementedError(); + } + + @override + Future postUrl(Uri url) { + // TODO: implement postUrl + throw UnimplementedError(); + } + + @override + Future put(String host, int port, String path) { + // TODO: implement put + throw UnimplementedError(); + } + + @override + Future putUrl(Uri url) { + // TODO: implement putUrl + throw UnimplementedError(); + } +} diff --git a/dart/test/protocol/proxy_test.dart b/dart/test/protocol/proxy_test.dart index 15f4908b5b..021b13990e 100644 --- a/dart/test/protocol/proxy_test.dart +++ b/dart/test/protocol/proxy_test.dart @@ -5,7 +5,7 @@ import 'package:test/test.dart'; void main() { final proxy = Proxy( host: 'localhost', - port: '8080', + port: 8080, type: ProxyType.http, user: 'admin', pass: '0000', @@ -13,7 +13,7 @@ void main() { final proxyJson = { 'host': 'localhost', - 'port': '8080', + 'port': 8080, 'type': 'HTTP', 'user': 'admin', 'pass': '0000', @@ -26,8 +26,7 @@ void main() { }); test('returns "PROXY host:port" for ProxyType.http with host and port', () { - Proxy proxy = - Proxy(type: ProxyType.http, host: 'localhost', port: '8080'); + Proxy proxy = Proxy(type: ProxyType.http, host: 'localhost', port: 8080); expect(proxy.toPacString(), equals('PROXY localhost:8080')); }); @@ -38,9 +37,8 @@ void main() { test('returns "SOCKS host:port" for ProxyType.socks with host and port', () { - Proxy proxy = - Proxy(type: ProxyType.socks, host: 'localhost', port: '1080'); - expect(proxy.toPacString(), equals('SOCKS localhost:1080')); + Proxy proxy = Proxy(type: ProxyType.socks, host: 'localhost', port: 8080); + expect(proxy.toPacString(), equals('SOCKS localhost:8080')); }); test('returns "SOCKS host" for ProxyType.socks with host only', () { @@ -84,14 +82,14 @@ void main() { final copy = data.copyWith( host: 'localhost-2', - port: '8000', + port: 9001, type: ProxyType.socks, user: 'user', pass: '1234', ); expect('localhost-2', copy.host); - expect('8000', copy.port); + expect(9001, copy.port); expect(ProxyType.socks, copy.type); expect('user', copy.user); expect('1234', copy.pass); diff --git a/dart/test/transport/io_http_transport_test.dart b/dart/test/transport/io_http_transport_test.dart deleted file mode 100644 index c6b1791fcf..0000000000 --- a/dart/test/transport/io_http_transport_test.dart +++ /dev/null @@ -1,36 +0,0 @@ -@TestOn('vm') -library dart_test; - -import 'package:http/io_client.dart' show IOClient; -import 'package:sentry/sentry.dart'; -import 'package:sentry/src/transport/http_transport.dart'; -import 'package:sentry/src/transport/rate_limiter.dart'; -import 'package:test/test.dart'; - -import '../mocks.dart'; - -void main() { - group('proxy', () { - late Fixture fixture; - - setUp(() { - fixture = Fixture(); - }); - - test('options.httpProxy should set client to IoClient', () async { - fixture.options.proxy = - Proxy(type: ProxyType.http, host: 'localhost', port: '8080'); - fixture.getSut(); - expect(fixture.options.httpClient is IOClient, true); - }); - }); -} - -class Fixture { - final options = SentryOptions(dsn: fakeDsn); - - HttpTransport getSut() { - final rateLimiter = RateLimiter(options); - return HttpTransport(options, rateLimiter); - } -} From 8ec28441b2b99985f3b8a3d41a9ededf794bd1c1 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 23 Jul 2024 14:25:10 +0200 Subject: [PATCH 05/34] rename file --- .../{io_proxy_client_provider.dart => io_client_provider.dart} | 0 dart/lib/src/transport/http_transport.dart | 2 +- dart/test/http_client/io_client_provider_test.dart | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename dart/lib/src/http_client/{io_proxy_client_provider.dart => io_client_provider.dart} (100%) diff --git a/dart/lib/src/http_client/io_proxy_client_provider.dart b/dart/lib/src/http_client/io_client_provider.dart similarity index 100% rename from dart/lib/src/http_client/io_proxy_client_provider.dart rename to dart/lib/src/http_client/io_client_provider.dart diff --git a/dart/lib/src/transport/http_transport.dart b/dart/lib/src/transport/http_transport.dart index c441e238bb..68950948a2 100644 --- a/dart/lib/src/transport/http_transport.dart +++ b/dart/lib/src/transport/http_transport.dart @@ -12,7 +12,7 @@ import '../sentry_envelope.dart'; import 'transport.dart'; import 'rate_limiter.dart'; import '../http_client/client_provider.dart' - if (dart.library.io) '../http_client/io_proxy_client_provider.dart'; + if (dart.library.io) '../http_client/io_client_provider.dart'; /// A transport is in charge of sending the event to the Sentry server. class HttpTransport implements Transport { diff --git a/dart/test/http_client/io_client_provider_test.dart b/dart/test/http_client/io_client_provider_test.dart index caca66d5d5..b802c5bf3c 100644 --- a/dart/test/http_client/io_client_provider_test.dart +++ b/dart/test/http_client/io_client_provider_test.dart @@ -4,7 +4,7 @@ library dart_test; import 'dart:io'; import 'package:sentry/sentry.dart'; -import 'package:sentry/src/http_client/io_proxy_client_provider.dart'; +import 'package:sentry/src/http_client/io_client_provider.dart'; import 'package:test/test.dart'; import '../mocks.dart'; From 301fd22bd6520d0b80724c580da1839711054eb5 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 23 Jul 2024 14:28:00 +0200 Subject: [PATCH 06/34] update docs --- dart/lib/src/sentry_options.dart | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dart/lib/src/sentry_options.dart b/dart/lib/src/sentry_options.dart index 7d3608393b..60729b2460 100644 --- a/dart/lib/src/sentry_options.dart +++ b/dart/lib/src/sentry_options.dart @@ -445,9 +445,10 @@ class SentryOptions { /// Configure a proxy to use for SDK API calls. /// - /// On io platforms (dart, linux, windows), this will use an 'HTTPClient' for - /// http communication. A http proxy will be set in returned for - /// 'HttpClient.findProxy' in the form 'PROXY :'. + /// On io platforms without native SDKs (dart, linux, windows), this will use + /// an 'IOClient' with inner 'HTTPClient' for http communication. + /// A http proxy will be set in returned for 'HttpClient.findProxy' in the + /// form 'PROXY :'. /// When setting 'user' and 'pass', the 'HttpClient.addProxyCredentials' /// method will be called wit empty 'realm'. /// From 1941696450047e4a98745855947f7a9514957d3b Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 23 Jul 2024 14:29:27 +0200 Subject: [PATCH 07/34] fix port parsing --- .../src/main/kotlin/io/sentry/flutter/SentryFlutter.kt | 4 +++- .../src/test/kotlin/io/sentry/flutter/SentryFlutterTest.kt | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt b/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt index 97850cae55..b409190e9d 100644 --- a/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt +++ b/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt @@ -124,7 +124,9 @@ class SentryFlutter( data.getIfNotNull>("proxy") { proxyJson -> options.proxy = Proxy().apply { host = proxyJson["host"] as? String - port = proxyJson["port"] as? String + port = (proxyJson["port"] as? Int)?.let { + "$it" + } (proxyJson["type"] as? String)?.let { type = try { Type.valueOf(it.uppercase()) diff --git a/flutter/android/src/test/kotlin/io/sentry/flutter/SentryFlutterTest.kt b/flutter/android/src/test/kotlin/io/sentry/flutter/SentryFlutterTest.kt index 0430d264d2..de3d69d60a 100644 --- a/flutter/android/src/test/kotlin/io/sentry/flutter/SentryFlutterTest.kt +++ b/flutter/android/src/test/kotlin/io/sentry/flutter/SentryFlutterTest.kt @@ -136,7 +136,7 @@ class Fixture { "readTimeoutMillis" to 9007, "proxy" to mapOf( "host" to "localhost", - "port" to "8080", + "port" to 8080, "type" to "http", // lowercase to check enum mapping "user" to "admin", "pass" to "0000", From 8dc9f479c3ef984bb3c1c4420567239be266645d Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 23 Jul 2024 14:32:19 +0200 Subject: [PATCH 08/34] Use client provider in SpotlightHttpTransport --- dart/lib/src/transport/spotlight_http_transport.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dart/lib/src/transport/spotlight_http_transport.dart b/dart/lib/src/transport/spotlight_http_transport.dart index f51e77d478..344b51a02f 100644 --- a/dart/lib/src/transport/spotlight_http_transport.dart +++ b/dart/lib/src/transport/spotlight_http_transport.dart @@ -4,6 +4,8 @@ import 'http_transport_request_handler.dart'; import '../../sentry.dart'; import '../noop_client.dart'; +import '../http_client/client_provider.dart' +if (dart.library.io) '../http_client/io_client_provider.dart'; /// Spotlight HTTP transport decorator that sends Sentry envelopes to both Sentry and Spotlight. class SpotlightHttpTransport extends Transport { @@ -13,7 +15,7 @@ class SpotlightHttpTransport extends Transport { factory SpotlightHttpTransport(SentryOptions options, Transport transport) { if (options.httpClient is NoOpClient) { - options.httpClient = Client(); + options.httpClient = getClientProvider().getClient(options); } return SpotlightHttpTransport._(options, transport); } From 488007a6ac7ba1c1425a88170dd626982cd50a75 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 23 Jul 2024 14:34:22 +0200 Subject: [PATCH 09/34] check if HttpClientBasicCredentials are set --- dart/test/http_client/io_client_provider_test.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/dart/test/http_client/io_client_provider_test.dart b/dart/test/http_client/io_client_provider_test.dart index b802c5bf3c..d033c79e05 100644 --- a/dart/test/http_client/io_client_provider_test.dart +++ b/dart/test/http_client/io_client_provider_test.dart @@ -71,6 +71,7 @@ void main() { expect(fixture.mockHttpClient.addProxyCredentialsRealm, ''); expect(fixture.mockUser, fixture.options.proxy?.user); expect(fixture.mockPass, fixture.options.proxy?.pass); + expect(fixture.mockHttpClient.addProxyCredentialsBasic, isNotNull); }); }); } From 56997b9025e6dbe502e8840f3cfa8b44a43dedce Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 23 Jul 2024 14:35:29 +0200 Subject: [PATCH 10/34] fix init native sdk tests --- flutter/test/integrations/init_native_sdk_test.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flutter/test/integrations/init_native_sdk_test.dart b/flutter/test/integrations/init_native_sdk_test.dart index 07427e6ea3..54789606cc 100644 --- a/flutter/test/integrations/init_native_sdk_test.dart +++ b/flutter/test/integrations/init_native_sdk_test.dart @@ -107,7 +107,7 @@ void main() { ..appHangTimeoutInterval = Duration(milliseconds: 9003) ..proxy = Proxy( host: "localhost", - port: '8080', + port: 8080, type: ProxyType.http, user: 'admin', pass: '0000', @@ -158,7 +158,7 @@ void main() { 'appHangTimeoutIntervalMillis': 9003, 'proxy': { 'host': 'localhost', - 'port': '8080', + 'port': 8080, 'type': 'HTTP', 'user': 'admin', 'pass': '0000', From 101f8fa0ff3e64fd00edd84fba28aa237b0c79f9 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 23 Jul 2024 14:46:42 +0200 Subject: [PATCH 11/34] add cl entry and format kotlin code --- CHANGELOG.md | 4 +++ .../kotlin/io/sentry/flutter/SentryFlutter.kt | 29 ++++++++++--------- .../io/sentry/flutter/SentryFlutterTest.kt | 15 +++++----- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e8f190369..5d4844fd6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Features + +- Add proxy support ([#2192](https://github.com/getsentry/sentry-dart/pull/2192)) + ### Fixes - Disable sff & frame delay detection on web, linux and windows ([#2182](https://github.com/getsentry/sentry-dart/pull/2182)) diff --git a/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt b/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt index b409190e9d..a17e0ab965 100644 --- a/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt +++ b/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt @@ -6,7 +6,7 @@ import io.sentry.android.core.BuildConfig import io.sentry.android.core.SentryAndroidOptions import io.sentry.protocol.SdkVersion import java.util.Locale -import java.net.Proxy.Type; +import java.net.Proxy.Type class SentryFlutter( private val androidSdk: String, @@ -122,21 +122,22 @@ class SentryFlutter( options.readTimeoutMillis = it } data.getIfNotNull>("proxy") { proxyJson -> - options.proxy = Proxy().apply { - host = proxyJson["host"] as? String - port = (proxyJson["port"] as? Int)?.let { - "$it" - } - (proxyJson["type"] as? String)?.let { - type = try { - Type.valueOf(it.uppercase()) - } catch (e: IllegalArgumentException) { - null + options.proxy = Proxy() + .apply { + host = proxyJson["host"] as? String + port = (proxyJson["port"] as? Int)?.let { + "$it" + } + (proxyJson["type"] as? String)?.let { + type = try { + Type.valueOf(it.uppercase()) + } catch (e: IllegalArgumentException) { + null + } } + user = proxyJson["user"] as? String + pass = proxyJson["pass"] as? String } - user = proxyJson["user"] as? String - pass = proxyJson["pass"] as? String - } } } } diff --git a/flutter/android/src/test/kotlin/io/sentry/flutter/SentryFlutterTest.kt b/flutter/android/src/test/kotlin/io/sentry/flutter/SentryFlutterTest.kt index de3d69d60a..7fba2192c5 100644 --- a/flutter/android/src/test/kotlin/io/sentry/flutter/SentryFlutterTest.kt +++ b/flutter/android/src/test/kotlin/io/sentry/flutter/SentryFlutterTest.kt @@ -134,13 +134,14 @@ class Fixture { "enableAutoPerformanceTracing" to true, "connectionTimeoutMillis" to 9006, "readTimeoutMillis" to 9007, - "proxy" to mapOf( - "host" to "localhost", - "port" to 8080, - "type" to "http", // lowercase to check enum mapping - "user" to "admin", - "pass" to "0000", - ) + "proxy" to + mapOf( + "host" to "localhost", + "port" to 8080, + "type" to "http", // lowercase to check enum mapping + "user" to "admin", + "pass" to "0000", + ) ) fun getSut(): SentryFlutter { From 97a1c792e7bab48f9ac79024520282db2a951e73 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 23 Jul 2024 15:03:50 +0200 Subject: [PATCH 12/34] fix multilin issue --- .../kotlin/io/sentry/flutter/SentryFlutter.kt | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt b/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt index a17e0ab965..7082533765 100644 --- a/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt +++ b/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt @@ -122,22 +122,21 @@ class SentryFlutter( options.readTimeoutMillis = it } data.getIfNotNull>("proxy") { proxyJson -> - options.proxy = Proxy() - .apply { - host = proxyJson["host"] as? String - port = (proxyJson["port"] as? Int)?.let { - "$it" - } - (proxyJson["type"] as? String)?.let { - type = try { - Type.valueOf(it.uppercase()) - } catch (e: IllegalArgumentException) { - null - } + options.proxy = Proxy().apply { + host = proxyJson["host"] as? String + port = (proxyJson["port"] as? Int)?.let { + "$it" + } + (proxyJson["type"] as? String)?.let { + type = try { + Type.valueOf(it.uppercase()) + } catch (e: IllegalArgumentException) { + null } - user = proxyJson["user"] as? String - pass = proxyJson["pass"] as? String } + user = proxyJson["user"] as? String + pass = proxyJson["pass"] as? String + } } } } From 8ca76d99e0d34ea13b40c40ca9e6aebdd5fa7410 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 23 Jul 2024 15:12:01 +0200 Subject: [PATCH 13/34] use toUpperCase(Locale.ROOT) --- .../android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt b/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt index 7082533765..b56fe925c0 100644 --- a/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt +++ b/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt @@ -129,7 +129,7 @@ class SentryFlutter( } (proxyJson["type"] as? String)?.let { type = try { - Type.valueOf(it.uppercase()) + Type.valueOf(it.toUpperCase(Locale.ROOT)) } catch (e: IllegalArgumentException) { null } From d8a516db8fb19ed94209618c999cfcae1e678a02 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 23 Jul 2024 15:18:33 +0200 Subject: [PATCH 14/34] fix newlines --- .../kotlin/io/sentry/flutter/SentryFlutter.kt | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt b/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt index b56fe925c0..3d5b1b9dca 100644 --- a/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt +++ b/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt @@ -124,16 +124,18 @@ class SentryFlutter( data.getIfNotNull>("proxy") { proxyJson -> options.proxy = Proxy().apply { host = proxyJson["host"] as? String - port = (proxyJson["port"] as? Int)?.let { - "$it" - } - (proxyJson["type"] as? String)?.let { - type = try { - Type.valueOf(it.toUpperCase(Locale.ROOT)) - } catch (e: IllegalArgumentException) { - null + port = (proxyJson["port"] as? Int) + ?.let { + "$it" + } + (proxyJson["type"] as? String) + ?.let { + type = try { + Type.valueOf(it.toUpperCase(Locale.ROOT)) + } catch (e: IllegalArgumentException) { + null + } } - } user = proxyJson["user"] as? String pass = proxyJson["pass"] as? String } From 569400a694e3216b354723ffe9c5ebaae97baeca Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 23 Jul 2024 15:19:12 +0200 Subject: [PATCH 15/34] fix newline --- .../kotlin/io/sentry/flutter/SentryFlutter.kt | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt b/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt index 3d5b1b9dca..260843cac6 100644 --- a/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt +++ b/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt @@ -122,23 +122,24 @@ class SentryFlutter( options.readTimeoutMillis = it } data.getIfNotNull>("proxy") { proxyJson -> - options.proxy = Proxy().apply { - host = proxyJson["host"] as? String - port = (proxyJson["port"] as? Int) - ?.let { - "$it" - } - (proxyJson["type"] as? String) - ?.let { - type = try { - Type.valueOf(it.toUpperCase(Locale.ROOT)) - } catch (e: IllegalArgumentException) { - null + options.proxy = Proxy() + .apply { + host = proxyJson["host"] as? String + port = (proxyJson["port"] as? Int) + ?.let { + "$it" } - } - user = proxyJson["user"] as? String - pass = proxyJson["pass"] as? String - } + (proxyJson["type"] as? String) + ?.let { + type = try { + Type.valueOf(it.toUpperCase(Locale.ROOT)) + } catch (e: IllegalArgumentException) { + null + } + } + user = proxyJson["user"] as? String + pass = proxyJson["pass"] as? String + } } } } From 0d11ed68cb607c81c7885e216c69f873329d5793 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 23 Jul 2024 15:23:25 +0200 Subject: [PATCH 16/34] format --- dart/lib/src/transport/spotlight_http_transport.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dart/lib/src/transport/spotlight_http_transport.dart b/dart/lib/src/transport/spotlight_http_transport.dart index 344b51a02f..7567039d82 100644 --- a/dart/lib/src/transport/spotlight_http_transport.dart +++ b/dart/lib/src/transport/spotlight_http_transport.dart @@ -5,7 +5,7 @@ import 'http_transport_request_handler.dart'; import '../../sentry.dart'; import '../noop_client.dart'; import '../http_client/client_provider.dart' -if (dart.library.io) '../http_client/io_client_provider.dart'; + if (dart.library.io) '../http_client/io_client_provider.dart'; /// Spotlight HTTP transport decorator that sends Sentry envelopes to both Sentry and Spotlight. class SpotlightHttpTransport extends Transport { From 8e5baf11bf20e53d38843fade7f48f836160bee8 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 23 Jul 2024 15:35:15 +0200 Subject: [PATCH 17/34] format flutter --- flutter/lib/src/native/sentry_native_channel.dart | 5 +++-- flutter/test/integrations/init_native_sdk_test.dart | 10 +++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/flutter/lib/src/native/sentry_native_channel.dart b/flutter/lib/src/native/sentry_native_channel.dart index 330d711dfa..623111bb9e 100644 --- a/flutter/lib/src/native/sentry_native_channel.dart +++ b/flutter/lib/src/native/sentry_native_channel.dart @@ -64,8 +64,9 @@ class SentryNativeChannel 'enableAppHangTracking': options.enableAppHangTracking, 'connectionTimeoutMillis': options.connectionTimeout.inMilliseconds, 'readTimeoutMillis': options.readTimeout.inMilliseconds, - 'appHangTimeoutIntervalMillis': options.appHangTimeoutInterval.inMilliseconds, - if (options.proxy != null) 'proxy': options.proxy?.toJson(), + 'appHangTimeoutIntervalMillis': + options.appHangTimeoutInterval.inMilliseconds, + if (options.proxy != null) 'proxy': options.proxy?.toJson(), }); } diff --git a/flutter/test/integrations/init_native_sdk_test.dart b/flutter/test/integrations/init_native_sdk_test.dart index 54789606cc..02211a579c 100644 --- a/flutter/test/integrations/init_native_sdk_test.dart +++ b/flutter/test/integrations/init_native_sdk_test.dart @@ -106,11 +106,11 @@ void main() { ..readTimeout = Duration(milliseconds: 9002) ..appHangTimeoutInterval = Duration(milliseconds: 9003) ..proxy = Proxy( - host: "localhost", - port: 8080, - type: ProxyType.http, - user: 'admin', - pass: '0000', + host: "localhost", + port: 8080, + type: ProxyType.http, + user: 'admin', + pass: '0000', ); fixture.options.sdk.addIntegration('foo'); From 6b2a062ce9999e32db3411325aba25beee234043 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 23 Jul 2024 15:45:09 +0200 Subject: [PATCH 18/34] log parse error --- .../android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt b/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt index 260843cac6..a56dc77da2 100644 --- a/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt +++ b/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt @@ -133,7 +133,8 @@ class SentryFlutter( ?.let { type = try { Type.valueOf(it.toUpperCase(Locale.ROOT)) - } catch (e: IllegalArgumentException) { + } catch (_: IllegalArgumentException) { + Log.w("Sentry", "Could not parse `type` from proxy json: $proxyJson") null } } From a8ae14604a00221d806b5a250a73f7b4dc5f83e0 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 23 Jul 2024 16:34:34 +0200 Subject: [PATCH 19/34] format by running ktlint locally --- .../kotlin/io/sentry/flutter/SentryFlutter.kt | 41 ++++++++++--------- .../io/sentry/flutter/SentryFlutterTest.kt | 7 ++-- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt b/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt index a56dc77da2..6d2e1ce4a3 100644 --- a/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt +++ b/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt @@ -5,8 +5,8 @@ import io.sentry.SentryOptions.Proxy import io.sentry.android.core.BuildConfig import io.sentry.android.core.SentryAndroidOptions import io.sentry.protocol.SdkVersion -import java.util.Locale import java.net.Proxy.Type +import java.util.Locale class SentryFlutter( private val androidSdk: String, @@ -122,25 +122,28 @@ class SentryFlutter( options.readTimeoutMillis = it } data.getIfNotNull>("proxy") { proxyJson -> - options.proxy = Proxy() - .apply { - host = proxyJson["host"] as? String - port = (proxyJson["port"] as? Int) - ?.let { - "$it" - } - (proxyJson["type"] as? String) - ?.let { - type = try { - Type.valueOf(it.toUpperCase(Locale.ROOT)) - } catch (_: IllegalArgumentException) { - Log.w("Sentry", "Could not parse `type` from proxy json: $proxyJson") - null + options.proxy = + Proxy() + .apply { + host = proxyJson["host"] as? String + port = + (proxyJson["port"] as? Int) + ?.let { + "$it" + } + (proxyJson["type"] as? String) + ?.let { + type = + try { + Type.valueOf(it.toUpperCase(Locale.ROOT)) + } catch (_: IllegalArgumentException) { + Log.w("Sentry", "Could not parse `type` from proxy json: $proxyJson") + null + } } - } - user = proxyJson["user"] as? String - pass = proxyJson["pass"] as? String - } + user = proxyJson["user"] as? String + pass = proxyJson["pass"] as? String + } } } } diff --git a/flutter/android/src/test/kotlin/io/sentry/flutter/SentryFlutterTest.kt b/flutter/android/src/test/kotlin/io/sentry/flutter/SentryFlutterTest.kt index 7fba2192c5..9fa9183f33 100644 --- a/flutter/android/src/test/kotlin/io/sentry/flutter/SentryFlutterTest.kt +++ b/flutter/android/src/test/kotlin/io/sentry/flutter/SentryFlutterTest.kt @@ -141,13 +141,12 @@ class Fixture { "type" to "http", // lowercase to check enum mapping "user" to "admin", "pass" to "0000", - ) + ), ) - fun getSut(): SentryFlutter { - return SentryFlutter( + fun getSut(): SentryFlutter = + SentryFlutter( androidSdk = "sentry.java.android.flutter", nativeSdk = "fixture-nativeSdk", ) - } } From 8452d39e30c22dcec43fb539a540e5b0a917e2aa Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 23 Jul 2024 17:07:04 +0200 Subject: [PATCH 20/34] import log --- .../android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt b/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt index 6d2e1ce4a3..123778e9be 100644 --- a/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt +++ b/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt @@ -1,5 +1,6 @@ package io.sentry.flutter +import android.util.Log import io.sentry.SentryLevel import io.sentry.SentryOptions.Proxy import io.sentry.android.core.BuildConfig From 2e9926e99a4bb9989f8f88868331d49783568306 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 23 Jul 2024 17:07:57 +0200 Subject: [PATCH 21/34] fix cl --- CHANGELOG.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be979a9693..1ebc22d2e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,10 @@ ### Features -- Add proxy support ([#2192](https://github.com/getsentry/sentry-dart/pull/2192)) - - Support `ignoredExceptionsForType` ([#2150](https://github.com/getsentry/sentry-dart/pull/2150)) - Filter out exception types by calling `SentryOptions.addExceptionFilterForType(Type exceptionType)` - +- Add proxy support ([#2192](https://github.com/getsentry/sentry-dart/pull/2192)) + ### Fixes - Disable sff & frame delay detection on web, linux and windows ([#2182](https://github.com/getsentry/sentry-dart/pull/2182)) From ef70ca4a5aefe9b9574e287f11f5d42e4a5f73f5 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 29 Jul 2024 13:34:49 +0200 Subject: [PATCH 22/34] fix cl --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ed68bd529..07bbf0538a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Features + +- Add proxy support ([#2192](https://github.com/getsentry/sentry-dart/pull/2192)) + ### Improvements - Add error type identifier to improve obfuscated Flutter issue titles ([#2170](https://github.com/getsentry/sentry-dart/pull/2170)) @@ -50,7 +54,6 @@ SentryFlutter.init((options) => - This allows viewing the correct dart formatted raw stacktrace in the Sentry UI - Support `ignoredExceptionsForType` ([#2150](https://github.com/getsentry/sentry-dart/pull/2150)) - Filter out exception types by calling `SentryOptions.addExceptionFilterForType(Type exceptionType)` -- Add proxy support ([#2192](https://github.com/getsentry/sentry-dart/pull/2192)) ### Fixes From a7a04d99e35d4c69320fa7906503f7318850abb9 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 29 Jul 2024 13:35:12 +0200 Subject: [PATCH 23/34] fix typo --- dart/lib/src/sentry_options.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dart/lib/src/sentry_options.dart b/dart/lib/src/sentry_options.dart index 076c8422c3..fd3417d218 100644 --- a/dart/lib/src/sentry_options.dart +++ b/dart/lib/src/sentry_options.dart @@ -495,7 +495,7 @@ class SentryOptions { /// A http proxy will be set in returned for 'HttpClient.findProxy' in the /// form 'PROXY :'. /// When setting 'user' and 'pass', the 'HttpClient.addProxyCredentials' - /// method will be called wit empty 'realm'. + /// method will be called with empty 'realm'. /// /// On Android, the proxy settings are handled by the native SDK. /// iOS and macOS native SDKs do not support proxy settings. From 4d9757071ad4bf27b8e676e38543f99e34254937 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 29 Jul 2024 13:52:12 +0200 Subject: [PATCH 24/34] mark client providers as internal --- dart/lib/src/http_client/client_provider.dart | 3 +++ dart/lib/src/http_client/io_client_provider.dart | 3 +++ 2 files changed, 6 insertions(+) diff --git a/dart/lib/src/http_client/client_provider.dart b/dart/lib/src/http_client/client_provider.dart index 25fcfe6b47..201a559601 100644 --- a/dart/lib/src/http_client/client_provider.dart +++ b/dart/lib/src/http_client/client_provider.dart @@ -1,11 +1,14 @@ +import 'package:meta/meta.dart'; import 'package:http/http.dart'; import '../sentry_options.dart'; +@internal ClientProvider getClientProvider() { return ClientProvider(); } +@internal class ClientProvider { Client getClient(SentryOptions options) { return Client(); diff --git a/dart/lib/src/http_client/io_client_provider.dart b/dart/lib/src/http_client/io_client_provider.dart index 4f56f1a94a..40b149eee2 100644 --- a/dart/lib/src/http_client/io_client_provider.dart +++ b/dart/lib/src/http_client/io_client_provider.dart @@ -2,12 +2,14 @@ import 'dart:io'; import 'package:http/http.dart'; import 'package:http/io_client.dart'; +import 'package:meta/meta.dart'; import '../protocol.dart'; import '../proxy.dart'; import '../sentry_options.dart'; import 'client_provider.dart'; +@internal ClientProvider getClientProvider() { return IoClientProvider( () { @@ -19,6 +21,7 @@ ClientProvider getClientProvider() { ); } +@internal class IoClientProvider implements ClientProvider { final HttpClient Function() _httpClient; final HttpClientCredentials Function(String, String) _httpClientCredentials; From 16c6795ff012f4c42ede9235bf6cc883420cc240 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 29 Jul 2024 14:02:03 +0200 Subject: [PATCH 25/34] rename Proxy to SentryProxy --- dart/lib/sentry.dart | 2 +- .../src/http_client/io_client_provider.dart | 2 +- .../{proxy.dart => protocol/sentry_proxy.dart} | 8 ++++---- dart/lib/src/sentry_options.dart | 2 +- .../http_client/io_client_provider_test.dart | 8 ++++---- ...{proxy_test.dart => sentry_proxy_test.dart} | 18 ++++++++++-------- .../integrations/init_native_sdk_test.dart | 2 +- 7 files changed, 22 insertions(+), 20 deletions(-) rename dart/lib/src/{proxy.dart => protocol/sentry_proxy.dart} (89%) rename dart/test/protocol/{proxy_test.dart => sentry_proxy_test.dart} (79%) diff --git a/dart/lib/sentry.dart b/dart/lib/sentry.dart index 02b6266f81..e9cae9d666 100644 --- a/dart/lib/sentry.dart +++ b/dart/lib/sentry.dart @@ -57,4 +57,4 @@ export 'src/utils.dart'; // spotlight debugging export 'src/spotlight.dart'; // proxy -export 'src/proxy.dart'; +export 'src/protocol/sentry_proxy.dart'; diff --git a/dart/lib/src/http_client/io_client_provider.dart b/dart/lib/src/http_client/io_client_provider.dart index 40b149eee2..c958298778 100644 --- a/dart/lib/src/http_client/io_client_provider.dart +++ b/dart/lib/src/http_client/io_client_provider.dart @@ -5,7 +5,7 @@ import 'package:http/io_client.dart'; import 'package:meta/meta.dart'; import '../protocol.dart'; -import '../proxy.dart'; +import '../protocol/sentry_proxy.dart'; import '../sentry_options.dart'; import 'client_provider.dart'; diff --git a/dart/lib/src/proxy.dart b/dart/lib/src/protocol/sentry_proxy.dart similarity index 89% rename from dart/lib/src/proxy.dart rename to dart/lib/src/protocol/sentry_proxy.dart index 9f0393f25e..469a192f4d 100644 --- a/dart/lib/src/proxy.dart +++ b/dart/lib/src/protocol/sentry_proxy.dart @@ -1,11 +1,11 @@ -class Proxy { +class SentryProxy { final ProxyType type; final String? host; final int? port; final String? user; final String? pass; - Proxy({required this.type, this.host, this.port, this.user, this.pass}); + SentryProxy({required this.type, this.host, this.port, this.user, this.pass}); String toPacString() { String type = 'DIRECT'; @@ -39,14 +39,14 @@ class Proxy { }; } - Proxy copyWith({ + SentryProxy copyWith({ String? host, int? port, ProxyType? type, String? user, String? pass, }) => - Proxy( + SentryProxy( host: host ?? this.host, port: port ?? this.port, type: type ?? this.type, diff --git a/dart/lib/src/sentry_options.dart b/dart/lib/src/sentry_options.dart index fd3417d218..19d7b56f42 100644 --- a/dart/lib/src/sentry_options.dart +++ b/dart/lib/src/sentry_options.dart @@ -499,7 +499,7 @@ class SentryOptions { /// /// On Android, the proxy settings are handled by the native SDK. /// iOS and macOS native SDKs do not support proxy settings. - Proxy? proxy; + SentryProxy? proxy; SentryOptions({this.dsn, PlatformChecker? checker}) { if (checker != null) { diff --git a/dart/test/http_client/io_client_provider_test.dart b/dart/test/http_client/io_client_provider_test.dart index d033c79e05..7df9f0c559 100644 --- a/dart/test/http_client/io_client_provider_test.dart +++ b/dart/test/http_client/io_client_provider_test.dart @@ -18,7 +18,7 @@ void main() { }); test('http proxy should call findProxyResult', () async { - fixture.options.proxy = Proxy( + fixture.options.proxy = SentryProxy( type: ProxyType.http, host: 'localhost', port: 8080, @@ -32,7 +32,7 @@ void main() { }); test('direct proxy should call findProxyResult', () async { - fixture.options.proxy = Proxy(type: ProxyType.direct); + fixture.options.proxy = SentryProxy(type: ProxyType.direct); final sut = fixture.getSut(); sut.getClient(fixture.options); @@ -43,7 +43,7 @@ void main() { test('socks proxy should not call findProxyResult', () async { fixture.options.proxy = - Proxy(type: ProxyType.socks, host: 'localhost', port: 8080); + SentryProxy(type: ProxyType.socks, host: 'localhost', port: 8080); final sut = fixture.getSut(); sut.getClient(fixture.options); @@ -52,7 +52,7 @@ void main() { }); test('authenticated proxy http should call addProxyCredentials', () async { - fixture.options.proxy = Proxy( + fixture.options.proxy = SentryProxy( type: ProxyType.http, host: 'localhost', port: 8080, diff --git a/dart/test/protocol/proxy_test.dart b/dart/test/protocol/sentry_proxy_test.dart similarity index 79% rename from dart/test/protocol/proxy_test.dart rename to dart/test/protocol/sentry_proxy_test.dart index 021b13990e..76c4d58250 100644 --- a/dart/test/protocol/proxy_test.dart +++ b/dart/test/protocol/sentry_proxy_test.dart @@ -3,7 +3,7 @@ import 'package:sentry/sentry.dart'; import 'package:test/test.dart'; void main() { - final proxy = Proxy( + final proxy = SentryProxy( host: 'localhost', port: 8080, type: ProxyType.http, @@ -21,38 +21,40 @@ void main() { group('toPacString', () { test('returns "DIRECT" for ProxyType.direct', () { - Proxy proxy = Proxy(type: ProxyType.direct); + SentryProxy proxy = SentryProxy(type: ProxyType.direct); expect(proxy.toPacString(), equals('DIRECT')); }); test('returns "PROXY host:port" for ProxyType.http with host and port', () { - Proxy proxy = Proxy(type: ProxyType.http, host: 'localhost', port: 8080); + SentryProxy proxy = + SentryProxy(type: ProxyType.http, host: 'localhost', port: 8080); expect(proxy.toPacString(), equals('PROXY localhost:8080')); }); test('returns "PROXY host" for ProxyType.http with host only', () { - Proxy proxy = Proxy(type: ProxyType.http, host: 'localhost'); + SentryProxy proxy = SentryProxy(type: ProxyType.http, host: 'localhost'); expect(proxy.toPacString(), equals('PROXY localhost')); }); test('returns "SOCKS host:port" for ProxyType.socks with host and port', () { - Proxy proxy = Proxy(type: ProxyType.socks, host: 'localhost', port: 8080); + SentryProxy proxy = + SentryProxy(type: ProxyType.socks, host: 'localhost', port: 8080); expect(proxy.toPacString(), equals('SOCKS localhost:8080')); }); test('returns "SOCKS host" for ProxyType.socks with host only', () { - Proxy proxy = Proxy(type: ProxyType.socks, host: 'localhost'); + SentryProxy proxy = SentryProxy(type: ProxyType.socks, host: 'localhost'); expect(proxy.toPacString(), equals('SOCKS localhost')); }); test('falls back to "DIRECT" if http is missing host', () { - Proxy proxy = Proxy(type: ProxyType.http); + SentryProxy proxy = SentryProxy(type: ProxyType.http); expect(proxy.toPacString(), equals('DIRECT')); }); test('falls back to "DIRECT" if socks is missing host', () { - Proxy proxy = Proxy(type: ProxyType.socks); + SentryProxy proxy = SentryProxy(type: ProxyType.socks); expect(proxy.toPacString(), equals('DIRECT')); }); }); diff --git a/flutter/test/integrations/init_native_sdk_test.dart b/flutter/test/integrations/init_native_sdk_test.dart index 02211a579c..bfdb0431b0 100644 --- a/flutter/test/integrations/init_native_sdk_test.dart +++ b/flutter/test/integrations/init_native_sdk_test.dart @@ -105,7 +105,7 @@ void main() { ..connectionTimeout = Duration(milliseconds: 9001) ..readTimeout = Duration(milliseconds: 9002) ..appHangTimeoutInterval = Duration(milliseconds: 9003) - ..proxy = Proxy( + ..proxy = SentryProxy( host: "localhost", port: 8080, type: ProxyType.http, From 67c474f125d12c1b11d15230abfc8a9c4917236f Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 29 Jul 2024 16:49:00 +0200 Subject: [PATCH 26/34] configure url session on ios --- .../src/http_client/io_client_provider.dart | 2 +- dart/lib/src/protocol/sentry_proxy.dart | 12 ++--- .../http_client/io_client_provider_test.dart | 8 ++-- dart/test/protocol/sentry_proxy_test.dart | 20 ++++----- .../ios/RunnerTests/SentryFlutterTests.swift | 44 ++++++++++++++++++- flutter/ios/Classes/SentryFlutter.swift | 34 ++++++++++++++ .../integrations/init_native_sdk_test.dart | 2 +- 7 files changed, 99 insertions(+), 23 deletions(-) diff --git a/dart/lib/src/http_client/io_client_provider.dart b/dart/lib/src/http_client/io_client_provider.dart index c958298778..b8ec366d06 100644 --- a/dart/lib/src/http_client/io_client_provider.dart +++ b/dart/lib/src/http_client/io_client_provider.dart @@ -35,7 +35,7 @@ class IoClientProvider implements ClientProvider { return Client(); } final pac = proxy.toPacString(); - if (proxy.type == ProxyType.socks) { + if (proxy.type == SentryProxyType.socks) { options.logger( SentryLevel.warning, "Setting proxy '$pac' is not supported.", diff --git a/dart/lib/src/protocol/sentry_proxy.dart b/dart/lib/src/protocol/sentry_proxy.dart index 469a192f4d..7dcaefef22 100644 --- a/dart/lib/src/protocol/sentry_proxy.dart +++ b/dart/lib/src/protocol/sentry_proxy.dart @@ -1,5 +1,5 @@ class SentryProxy { - final ProxyType type; + final SentryProxyType type; final String? host; final int? port; final String? user; @@ -10,12 +10,12 @@ class SentryProxy { String toPacString() { String type = 'DIRECT'; switch (this.type) { - case ProxyType.direct: + case SentryProxyType.direct: return 'DIRECT'; - case ProxyType.http: + case SentryProxyType.http: type = 'PROXY'; break; - case ProxyType.socks: + case SentryProxyType.socks: type = 'SOCKS'; break; } @@ -42,7 +42,7 @@ class SentryProxy { SentryProxy copyWith({ String? host, int? port, - ProxyType? type, + SentryProxyType? type, String? user, String? pass, }) => @@ -55,7 +55,7 @@ class SentryProxy { ); } -enum ProxyType { +enum SentryProxyType { direct, http, socks; diff --git a/dart/test/http_client/io_client_provider_test.dart b/dart/test/http_client/io_client_provider_test.dart index 7df9f0c559..ffba4aa0ee 100644 --- a/dart/test/http_client/io_client_provider_test.dart +++ b/dart/test/http_client/io_client_provider_test.dart @@ -19,7 +19,7 @@ void main() { test('http proxy should call findProxyResult', () async { fixture.options.proxy = SentryProxy( - type: ProxyType.http, + type: SentryProxyType.http, host: 'localhost', port: 8080, ); @@ -32,7 +32,7 @@ void main() { }); test('direct proxy should call findProxyResult', () async { - fixture.options.proxy = SentryProxy(type: ProxyType.direct); + fixture.options.proxy = SentryProxy(type: SentryProxyType.direct); final sut = fixture.getSut(); sut.getClient(fixture.options); @@ -43,7 +43,7 @@ void main() { test('socks proxy should not call findProxyResult', () async { fixture.options.proxy = - SentryProxy(type: ProxyType.socks, host: 'localhost', port: 8080); + SentryProxy(type: SentryProxyType.socks, host: 'localhost', port: 8080); final sut = fixture.getSut(); sut.getClient(fixture.options); @@ -53,7 +53,7 @@ void main() { test('authenticated proxy http should call addProxyCredentials', () async { fixture.options.proxy = SentryProxy( - type: ProxyType.http, + type: SentryProxyType.http, host: 'localhost', port: 8080, user: 'admin', diff --git a/dart/test/protocol/sentry_proxy_test.dart b/dart/test/protocol/sentry_proxy_test.dart index 76c4d58250..691d63bad5 100644 --- a/dart/test/protocol/sentry_proxy_test.dart +++ b/dart/test/protocol/sentry_proxy_test.dart @@ -6,7 +6,7 @@ void main() { final proxy = SentryProxy( host: 'localhost', port: 8080, - type: ProxyType.http, + type: SentryProxyType.http, user: 'admin', pass: '0000', ); @@ -21,40 +21,40 @@ void main() { group('toPacString', () { test('returns "DIRECT" for ProxyType.direct', () { - SentryProxy proxy = SentryProxy(type: ProxyType.direct); + SentryProxy proxy = SentryProxy(type: SentryProxyType.direct); expect(proxy.toPacString(), equals('DIRECT')); }); test('returns "PROXY host:port" for ProxyType.http with host and port', () { SentryProxy proxy = - SentryProxy(type: ProxyType.http, host: 'localhost', port: 8080); + SentryProxy(type: SentryProxyType.http, host: 'localhost', port: 8080); expect(proxy.toPacString(), equals('PROXY localhost:8080')); }); test('returns "PROXY host" for ProxyType.http with host only', () { - SentryProxy proxy = SentryProxy(type: ProxyType.http, host: 'localhost'); + SentryProxy proxy = SentryProxy(type: SentryProxyType.http, host: 'localhost'); expect(proxy.toPacString(), equals('PROXY localhost')); }); test('returns "SOCKS host:port" for ProxyType.socks with host and port', () { SentryProxy proxy = - SentryProxy(type: ProxyType.socks, host: 'localhost', port: 8080); + SentryProxy(type: SentryProxyType.socks, host: 'localhost', port: 8080); expect(proxy.toPacString(), equals('SOCKS localhost:8080')); }); test('returns "SOCKS host" for ProxyType.socks with host only', () { - SentryProxy proxy = SentryProxy(type: ProxyType.socks, host: 'localhost'); + SentryProxy proxy = SentryProxy(type: SentryProxyType.socks, host: 'localhost'); expect(proxy.toPacString(), equals('SOCKS localhost')); }); test('falls back to "DIRECT" if http is missing host', () { - SentryProxy proxy = SentryProxy(type: ProxyType.http); + SentryProxy proxy = SentryProxy(type: SentryProxyType.http); expect(proxy.toPacString(), equals('DIRECT')); }); test('falls back to "DIRECT" if socks is missing host', () { - SentryProxy proxy = SentryProxy(type: ProxyType.socks); + SentryProxy proxy = SentryProxy(type: SentryProxyType.socks); expect(proxy.toPacString(), equals('DIRECT')); }); }); @@ -85,14 +85,14 @@ void main() { final copy = data.copyWith( host: 'localhost-2', port: 9001, - type: ProxyType.socks, + type: SentryProxyType.socks, user: 'user', pass: '1234', ); expect('localhost-2', copy.host); expect(9001, copy.port); - expect(ProxyType.socks, copy.type); + expect(SentryProxyType.socks, copy.type); expect('user', copy.user); expect('1234', copy.pass); }); diff --git a/flutter/example/ios/RunnerTests/SentryFlutterTests.swift b/flutter/example/ios/RunnerTests/SentryFlutterTests.swift index 057b2363b5..910c262cd8 100644 --- a/flutter/example/ios/RunnerTests/SentryFlutterTests.swift +++ b/flutter/example/ios/RunnerTests/SentryFlutterTests.swift @@ -43,7 +43,14 @@ final class SentryFlutterTests: XCTestCase { "maxAttachmentSize": NSNumber(value: 9004), "captureFailedRequests": false, "enableAppHangTracking": false, - "appHangTimeoutIntervalMillis": NSNumber(value: 10000) + "appHangTimeoutIntervalMillis": NSNumber(value: 10000), + "proxy": [ + "host": "localhost", + "port": NSNumber(value: 8080), + "type": "hTtP", // mixed case to check enum mapping + "user": "admin", + "pass": "0000", + ] ] ) @@ -68,6 +75,41 @@ final class SentryFlutterTests: XCTestCase { XCTAssertEqual(false, fixture.options.enableCaptureFailedRequests) XCTAssertEqual(false, fixture.options.enableAppHangTracking) XCTAssertEqual(10, fixture.options.appHangTimeoutInterval) + + XCTAssertNotNil(fixture.options.urlSession) + XCTAssertEqual(true, fixture.options.urlSession?.configuration.connectionProxyDictionary?[kCFNetworkProxiesHTTPEnable as String] as? Bool) + XCTAssertEqual("localhost", fixture.options.urlSession?.configuration.connectionProxyDictionary?[kCFNetworkProxiesHTTPProxy as String] as? String) + XCTAssertEqual(8080, fixture.options.urlSession?.configuration.connectionProxyDictionary?[kCFNetworkProxiesHTTPPort as String] as? Int) + XCTAssertEqual("admin", fixture.options.urlSession?.configuration.connectionProxyDictionary?[kCFProxyUsernameKey as String] as? String) + XCTAssertEqual("0000", fixture.options.urlSession?.configuration.connectionProxyDictionary?[kCFProxyPasswordKey as String] as? String) + } + + func testUpdateSocksProxy() { + let sut = fixture.getSut() + + sut.update( + options: fixture.options, + with: [ + "proxy": [ + "host": "localhost", + "port": 8080, + "type": "sOcKs", // mixed case to check enum mapping + "user": "admin", + "pass": "0000", + ] + ] + ) + + #if os(macOS) + XCTAssertNotNil(fixture.options.urlSession) + XCTAssertEqual(true, fixture.options.urlSession?.configuration.connectionProxyDictionary?[kCFNetworkProxiesSOCKSEnable as String] as? Bool) + XCTAssertEqual("localhost", fixture.options.urlSession?.configuration.connectionProxyDictionary?[kCFNetworkProxiesSOCKSProxy as String] as? String) + XCTAssertEqual(8080, fixture.options.urlSession?.configuration.connectionProxyDictionary?[kCFNetworkProxiesSOCKSPort as String] as? Int) + XCTAssertEqual("admin", fixture.options.urlSession?.configuration.connectionProxyDictionary?[kCFProxyUsernameKey as String] as? String) + XCTAssertEqual("0000", fixture.options.urlSession?.configuration.connectionProxyDictionary?[kCFProxyPasswordKey as String] as? String) + #else + XCTAssertNil(fixture.options.urlSession) + #endif } } diff --git a/flutter/ios/Classes/SentryFlutter.swift b/flutter/ios/Classes/SentryFlutter.swift index b26bcfc30d..303ad13891 100644 --- a/flutter/ios/Classes/SentryFlutter.swift +++ b/flutter/ios/Classes/SentryFlutter.swift @@ -70,6 +70,40 @@ public final class SentryFlutter { if let appHangTimeoutIntervalMillis = data["appHangTimeoutIntervalMillis"] as? NSNumber { options.appHangTimeoutInterval = appHangTimeoutIntervalMillis.doubleValue / 1000 } + if let proxy = data["proxy"] as? [String: Any] { + guard let host = proxy["host"] as? String, + let port = proxy["port"] as? Int, + let type = proxy["type"] as? String else { + return + } + + var connectionProxyDictionary: [String: Any] = [:] + if type.lowercased() == "http" { + connectionProxyDictionary[kCFNetworkProxiesHTTPEnable as String] = true + connectionProxyDictionary[kCFNetworkProxiesHTTPProxy as String] = host + connectionProxyDictionary[kCFNetworkProxiesHTTPPort as String] = port + } else if type.lowercased() == "socks" { + #if os(macOS) + connectionProxyDictionary[kCFNetworkProxiesSOCKSEnable as String] = true + connectionProxyDictionary[kCFNetworkProxiesSOCKSProxy as String] = host + connectionProxyDictionary[kCFNetworkProxiesSOCKSPort as String] = port + #else + return + #endif + } else { + return + } + + if let user = proxy["user"] as? String, let pass = proxy["pass"] { + connectionProxyDictionary[kCFProxyUsernameKey as String] = user + connectionProxyDictionary[kCFProxyPasswordKey as String] = pass + } + + let configuration = URLSessionConfiguration.default + configuration.connectionProxyDictionary = connectionProxyDictionary + + options.urlSession = URLSession(configuration: configuration) + } } private func logLevelFrom(diagnosticLevel: String) -> SentryLevel { diff --git a/flutter/test/integrations/init_native_sdk_test.dart b/flutter/test/integrations/init_native_sdk_test.dart index bfdb0431b0..d3faa93346 100644 --- a/flutter/test/integrations/init_native_sdk_test.dart +++ b/flutter/test/integrations/init_native_sdk_test.dart @@ -108,7 +108,7 @@ void main() { ..proxy = SentryProxy( host: "localhost", port: 8080, - type: ProxyType.http, + type: SentryProxyType.http, user: 'admin', pass: '0000', ); From acb26581b83bc8070fafe59bbd54179a8f3188e2 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 30 Jul 2024 10:07:30 +0200 Subject: [PATCH 27/34] update changelog entry --- CHANGELOG.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07bbf0538a..6660c0a3fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,26 @@ ### Features - Add proxy support ([#2192](https://github.com/getsentry/sentry-dart/pull/2192)) + - Configure a `SentryProxy` object and set it on `SentryFlutter.init` +```dart +import 'package:flutter/widgets.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; + +Future main() async { + await SentryFlutter.init( + (options) { + options.dsn = 'https://example@sentry.io/add-your-dsn-here'; + options.proxy = SentryProxy( + type: SenryProxyType.http, + host: 'localhost', + port: 8080, + ); + }, + // Init your App. + appRunner: () => runApp(MyApp()), + ); +} +``` ### Improvements From 4bbf9114b369ca5ec0bc6dbbcf1b8c7ef79507be Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 30 Jul 2024 10:49:15 +0200 Subject: [PATCH 28/34] =?UTF-8?q?run=20swiftlingt=20=E2=80=94autocorrect?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- flutter/ios/Classes/SentryFlutter.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flutter/ios/Classes/SentryFlutter.swift b/flutter/ios/Classes/SentryFlutter.swift index 303ad13891..957d8b485a 100644 --- a/flutter/ios/Classes/SentryFlutter.swift +++ b/flutter/ios/Classes/SentryFlutter.swift @@ -76,7 +76,7 @@ public final class SentryFlutter { let type = proxy["type"] as? String else { return } - + var connectionProxyDictionary: [String: Any] = [:] if type.lowercased() == "http" { connectionProxyDictionary[kCFNetworkProxiesHTTPEnable as String] = true @@ -93,15 +93,15 @@ public final class SentryFlutter { } else { return } - + if let user = proxy["user"] as? String, let pass = proxy["pass"] { connectionProxyDictionary[kCFProxyUsernameKey as String] = user connectionProxyDictionary[kCFProxyPasswordKey as String] = pass } - + let configuration = URLSessionConfiguration.default configuration.connectionProxyDictionary = connectionProxyDictionary - + options.urlSession = URLSession(configuration: configuration) } } From f48b52d9be2d7ffd58df9481f22c81269354a6f8 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 30 Jul 2024 10:50:22 +0200 Subject: [PATCH 29/34] =?UTF-8?q?run=20swiftling=20=E2=80=94autocorrect?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/ios/RunnerTests/SentryFlutterTests.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/flutter/example/ios/RunnerTests/SentryFlutterTests.swift b/flutter/example/ios/RunnerTests/SentryFlutterTests.swift index 910c262cd8..a6ea06123c 100644 --- a/flutter/example/ios/RunnerTests/SentryFlutterTests.swift +++ b/flutter/example/ios/RunnerTests/SentryFlutterTests.swift @@ -49,7 +49,7 @@ final class SentryFlutterTests: XCTestCase { "port": NSNumber(value: 8080), "type": "hTtP", // mixed case to check enum mapping "user": "admin", - "pass": "0000", + "pass": "0000" ] ] ) @@ -75,7 +75,7 @@ final class SentryFlutterTests: XCTestCase { XCTAssertEqual(false, fixture.options.enableCaptureFailedRequests) XCTAssertEqual(false, fixture.options.enableAppHangTracking) XCTAssertEqual(10, fixture.options.appHangTimeoutInterval) - + XCTAssertNotNil(fixture.options.urlSession) XCTAssertEqual(true, fixture.options.urlSession?.configuration.connectionProxyDictionary?[kCFNetworkProxiesHTTPEnable as String] as? Bool) XCTAssertEqual("localhost", fixture.options.urlSession?.configuration.connectionProxyDictionary?[kCFNetworkProxiesHTTPProxy as String] as? String) @@ -83,7 +83,7 @@ final class SentryFlutterTests: XCTestCase { XCTAssertEqual("admin", fixture.options.urlSession?.configuration.connectionProxyDictionary?[kCFProxyUsernameKey as String] as? String) XCTAssertEqual("0000", fixture.options.urlSession?.configuration.connectionProxyDictionary?[kCFProxyPasswordKey as String] as? String) } - + func testUpdateSocksProxy() { let sut = fixture.getSut() @@ -95,11 +95,11 @@ final class SentryFlutterTests: XCTestCase { "port": 8080, "type": "sOcKs", // mixed case to check enum mapping "user": "admin", - "pass": "0000", + "pass": "0000" ] ] ) - + #if os(macOS) XCTAssertNotNil(fixture.options.urlSession) XCTAssertEqual(true, fixture.options.urlSession?.configuration.connectionProxyDictionary?[kCFNetworkProxiesSOCKSEnable as String] as? Bool) From 89c091501734ae2e8c48b846e6e9bee1795cc2c7 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 30 Jul 2024 11:24:27 +0200 Subject: [PATCH 30/34] run format --- dart/test/http_client/io_client_provider_test.dart | 4 ++-- dart/test/protocol/sentry_proxy_test.dart | 14 ++++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/dart/test/http_client/io_client_provider_test.dart b/dart/test/http_client/io_client_provider_test.dart index ffba4aa0ee..0672e84c08 100644 --- a/dart/test/http_client/io_client_provider_test.dart +++ b/dart/test/http_client/io_client_provider_test.dart @@ -42,8 +42,8 @@ void main() { }); test('socks proxy should not call findProxyResult', () async { - fixture.options.proxy = - SentryProxy(type: SentryProxyType.socks, host: 'localhost', port: 8080); + fixture.options.proxy = SentryProxy( + type: SentryProxyType.socks, host: 'localhost', port: 8080); final sut = fixture.getSut(); sut.getClient(fixture.options); diff --git a/dart/test/protocol/sentry_proxy_test.dart b/dart/test/protocol/sentry_proxy_test.dart index 691d63bad5..795dc1793d 100644 --- a/dart/test/protocol/sentry_proxy_test.dart +++ b/dart/test/protocol/sentry_proxy_test.dart @@ -26,25 +26,27 @@ void main() { }); test('returns "PROXY host:port" for ProxyType.http with host and port', () { - SentryProxy proxy = - SentryProxy(type: SentryProxyType.http, host: 'localhost', port: 8080); + SentryProxy proxy = SentryProxy( + type: SentryProxyType.http, host: 'localhost', port: 8080); expect(proxy.toPacString(), equals('PROXY localhost:8080')); }); test('returns "PROXY host" for ProxyType.http with host only', () { - SentryProxy proxy = SentryProxy(type: SentryProxyType.http, host: 'localhost'); + SentryProxy proxy = + SentryProxy(type: SentryProxyType.http, host: 'localhost'); expect(proxy.toPacString(), equals('PROXY localhost')); }); test('returns "SOCKS host:port" for ProxyType.socks with host and port', () { - SentryProxy proxy = - SentryProxy(type: SentryProxyType.socks, host: 'localhost', port: 8080); + SentryProxy proxy = SentryProxy( + type: SentryProxyType.socks, host: 'localhost', port: 8080); expect(proxy.toPacString(), equals('SOCKS localhost:8080')); }); test('returns "SOCKS host" for ProxyType.socks with host only', () { - SentryProxy proxy = SentryProxy(type: SentryProxyType.socks, host: 'localhost'); + SentryProxy proxy = + SentryProxy(type: SentryProxyType.socks, host: 'localhost'); expect(proxy.toPacString(), equals('SOCKS localhost')); }); From b53e604f9123cb9521479cc42f392968323694fe Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 5 Aug 2024 11:47:19 +0200 Subject: [PATCH 31/34] fix cl and add log --- CHANGELOG.md | 4 +++- flutter/ios/Classes/SentryFlutter.swift | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c631310ea..5e1fe7da0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## 8.6.0 +## Unreleased ### Features @@ -26,6 +26,8 @@ Future main() async { } ``` +## 8.6.0 + ### Improvements - Add error type identifier to improve obfuscated Flutter issue titles ([#2170](https://github.com/getsentry/sentry-dart/pull/2170)) diff --git a/flutter/ios/Classes/SentryFlutter.swift b/flutter/ios/Classes/SentryFlutter.swift index 957d8b485a..769f595fba 100644 --- a/flutter/ios/Classes/SentryFlutter.swift +++ b/flutter/ios/Classes/SentryFlutter.swift @@ -74,6 +74,7 @@ public final class SentryFlutter { guard let host = proxy["host"] as? String, let port = proxy["port"] as? Int, let type = proxy["type"] as? String else { + print("Could not read proxy data") return } From c240fc7afdbb31958301d595e0eb8c3b2b201bd0 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 5 Aug 2024 11:48:41 +0200 Subject: [PATCH 32/34] update docs --- dart/lib/src/sentry_options.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dart/lib/src/sentry_options.dart b/dart/lib/src/sentry_options.dart index 19d7b56f42..1da451e3d1 100644 --- a/dart/lib/src/sentry_options.dart +++ b/dart/lib/src/sentry_options.dart @@ -497,8 +497,8 @@ class SentryOptions { /// When setting 'user' and 'pass', the 'HttpClient.addProxyCredentials' /// method will be called with empty 'realm'. /// - /// On Android, the proxy settings are handled by the native SDK. - /// iOS and macOS native SDKs do not support proxy settings. + /// On Android & iOS, the proxy settings are handled by the native SDK. + /// iOS only supports http proxies, while macOS also supports socks. SentryProxy? proxy; SentryOptions({this.dsn, PlatformChecker? checker}) { From 4e25d10913d1fac2b3d73b5ebf466299ce9ff069 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 6 Aug 2024 15:49:33 +0200 Subject: [PATCH 33/34] disable swiftlint rules --- flutter/ios/Classes/SentryFlutter.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/flutter/ios/Classes/SentryFlutter.swift b/flutter/ios/Classes/SentryFlutter.swift index 769f595fba..7e3310b5eb 100644 --- a/flutter/ios/Classes/SentryFlutter.swift +++ b/flutter/ios/Classes/SentryFlutter.swift @@ -1,11 +1,13 @@ import Sentry +// swiftlint:disable file_length function_body_length line_length + public final class SentryFlutter { public init() { } - // swiftlint:disable:next function_body_length cyclomatic_complexity + // swiftlint:disable:next cyclomatic_complexity public func update(options: Options, with data: [String: Any]) { if let dsn = data["dsn"] as? String { options.dsn = dsn @@ -124,3 +126,5 @@ public final class SentryFlutter { } } } + +// swiftlint:enable file_length function_body_length line_length From bd279c7846ae3529c3c1ebf8a2253d657a3cc70d Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 6 Aug 2024 16:07:03 +0200 Subject: [PATCH 34/34] fix swiftlint issues --- flutter/example/ios/RunnerTests/SentryFlutterTests.swift | 4 ++++ flutter/ios/Classes/SentryFlutter.swift | 6 +----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/flutter/example/ios/RunnerTests/SentryFlutterTests.swift b/flutter/example/ios/RunnerTests/SentryFlutterTests.swift index a6ea06123c..4873388f2f 100644 --- a/flutter/example/ios/RunnerTests/SentryFlutterTests.swift +++ b/flutter/example/ios/RunnerTests/SentryFlutterTests.swift @@ -9,6 +9,8 @@ import XCTest import sentry_flutter import Sentry +// swiftlint:disable function_body_length line_length + final class SentryFlutterTests: XCTestCase { private var fixture: Fixture! @@ -123,3 +125,5 @@ extension SentryFlutterTests { } } } + +// swiftlint:enable function_body_length line_length diff --git a/flutter/ios/Classes/SentryFlutter.swift b/flutter/ios/Classes/SentryFlutter.swift index 7e3310b5eb..769f595fba 100644 --- a/flutter/ios/Classes/SentryFlutter.swift +++ b/flutter/ios/Classes/SentryFlutter.swift @@ -1,13 +1,11 @@ import Sentry -// swiftlint:disable file_length function_body_length line_length - public final class SentryFlutter { public init() { } - // swiftlint:disable:next cyclomatic_complexity + // swiftlint:disable:next function_body_length cyclomatic_complexity public func update(options: Options, with data: [String: Any]) { if let dsn = data["dsn"] as? String { options.dsn = dsn @@ -126,5 +124,3 @@ public final class SentryFlutter { } } } - -// swiftlint:enable file_length function_body_length line_length