Skip to content

Commit

Permalink
Only rebuild response in OkHttp interceptor if we modify the body
Browse files Browse the repository at this point in the history
  • Loading branch information
bidetofevil committed Oct 30, 2023
1 parent 8cf8db4 commit 6be995f
Showing 1 changed file with 73 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,81 +40,69 @@ public class EmbraceOkHttp3NetworkInterceptor internal constructor(
) : Interceptor {
public constructor() : this(Embrace.getInstance(), Clock { System.currentTimeMillis() })

@Suppress("ComplexMethod")
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
// If the SDK has not started, don't do anything
val originalRequest: Request = chain.request()
if (!embrace.isStarted || embrace.internalInterface.isInternalNetworkCaptureDisabled()) {
return chain.proceed(originalRequest)
}
val offset = sdkClockOffset()

val networkSpanForwardingEnabled = embrace.internalInterface.isNetworkSpanForwardingEnabled()
var traceparent: String? = null
if (networkSpanForwardingEnabled && originalRequest.header(TRACEPARENT_HEADER_NAME) == null) {
traceparent = embrace.generateW3cTraceparent()
}
val request =
if (traceparent == null) originalRequest else originalRequest.newBuilder().header(TRACEPARENT_HEADER_NAME, traceparent).build()

// Take a snapshot of the difference in the system and SDK clocks and send the request along the chain
val offset = sdkClockOffset()
val networkResponse: Response = chain.proceed(request)
val responseBuilder: Response.Builder = networkResponse.newBuilder().request(request)
var contentLength: Long? = null
// Try to get the content length from the header
val contentLengthHeaderValue = networkResponse.header(CONTENT_LENGTH_HEADER_NAME)
if (contentLengthHeaderValue != null) {
try {
contentLength = contentLengthHeaderValue.toLong()
} catch (ex: Exception) {
// Ignore
}
}

// If we get the body for a server-sent events stream, then we will wait forever
val contentType = networkResponse.header(CONTENT_TYPE_HEADER_NAME)
// Get response and determine the size of the body
var contentLength: Long? = getContentLengthFromHeader(networkResponse)

// Tolerant of a charset specified in header,
// e.g. Content-Type: text/event-stream;charset=UTF-8
val serverSentEvent = contentType != null && contentType.startsWith(CONTENT_TYPE_EVENT_STREAM)
if (!serverSentEvent && contentLength == null) {
try {
val body = networkResponse.body
if (body != null) {
val source = body.source()
source.request(Long.MAX_VALUE)
contentLength = source.buffer.size
}
} catch (ex: Exception) {
// Ignore
}
if (contentLength == null) {
// If we get the body for a server-sent events stream, then we will wait forever
contentLength = getContentLengthFromBody(networkResponse, networkResponse.header(CONTENT_TYPE_HEADER_NAME))
}

if (contentLength == null) {
// Otherwise default to zero
// Set the content length to 0 if we can't determine it
contentLength = 0L
}
val shouldCaptureNetworkData = embrace.internalInterface.shouldCaptureNetworkBody(request.url.toString(), request.method)
if (shouldCaptureNetworkData &&
ENCODING_GZIP.equals(networkResponse.header(CONTENT_ENCODING_HEADER_NAME), ignoreCase = true) &&
networkResponse.promisesBody()
) {
val body = networkResponse.body
if (body != null) {
val strippedHeaders = networkResponse.headers.newBuilder()
.removeAll(CONTENT_ENCODING_HEADER_NAME)
.removeAll(CONTENT_LENGTH_HEADER_NAME)
.build()
val realResponseBody = RealResponseBody(
contentType,
-1L,
GzipSource(body.source()).buffer()
)
responseBuilder.headers(strippedHeaders)
responseBuilder.body(realResponseBody)
}
}
val response: Response = responseBuilder.build()

var response: Response = networkResponse
var networkCaptureData: NetworkCaptureData? = null
val shouldCaptureNetworkData = embrace.internalInterface.shouldCaptureNetworkBody(request.url.toString(), request.method)

// If we need to capture the network response body,
if (shouldCaptureNetworkData) {
if (ENCODING_GZIP.equals(networkResponse.header(CONTENT_ENCODING_HEADER_NAME), ignoreCase = true) &&
networkResponse.promisesBody()
) {
val body = networkResponse.body
if (body != null) {
val strippedHeaders = networkResponse.headers.newBuilder()
.removeAll(CONTENT_ENCODING_HEADER_NAME)
.removeAll(CONTENT_LENGTH_HEADER_NAME)
.build()
val realResponseBody = RealResponseBody(
networkResponse.header(CONTENT_TYPE_HEADER_NAME),
-1L,
GzipSource(body.source()).buffer()
)
val responseBuilder = networkResponse.newBuilder().request(request)
responseBuilder.headers(strippedHeaders)
responseBuilder.body(realResponseBody)
response = responseBuilder.build()
}
}

networkCaptureData = getNetworkCaptureData(request, response)
}

embrace.recordNetworkRequest(
EmbraceNetworkRequest.fromCompletedRequest(
EmbraceHttpPathOverride.getURLString(EmbraceOkHttp3PathOverrideRequest(request)),
Expand All @@ -132,6 +120,40 @@ public class EmbraceOkHttp3NetworkInterceptor internal constructor(
return response
}

private fun getContentLengthFromHeader(networkResponse: Response): Long? {
var contentLength: Long? = null
val contentLengthHeaderValue = networkResponse.header(CONTENT_LENGTH_HEADER_NAME)
if (contentLengthHeaderValue != null) {
try {
contentLength = contentLengthHeaderValue.toLong()
} catch (ex: Exception) {
// Ignore
}
}
return contentLength
}

private fun getContentLengthFromBody(networkResponse: Response, contentType: String?): Long? {
var contentLength: Long? = null

// Tolerant of a charset specified in header, e.g. Content-Type: text/event-stream;charset=UTF-8
val serverSentEvent = contentType != null && contentType.startsWith(CONTENT_TYPE_EVENT_STREAM)
if (!serverSentEvent) {
try {
val body = networkResponse.body
if (body != null) {
val source = body.source()
source.request(Long.MAX_VALUE)
contentLength = source.buffer.size
}
} catch (ex: Exception) {
// Ignore
}
}

return contentLength
}

private fun getNetworkCaptureData(request: Request, response: Response): NetworkCaptureData {
var requestHeaders: Map<String, String>? = null
var requestQueryParams: String? = null
Expand Down

0 comments on commit 6be995f

Please sign in to comment.