Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -54,51 +54,56 @@ class AppTPBlockListInterceptorApiPlugin @Inject constructor(
moshi.adapter(Types.newParameterizedType(Map::class.java, String::class.java, String::class.java))
}
override fun intercept(chain: Chain): Response {
val request = chain.request().newBuilder()
val originalRequest = chain.request()

val tdsRequired = chain.request().tag(Invocation::class.java)
val tdsRequired = originalRequest.tag(Invocation::class.java)
?.method()
?.isAnnotationPresent(AppTPTdsRequired::class.java) == true

val shouldInterceptRequest = tdsRequired && runBlocking {
appTrackingProtection.isEnabled()
}

return if (shouldInterceptRequest) {
logcat { "[AppTP]: Intercepted AppTP TDS Request: ${chain.request()}" }
val activeExperiment = runBlocking {
inventory.activeAppTpTdsFlag()?.also {
it.enroll()
}
if (!shouldInterceptRequest) {
return chain.proceed(originalRequest)
}

logcat { "[AppTP]: Intercepted AppTP TDS Request: $originalRequest" }
val activeExperiment = runBlocking {
inventory.activeAppTpTdsFlag()?.also {
it.enroll()
}
logcat { "[AppTP]: Active experiment: ${activeExperiment?.featureName()}" }
logcat { "[AppTP]: Cohort: ${runBlocking { activeExperiment?.getCohort() }}" }
}
logcat { "[AppTP]: Active experiment: ${activeExperiment?.featureName()}" }
logcat { "[AppTP]: Cohort: ${runBlocking { activeExperiment?.getCohort() }}" }

if (activeExperiment == null) {
return chain.proceed(originalRequest)
}

activeExperiment?.let {
val config = activeExperiment.getSettings()?.let {
runCatching {
jsonAdapter.fromJson(it)
}.getOrDefault(emptyMap())
} ?: emptyMap()
val path = when {
runBlocking { activeExperiment.isEnrolledAndEnabled(TREATMENT) } -> config["treatmentUrl"]
runBlocking { activeExperiment.isEnrolledAndEnabled(CONTROL) } -> config["controlUrl"]
else -> config["nextUrl"]
} ?: return chain.proceed(request.build())
val newURL = "$APPTP_TDS_BASE_URL$path"
logcat { "[AppTP]: Rewrote TDS request URL to $newURL" }
chain.proceed(request.url(newURL).build()).also { response ->
if (!response.isSuccessful) {
pixel.appTPBlocklistExperimentDownloadFailure(
response.code,
activeExperiment.featureName().name,
runBlocking { activeExperiment.getCohort() }?.name.toString(),
)
}
}
} ?: chain.proceed(request.build())
} else {
chain.proceed(request.build())
val config = activeExperiment.getSettings()?.let {
runCatching {
jsonAdapter.fromJson(it)
}.getOrDefault(emptyMap())
} ?: emptyMap()

val path = when {
runBlocking { activeExperiment.isEnrolledAndEnabled(TREATMENT) } -> config["treatmentUrl"]
runBlocking { activeExperiment.isEnrolledAndEnabled(CONTROL) } -> config["controlUrl"]
else -> config["nextUrl"]
} ?: return chain.proceed(originalRequest)

val newURL = "$APPTP_TDS_BASE_URL$path"
logcat { "[AppTP]: Rewrote TDS request URL to $newURL" }

return chain.proceed(originalRequest.newBuilder().url(newURL).build()).also { response ->
if (!response.isSuccessful) {
pixel.appTPBlocklistExperimentDownloadFailure(
response.code,
activeExperiment.featureName().name,
runBlocking { activeExperiment.getCohort() }?.name.toString(),
)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,23 @@ class CohortPixelInterceptor @Inject constructor(
private val cohortStore: CohortStore,
) : PixelInterceptorPlugin, Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request().newBuilder()
val pixel = chain.request().url.pathSegments.last()
val originalRequest = chain.request()
val pixel = originalRequest.url.pathSegments.last()

val url = if (pixel.startsWith(PIXEL_PREFIX) && !EXCEPTIONS.any { exception -> pixel.startsWith(exception) }) {
// IF there is no cohort for ATP we just drop the pixel request
// ELSE we add the cohort param
cohortStore.getCohortStoredLocalDate()?.let {
chain.request().url.newBuilder().addQueryParameter(COHORT_PARAM, cohortCalculator.calculateCohortForDate(it)).build()
} ?: return dummyResponse(chain)
} else {
chain.request().url
if (!pixel.startsWith(PIXEL_PREFIX) || EXCEPTIONS.any { exception -> pixel.startsWith(exception) }) {
return chain.proceed(originalRequest)
}

return chain.proceed(request.url(url).build())
// IF there is no cohort for ATP we just drop the pixel request
val cohortDate = cohortStore.getCohortStoredLocalDate()
?: return dummyResponse(chain)

// ELSE we add the cohort param
val url = originalRequest.url.newBuilder()
.addQueryParameter(COHORT_PARAM, cohortCalculator.calculateCohortForDate(cohortDate))
.build()

return chain.proceed(originalRequest.newBuilder().url(url).build())
}

private fun dummyResponse(chain: Interceptor.Chain): Response {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,20 +51,28 @@ class PixelParamRemovalInterceptor @Inject constructor(
}

override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request().newBuilder()
val pixel = chain.request().url.pathSegments.last()
val url = chain.request().url.newBuilder().apply {
val atbs = pixels.filter { it.second.contains(ATB) }.map { it.first }
val versions = pixels.filter { it.second.contains(APP_VERSION) }.map { it.first }
if (atbs.any { pixel.startsWith(it) }) {
val originalRequest = chain.request()
val pixel = originalRequest.url.pathSegments.last()

val atbs = pixels.filter { it.second.contains(ATB) }.map { it.first }
val versions = pixels.filter { it.second.contains(APP_VERSION) }.map { it.first }
val shouldRemoveAtb = atbs.any { pixel.startsWith(it) }
val shouldRemoveVersion = versions.any { pixel.startsWith(it) }

if (!shouldRemoveAtb && !shouldRemoveVersion) {
return chain.proceed(originalRequest)
}

val url = originalRequest.url.newBuilder().apply {
if (shouldRemoveAtb) {
removeAllQueryParameters(AppUrl.ParamKey.ATB)
}
if (versions.any { pixel.startsWith(it) }) {
if (shouldRemoveVersion) {
removeAllQueryParameters(Pixel.PixelParameter.APP_VERSION)
}
}.build()

return chain.proceed(request.url(url).build())
return chain.proceed(originalRequest.newBuilder().url(url).build())
}

override fun getInterceptor(): Interceptor {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,21 @@ import okhttp3.Response
*/
class PixelReQueryInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
var url = chain.request().url
val request = chain.request().newBuilder()
val originalRequest = chain.request()
val originalUrlString = originalRequest.url.toUrl().toString()

url = url.toUrl().toString().replace("rq_0_android_${DeviceInfo.FormFactor.PHONE.description}", "rq_0").toHttpUrl()
url = url.toUrl().toString().replace("rq_0_android_${DeviceInfo.FormFactor.TABLET.description}", "rq_0").toHttpUrl()
url = url.toUrl().toString().replace("rq_1_android_${DeviceInfo.FormFactor.PHONE.description}", "rq_1").toHttpUrl()
url = url.toUrl().toString().replace("rq_1_android_${DeviceInfo.FormFactor.TABLET.description}", "rq_1").toHttpUrl()
val modifiedUrlString = originalUrlString
.replace("rq_0_android_${DeviceInfo.FormFactor.PHONE.description}", "rq_0")
.replace("rq_0_android_${DeviceInfo.FormFactor.TABLET.description}", "rq_0")
.replace("rq_1_android_${DeviceInfo.FormFactor.PHONE.description}", "rq_1")
.replace("rq_1_android_${DeviceInfo.FormFactor.TABLET.description}", "rq_1")

logcat { "Pixel interceptor: $url" }
if (modifiedUrlString == originalUrlString) {
return chain.proceed(originalRequest)
}

return chain.proceed(request.url(url).build())
logcat { "Pixel interceptor: $modifiedUrlString" }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now we see the log only if the interceptor modified the URL. I can move it up if we want to see the log for all intercepted requests, as it was before.


return chain.proceed(originalRequest.newBuilder().url(modifiedUrlString.toHttpUrl()).build())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,33 +38,42 @@ class CampaignPixelParamsAdditionInterceptor @Inject constructor(
private val additionalPixelParamsDataStore: AdditionalPixelParamsDataStore,
) : Interceptor, PixelInterceptorPlugin {
override fun intercept(chain: Chain): Response {
val request = chain.request().newBuilder()
val url = chain.request().url.newBuilder()
val originalRequest = chain.request()

if (additionalPixelParamsFeature.self().isEnabled()) {
val queryParamsString = chain.request().url.query
if (queryParamsString != null) {
val pixel = chain.request().url.pathSegments.last()
pixelsPlugin.getPlugins().forEach { plugin ->
if (plugin.names().any { pixel.startsWith(it) }) {
val queryParams = queryParamsString.toParamsMap()
if (plugin.isEligible(queryParams)) {
runBlocking {
/**
* The additional parameters being collected only apply to a single promotion about a DuckDuckGo product.
* The parameters are temporary, collected in aggregate, and anonymous.
*/
additionalPixelParamsGenerator.generateAdditionalParams().forEach { (key, value) ->
url.addQueryParameter(key, value)
}
}
if (!additionalPixelParamsFeature.self().isEnabled()) {
return chain.proceed(originalRequest)
}

val queryParamsString = originalRequest.url.query
?: return chain.proceed(originalRequest)

val pixel = originalRequest.url.pathSegments.last()
var paramsAdded = false
val urlBuilder = originalRequest.url.newBuilder()

pixelsPlugin.getPlugins().forEach { plugin ->
if (plugin.names().any { pixel.startsWith(it) }) {
val queryParams = queryParamsString.toParamsMap()
if (plugin.isEligible(queryParams)) {
runBlocking {
/**
* The additional parameters being collected only apply to a single promotion about a DuckDuckGo product.
* The parameters are temporary, collected in aggregate, and anonymous.
*/
additionalPixelParamsGenerator.generateAdditionalParams().forEach { (key, value) ->
urlBuilder.addQueryParameter(key, value)
paramsAdded = true
}
}
}
}
}

return chain.proceed(request.url(url.build()).build())
if (!paramsAdded) {
return chain.proceed(originalRequest)
}

return chain.proceed(originalRequest.newBuilder().url(urlBuilder.build()).build())
}

private fun CampaignPixelParamsAdditionPlugin.isEligible(queryParams: Map<String, String>): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,36 +50,40 @@ class BlockListInterceptorApiPlugin @Inject constructor(
moshi.adapter(Types.newParameterizedType(Map::class.java, String::class.java, String::class.java))
}
override fun intercept(chain: Chain): Response {
val request = chain.request().newBuilder()
val originalRequest = chain.request()

val tdsRequired = chain.request().tag(Invocation::class.java)
val tdsRequired = originalRequest.tag(Invocation::class.java)
?.method()
?.isAnnotationPresent(TdsRequired::class.java) == true

return if (tdsRequired) {
val activeExperiment = runBlocking {
inventory.activeTdsFlag().also { it?.enroll() }
}
if (!tdsRequired) {
return chain.proceed(originalRequest)
}

activeExperiment?.let {
val config = activeExperiment.getSettings()?.let {
runCatching {
jsonAdapter.fromJson(it)
}.getOrDefault(emptyMap())
} ?: emptyMap()
val path = when {
runBlocking { activeExperiment.isEnrolledAndEnabled(TREATMENT) } -> config["treatmentUrl"]
runBlocking { activeExperiment.isEnrolledAndEnabled(CONTROL) } -> config["controlUrl"]
else -> config["nextUrl"]
} ?: return chain.proceed(request.build())
chain.proceed(request.url("$TDS_BASE_URL$path").build()).also { response ->
if (!response.isSuccessful) {
pixel.fire(BLOCKLIST_TDS_FAILURE, mapOf("code" to response.code.toString()))
}
}
} ?: chain.proceed(request.build())
} else {
chain.proceed(request.build())
val activeExperiment = runBlocking {
inventory.activeTdsFlag().also { it?.enroll() }
}

if (activeExperiment == null) {
return chain.proceed(originalRequest)
}

val config = activeExperiment.getSettings()?.let {
runCatching {
jsonAdapter.fromJson(it)
}.getOrDefault(emptyMap())
} ?: emptyMap()

val path = when {
runBlocking { activeExperiment.isEnrolledAndEnabled(TREATMENT) } -> config["treatmentUrl"]
runBlocking { activeExperiment.isEnrolledAndEnabled(CONTROL) } -> config["controlUrl"]
else -> config["nextUrl"]
} ?: return chain.proceed(originalRequest)

return chain.proceed(originalRequest.newBuilder().url("$TDS_BASE_URL$path").build()).also { response ->
if (!response.isSuccessful) {
pixel.fire(BLOCKLIST_TDS_FAILURE, mapOf("code" to response.code.toString()))
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,21 @@ import javax.inject.Inject
class AttributedMetricPixelInterceptor @Inject constructor() : Interceptor, PixelInterceptorPlugin {

override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request().newBuilder()
var url = chain.request().url
val pixel = chain.request().url.pathSegments.last()
if (pixel.startsWith(ATTRIBUTED_METRICS_PIXEL_PREFIX)) {
url = url.toUrl().toString().replace("android_${DeviceInfo.FormFactor.PHONE.description}", "android").toHttpUrl()
logcat(tag = "AttributedMetrics") {
"Pixel renamed to: $url"
}
val originalRequest = chain.request()
val pixel = originalRequest.url.pathSegments.last()

if (!pixel.startsWith(ATTRIBUTED_METRICS_PIXEL_PREFIX)) {
return chain.proceed(originalRequest)
}

val url = originalRequest.url.toUrl().toString()
.replace("android_${DeviceInfo.FormFactor.PHONE.description}", "android")
.toHttpUrl()
logcat(tag = "AttributedMetrics") {
"Pixel renamed to: $url"
}
return chain.proceed(request.url(url).build())

return chain.proceed(originalRequest.newBuilder().url(url).build())
}

override fun getInterceptor() = this
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,19 @@ class MetricPixelInterceptor @Inject constructor(
private val pixelStore: MetricsPixelStore,
) : PixelInterceptorPlugin, Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request().newBuilder()
val pixel = chain.request().url.pathSegments.last()
val originalRequest = chain.request()
val pixel = originalRequest.url.pathSegments.last()

// If not a metrics pixel, proceed
if (!pixel.startsWith(METRICS_PIXEL_PREFIX)) return chain.proceed(request.build())
if (!pixel.startsWith(METRICS_PIXEL_PREFIX)) {
return chain.proceed(originalRequest)
}

// If one of the parameters doesn't exist or is empty, drop request
val metricName = chain.request().url.queryParameter("metric")
val value = chain.request().url.queryParameter("value")
val conversionWindowDays = chain.request().url.queryParameter("conversionWindowDays")
val enrollmentDate = chain.request().url.queryParameter("enrollmentDate")
val metricName = originalRequest.url.queryParameter("metric")
val value = originalRequest.url.queryParameter("value")
val conversionWindowDays = originalRequest.url.queryParameter("conversionWindowDays")
val enrollmentDate = originalRequest.url.queryParameter("enrollmentDate")

if (metricName.isNullOrEmpty() || value.isNullOrEmpty() || conversionWindowDays.isNullOrEmpty() || enrollmentDate.isNullOrEmpty()) {
return dummyResponse(chain)
Expand Down Expand Up @@ -96,7 +98,7 @@ class MetricPixelInterceptor @Inject constructor(
// If inside conversion window, proceed, if not drop
val diffDays = daysBetweenTodayAnd(enrollmentDate)
return if (diffDays in lowerWindow..upperWindow) {
chain.proceed(request.build()).also { pixelStore.storePixelTag(tag) }
chain.proceed(originalRequest).also { pixelStore.storePixelTag(tag) }
} else {
dummyResponse(chain)
}
Expand Down
Loading
Loading