Skip to content

Commit

Permalink
Merge 124b264 into e96a1b7
Browse files Browse the repository at this point in the history
  • Loading branch information
lbloder authored May 11, 2023
2 parents e96a1b7 + 124b264 commit d9bd3b7
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 10 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -19,11 +23,11 @@ class SentryApollo3Interceptor : ApolloInterceptor {
chain: ApolloInterceptorChain
): Flow<ApolloResponse<D>> {
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())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<TraceContext>(),
anyOrNull(),
anyOrNull()
)
}

@Test
fun `adds breadcrumb when http calls succeeds`() {
executeQuery(fixture.getSut())
Expand Down Expand Up @@ -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)
Expand All @@ -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
}
Expand Down

0 comments on commit d9bd3b7

Please sign in to comment.