-
-
Notifications
You must be signed in to change notification settings - Fork 31
/
ResponseWithInterceptorChainMethodVisitor.kt
95 lines (83 loc) · 3.12 KB
/
ResponseWithInterceptorChainMethodVisitor.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package io.sentry.android.gradle.instrumentation.okhttp.visitor
import io.sentry.android.gradle.instrumentation.util.Types
import org.objectweb.asm.Label
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes
import org.objectweb.asm.commons.GeneratorAdapter
import org.objectweb.asm.commons.Method
class ResponseWithInterceptorChainMethodVisitor(
api: Int,
private val originalVisitor: MethodVisitor,
access: Int,
name: String?,
descriptor: String?
) : GeneratorAdapter(api, originalVisitor, access, name, descriptor) {
private var shouldInstrument = false
override fun visitMethodInsn(
opcode: Int,
owner: String?,
name: String?,
descriptor: String?,
isInterface: Boolean
) {
if (opcode == Opcodes.INVOKEVIRTUAL &&
owner == "okhttp3/OkHttpClient" &&
name == "interceptors"
) {
shouldInstrument = true
}
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface)
}
override fun visitInsn(opcode: Int) {
super.visitInsn(opcode)
if (opcode == Opcodes.POP && shouldInstrument) {
visitAddSentryInterceptor()
shouldInstrument = false
}
}
/*
Roughly constructing this, but in Java:
if (interceptors.find { it is SentryOkHttpInterceptor } != null) {
interceptors += SentryOkHttpInterceptor()
}
*/
private fun MethodVisitor.visitAddSentryInterceptor() {
originalVisitor.visitVarInsn(Opcodes.ALOAD, 1) // interceptors list
checkCast(Types.ITERABLE)
invokeInterface(Types.ITERABLE, Method.getMethod("java.util.Iterator iterator ()"))
val iteratorIndex = newLocal(Types.ITERATOR)
storeLocal(iteratorIndex)
val whileLabel = Label()
val endWhileLabel = Label()
visitLabel(whileLabel)
loadLocal(iteratorIndex)
invokeInterface(Types.ITERATOR, Method.getMethod("boolean hasNext ()"))
ifZCmp(EQ, endWhileLabel)
loadLocal(iteratorIndex)
invokeInterface(Types.ITERATOR, Method.getMethod("Object next ()"))
val interceptorIndex = newLocal(Types.OBJECT)
storeLocal(interceptorIndex)
loadLocal(interceptorIndex)
checkCast(Types.OKHTTP_INTERCEPTOR)
instanceOf(Types.SENTRY_OKHTTP_INTERCEPTOR)
ifZCmp(EQ, whileLabel)
loadLocal(interceptorIndex)
val ifLabel = Label()
goTo(ifLabel)
visitLabel(endWhileLabel)
originalVisitor.visitInsn(Opcodes.ACONST_NULL)
visitLabel(ifLabel)
val originalMethodLabel = Label()
ifNonNull(originalMethodLabel)
originalVisitor.visitVarInsn(Opcodes.ALOAD, 1)
checkCast(Types.COLLECTION)
newInstance(Types.SENTRY_OKHTTP_INTERCEPTOR)
dup()
val sentryOkHttpCtor = Method.getMethod("void <init> ()")
invokeConstructor(Types.SENTRY_OKHTTP_INTERCEPTOR, sentryOkHttpCtor)
val addInterceptor = Method.getMethod("boolean add (Object)")
invokeInterface(Types.COLLECTION, addInterceptor)
pop()
visitLabel(originalMethodLabel)
}
}