From 51ed8cf47e4c8e3030cce3ae6c2c11ae7496c8df Mon Sep 17 00:00:00 2001 From: Lukas Bloder Date: Thu, 4 May 2023 16:47:59 +0200 Subject: [PATCH 1/3] add test for non-ascii characters as id --- .../apollo3/SentryApollo3InterceptorTest.kt | 4 ++-- ...ntryApollo3InterceptorWithVariablesTest.kt | 19 +++++++++++++++++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/sentry-apollo-3/src/test/java/io/sentry/apollo3/SentryApollo3InterceptorTest.kt b/sentry-apollo-3/src/test/java/io/sentry/apollo3/SentryApollo3InterceptorTest.kt index 5266fc69afb..a45f58d7145 100644 --- a/sentry-apollo-3/src/test/java/io/sentry/apollo3/SentryApollo3InterceptorTest.kt +++ b/sentry-apollo-3/src/test/java/io/sentry/apollo3/SentryApollo3InterceptorTest.kt @@ -265,7 +265,7 @@ class SentryApollo3InterceptorTest { } } - private fun executeQuery(sut: ApolloClient = fixture.getSut(), isSpanActive: Boolean = true) = runBlocking { + private fun executeQuery(sut: ApolloClient = fixture.getSut(), isSpanActive: Boolean = true, id: String = "83") = runBlocking { var tx: ITransaction? = null if (isSpanActive) { tx = SentryTracer(TransactionContext("op", "desc", TracesSamplingDecision(true)), fixture.hub) @@ -274,7 +274,7 @@ class SentryApollo3InterceptorTest { val coroutine = launch { try { - sut.query(LaunchDetailsQuery("83")).execute() + sut.query(LaunchDetailsQuery(id)).execute() } catch (e: ApolloException) { return@launch } diff --git a/sentry-apollo-3/src/test/java/io/sentry/apollo3/SentryApollo3InterceptorWithVariablesTest.kt b/sentry-apollo-3/src/test/java/io/sentry/apollo3/SentryApollo3InterceptorWithVariablesTest.kt index cab0be89159..3813811a01a 100644 --- a/sentry-apollo-3/src/test/java/io/sentry/apollo3/SentryApollo3InterceptorWithVariablesTest.kt +++ b/sentry-apollo-3/src/test/java/io/sentry/apollo3/SentryApollo3InterceptorWithVariablesTest.kt @@ -120,6 +120,21 @@ class SentryApollo3InterceptorWithVariablesTest { ) } + @Test + fun `handles non-ascii header values correctly`() { + executeQuery(id = "รก") + + verify(fixture.hub).captureTransaction( + check { + assertTransactionDetails(it) + assertEquals(SpanStatus.OK, it.spans.first().status) + }, + anyOrNull(), + anyOrNull(), + anyOrNull() + ) + } + @Test fun `adds breadcrumb when http calls succeeds`() { executeQuery(fixture.getSut()) @@ -153,7 +168,7 @@ class SentryApollo3InterceptorWithVariablesTest { } } - private fun executeQuery(sut: ApolloClient = fixture.getSut(), isSpanActive: Boolean = true) = runBlocking { + private fun executeQuery(sut: ApolloClient = fixture.getSut(), isSpanActive: Boolean = true, id: String = "83") = runBlocking { var tx: ITransaction? = null if (isSpanActive) { tx = SentryTracer(TransactionContext("op", "desc", TracesSamplingDecision(true)), fixture.hub) @@ -162,7 +177,7 @@ class SentryApollo3InterceptorWithVariablesTest { val coroutine = launch { try { - sut.query(LaunchDetailsQuery("83")).execute() + sut.query(LaunchDetailsQuery(id)).execute() } catch (e: ApolloException) { return@launch } From 1b0f67e66de363ab820f5c711c0fca9fa45f4805 Mon Sep 17 00:00:00 2001 From: Lukas Bloder Date: Thu, 11 May 2023 10:41:00 +0200 Subject: [PATCH 2/3] base64 encode internal headers --- .../sentry/apollo3/SentryApollo3HttpInterceptor.kt | 13 ++++++++++--- .../io/sentry/apollo3/SentryApollo3Interceptor.kt | 10 +++++++--- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/sentry-apollo-3/src/main/java/io/sentry/apollo3/SentryApollo3HttpInterceptor.kt b/sentry-apollo-3/src/main/java/io/sentry/apollo3/SentryApollo3HttpInterceptor.kt index 2c4c07cbdce..c6a2eb94755 100644 --- a/sentry-apollo-3/src/main/java/io/sentry/apollo3/SentryApollo3HttpInterceptor.kt +++ b/sentry-apollo-3/src/main/java/io/sentry/apollo3/SentryApollo3HttpInterceptor.kt @@ -20,6 +20,7 @@ import io.sentry.SpanStatus import io.sentry.TypeCheckHint import io.sentry.util.PropagationTargetsUtils import io.sentry.util.UrlUtils +import io.sentry.vendor.Base64 class SentryApollo3HttpInterceptor @JvmOverloads constructor(private val hub: IHub = HubAdapter.getInstance(), private val beforeSpan: BeforeSpanCallback? = null) : HttpInterceptor, IntegrationName { @@ -96,10 +97,14 @@ class SentryApollo3HttpInterceptor @JvmOverloads constructor(private val hub: IH val method = request.method val operationName = operationNameFromHeaders(request) - val operationType = request.valueForHeader(SENTRY_APOLLO_3_OPERATION_TYPE) + val operationType = request.valueForHeader(SENTRY_APOLLO_3_OPERATION_TYPE)?.let { + String(Base64.decode(it, Base64.DEFAULT)) + } val operation = if (operationType != null) "http.graphql.$operationType" else "http.graphql" val operationId = request.valueForHeader("X-APOLLO-OPERATION-ID") - val variables = request.valueForHeader(SENTRY_APOLLO_3_VARIABLES) + val variables = request.valueForHeader(SENTRY_APOLLO_3_VARIABLES)?.let { + String(Base64.decode(it, Base64.DEFAULT)) + } val description = "${operationType ?: method} ${operationName ?: urlDetails.urlOrFallback}" return activeSpan.startChild(operation, description).apply { @@ -116,7 +121,9 @@ class SentryApollo3HttpInterceptor @JvmOverloads constructor(private val hub: IH } private fun operationNameFromHeaders(request: HttpRequest): String? { - return request.valueForHeader(SENTRY_APOLLO_3_OPERATION_NAME) ?: request.valueForHeader("X-APOLLO-OPERATION-NAME") + return request.valueForHeader(SENTRY_APOLLO_3_OPERATION_NAME)?.let { + String(Base64.decode(it, Base64.DEFAULT)) + } ?: request.valueForHeader("X-APOLLO-OPERATION-NAME") } private fun HttpRequest.valueForHeader(key: String) = headers.firstOrNull { it.name == key }?.value diff --git a/sentry-apollo-3/src/main/java/io/sentry/apollo3/SentryApollo3Interceptor.kt b/sentry-apollo-3/src/main/java/io/sentry/apollo3/SentryApollo3Interceptor.kt index c0e0448e812..6633b7089ac 100644 --- a/sentry-apollo-3/src/main/java/io/sentry/apollo3/SentryApollo3Interceptor.kt +++ b/sentry-apollo-3/src/main/java/io/sentry/apollo3/SentryApollo3Interceptor.kt @@ -10,6 +10,10 @@ import com.apollographql.apollo3.api.Subscription import com.apollographql.apollo3.api.variables import com.apollographql.apollo3.interceptor.ApolloInterceptor import com.apollographql.apollo3.interceptor.ApolloInterceptorChain +import io.sentry.apollo3.SentryApollo3HttpInterceptor.Companion.SENTRY_APOLLO_3_OPERATION_NAME +import io.sentry.apollo3.SentryApollo3HttpInterceptor.Companion.SENTRY_APOLLO_3_OPERATION_TYPE +import io.sentry.apollo3.SentryApollo3HttpInterceptor.Companion.SENTRY_APOLLO_3_VARIABLES +import io.sentry.vendor.Base64 import kotlinx.coroutines.flow.Flow class SentryApollo3Interceptor : ApolloInterceptor { @@ -19,11 +23,11 @@ class SentryApollo3Interceptor : ApolloInterceptor { chain: ApolloInterceptorChain ): Flow> { val builder = request.newBuilder() - .addHttpHeader(SentryApollo3HttpInterceptor.SENTRY_APOLLO_3_OPERATION_TYPE, operationType(request)) - .addHttpHeader(SentryApollo3HttpInterceptor.SENTRY_APOLLO_3_OPERATION_NAME, request.operation.name()) + .addHttpHeader(SENTRY_APOLLO_3_OPERATION_TYPE, Base64.encodeToString(operationType(request).toByteArray(), Base64.DEFAULT)) + .addHttpHeader(SENTRY_APOLLO_3_OPERATION_NAME, Base64.encodeToString(request.operation.name().toByteArray(), Base64.DEFAULT)) request.scalarAdapters?.let { - builder.addHttpHeader(SentryApollo3HttpInterceptor.SENTRY_APOLLO_3_VARIABLES, request.operation.variables(it).valueMap.toString()) + builder.addHttpHeader(SENTRY_APOLLO_3_VARIABLES, Base64.encodeToString(request.operation.variables(it).valueMap.toString().toByteArray(), Base64.DEFAULT)) } return chain.proceed(builder.build()) } From 124b2640e31541a3bfc2cd85ac927cdcb16977ed Mon Sep 17 00:00:00 2001 From: Lukas Bloder Date: Thu, 11 May 2023 10:43:18 +0200 Subject: [PATCH 3/3] add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4054f490efa..8b82b30eedf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ - Android Profiler on calling thread ([#2691](https://github.com/getsentry/sentry-java/pull/2691)) - Use `configureScope` instead of `withScope` in `Hub.close()`. This ensures that the main scope releases the in-memory data when closing a hub instance. ([#2688](https://github.com/getsentry/sentry-java/pull/2688)) +- Base64 encode internal Apollo3 Headers ([#2707](https://github.com/getsentry/sentry-java/pull/2707)) ### Dependencies