diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/entity/HttpTransaction.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/entity/HttpTransaction.kt
index 5d5921d4..742a81c4 100644
--- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/entity/HttpTransaction.kt
+++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/entity/HttpTransaction.kt
@@ -38,6 +38,7 @@ internal class HttpTransaction(
@ColumnInfo(name = "protocol") var protocol: String?,
@ColumnInfo(name = "method") var method: String?,
@ColumnInfo(name = "url") var url: String?,
+ @ColumnInfo(name = "hostIp") var hostIp: String?,
@ColumnInfo(name = "host") var host: String?,
@ColumnInfo(name = "path") var path: String?,
@ColumnInfo(name = "scheme") var scheme: String?,
@@ -70,6 +71,7 @@ internal class HttpTransaction(
protocol = null,
method = null,
url = null,
+ hostIp = null,
host = null,
path = null,
scheme = null,
@@ -317,6 +319,7 @@ internal class HttpTransaction(
(protocol == other.protocol) &&
(method == other.method) &&
(url == other.url) &&
+ (hostIp == other.hostIp) &&
(host == other.host) &&
(path == other.path) &&
(scheme == other.scheme) &&
diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/room/ChuckerDatabase.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/room/ChuckerDatabase.kt
index 43f5f29c..0e0c8d73 100644
--- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/room/ChuckerDatabase.kt
+++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/data/room/ChuckerDatabase.kt
@@ -6,7 +6,7 @@ import androidx.room.Room
import androidx.room.RoomDatabase
import com.chuckerteam.chucker.internal.data.entity.HttpTransaction
-@Database(entities = [HttpTransaction::class], version = 9, exportSchema = false)
+@Database(entities = [HttpTransaction::class], version = 10, exportSchema = false)
internal abstract class ChuckerDatabase : RoomDatabase() {
abstract fun transactionDao(): HttpTransactionDao
diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/support/ResponseExt.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/support/ResponseExt.kt
new file mode 100644
index 00000000..41d6471b
--- /dev/null
+++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/support/ResponseExt.kt
@@ -0,0 +1,17 @@
+package com.chuckerteam.chucker.internal.support
+
+import okio.BufferedSource
+import java.util.regex.Matcher
+import java.util.regex.Pattern
+
+private const val IP_REGEX = "(?:\\d{1,3}\\.){3}\\d{1,3}"
+
+public fun BufferedSource.getHostIp(): String? {
+ val body = readUtf8()
+ val pattern: Pattern = Pattern.compile(IP_REGEX)
+ val matcher: Matcher? = body.let { pattern.matcher(it) }
+ if (matcher?.find() == true) {
+ return matcher.group()
+ }
+ return null
+}
diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/support/ResponseProcessor.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/support/ResponseProcessor.kt
index 7a2c4cd9..72fead15 100644
--- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/support/ResponseProcessor.kt
+++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/support/ResponseProcessor.kt
@@ -43,6 +43,7 @@ internal class ResponseProcessor(
requestDate = response.sentRequestAtMillis
responseDate = response.receivedResponseAtMillis
protocol = response.protocol.toString()
+ hostIp = response.body?.source()?.getHostIp()
responseCode = response.code
responseMessage = response.message
diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/support/TransactionDetailsSharable.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/support/TransactionDetailsSharable.kt
index 388b4527..158f9cbb 100644
--- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/support/TransactionDetailsSharable.kt
+++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/support/TransactionDetailsSharable.kt
@@ -13,6 +13,7 @@ internal class TransactionDetailsSharable(
override fun toSharableContent(context: Context): Source =
Buffer().apply {
writeUtf8("${context.getString(R.string.chucker_url)}: ${transaction.getFormattedUrl(encodeUrls)}\n")
+ writeUtf8("${context.getString(R.string.chucker_host_ip)}: ${transaction.hostIp}\n")
writeUtf8("${context.getString(R.string.chucker_method)}: ${transaction.method}\n")
writeUtf8("${context.getString(R.string.chucker_protocol)}: ${transaction.protocol}\n")
writeUtf8("${context.getString(R.string.chucker_status)}: ${transaction.status}\n")
diff --git a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionOverviewFragment.kt b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionOverviewFragment.kt
index ae961c2b..f8619e11 100644
--- a/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionOverviewFragment.kt
+++ b/library/src/main/kotlin/com/chuckerteam/chucker/internal/ui/transaction/TransactionOverviewFragment.kt
@@ -64,6 +64,7 @@ internal class TransactionOverviewFragment : Fragment() {
) {
with(overviewBinding) {
url.text = transaction?.getFormattedUrl(encodeUrl)
+ hostIp.text = transaction?.hostIp
method.text = transaction?.method
protocol.text = transaction?.protocol
status.text = transaction?.status.toString()
diff --git a/library/src/main/res/layout/chucker_fragment_transaction_overview.xml b/library/src/main/res/layout/chucker_fragment_transaction_overview.xml
index b5644061..99c223c5 100644
--- a/library/src/main/res/layout/chucker_fragment_transaction_overview.xml
+++ b/library/src/main/res/layout/chucker_fragment_transaction_overview.xml
@@ -38,6 +38,27 @@
app:layout_constraintTop_toTopOf="parent"
tools:text="https://example.com/path/to/resource?here=might_be_really_long" />
+
+
+
+
+ app:layout_constraintTop_toBottomOf="@id/host_ip" />
Request
Response
URL
+ Host IP
Method
Protocol
Status
diff --git a/library/src/test/kotlin/com/chuckerteam/chucker/internal/data/entity/TransactionTestUtils.kt b/library/src/test/kotlin/com/chuckerteam/chucker/internal/data/entity/TransactionTestUtils.kt
index c4fe1a61..eeae2eb8 100644
--- a/library/src/test/kotlin/com/chuckerteam/chucker/internal/data/entity/TransactionTestUtils.kt
+++ b/library/src/test/kotlin/com/chuckerteam/chucker/internal/data/entity/TransactionTestUtils.kt
@@ -23,6 +23,7 @@ internal fun HttpTransaction.withResponseData(): HttpTransaction =
responseCode = 418 // I'm a teapot
responseDate = 321L
tookMs = 21L
+ hostIp = "192.168.1.1"
responseTlsVersion = randomString()
responseCipherSuite = randomString()
responsePayloadSize = 0L
diff --git a/library/src/test/kotlin/com/chuckerteam/chucker/internal/data/har/ResponseTest.kt b/library/src/test/kotlin/com/chuckerteam/chucker/internal/data/har/ResponseTest.kt
index 003b9111..b824c70b 100644
--- a/library/src/test/kotlin/com/chuckerteam/chucker/internal/data/har/ResponseTest.kt
+++ b/library/src/test/kotlin/com/chuckerteam/chucker/internal/data/har/ResponseTest.kt
@@ -1,8 +1,10 @@
package com.chuckerteam.chucker.internal.data.har
import com.chuckerteam.chucker.internal.data.har.log.entry.response.Content
+import com.chuckerteam.chucker.internal.support.getHostIp
import com.chuckerteam.chucker.util.HarTestUtils
import com.google.common.truth.Truth.assertThat
+import okhttp3.mockwebserver.MockResponse
import org.junit.Test
internal class ResponseTest {
@@ -48,4 +50,24 @@ internal class ResponseTest {
assertThat(response?.bodySize).isEqualTo(1000)
}
+
+ @Test
+ fun `host ip address from response successfully`() {
+ val body =
+ "{\"args\": {},\"origin\": \"192.168.1.1\", \"url\": \"https://httpbin.org/get\"}"
+ val response = MockResponse().setBody(body).setResponseCode(200)
+ val buffer = response.getBody()
+ val hostIp = buffer?.getHostIp()
+ assertThat(hostIp).isEqualTo("192.168.1.1")
+ }
+
+ @Test
+ fun `host ip address from response doesn't exist`() {
+ val body =
+ "{\"args\": {}, \"url\": \"https://httpbin.org/get\"}"
+ val response = MockResponse().setBody(body).setResponseCode(200)
+ val buffer = response.getBody()
+ val hostIp = buffer?.getHostIp()
+ assertThat(hostIp).isEqualTo(null)
+ }
}
diff --git a/library/src/test/kotlin/com/chuckerteam/chucker/internal/data/room/HttpTransactionDaoTest.kt b/library/src/test/kotlin/com/chuckerteam/chucker/internal/data/room/HttpTransactionDaoTest.kt
index 662c4fd0..1e04ea70 100644
--- a/library/src/test/kotlin/com/chuckerteam/chucker/internal/data/room/HttpTransactionDaoTest.kt
+++ b/library/src/test/kotlin/com/chuckerteam/chucker/internal/data/room/HttpTransactionDaoTest.kt
@@ -60,6 +60,7 @@ internal class HttpTransactionDaoTest {
assertThat(stringValue("responseHeaders")).isEqualTo(data.responseHeaders)
assertThat(stringValue("method")).isEqualTo(data.method)
assertThat(stringValue("url")).isEqualTo(data.url)
+ assertThat(stringValue("hostIp")).isEqualTo(data.hostIp)
assertThat(stringValue("host")).isEqualTo(data.host)
assertThat(stringValue("path")).isEqualTo(data.path)
assertThat(stringValue("scheme")).isEqualTo(data.scheme)
diff --git a/library/src/test/kotlin/com/chuckerteam/chucker/util/HarTestUtils.kt b/library/src/test/kotlin/com/chuckerteam/chucker/util/HarTestUtils.kt
index d98f9360..af03984a 100644
--- a/library/src/test/kotlin/com/chuckerteam/chucker/util/HarTestUtils.kt
+++ b/library/src/test/kotlin/com/chuckerteam/chucker/util/HarTestUtils.kt
@@ -29,6 +29,7 @@ internal object HarTestUtils {
protocol = "HTTP",
method = method,
url = "http://localhost:80/getUsers",
+ hostIp = "192.168.1.1",
host = "localhost",
path = "/getUsers",
scheme = "",
diff --git a/library/src/test/kotlin/com/chuckerteam/chucker/util/TestTransactionFactory.kt b/library/src/test/kotlin/com/chuckerteam/chucker/util/TestTransactionFactory.kt
index 6caa417c..f417d090 100644
--- a/library/src/test/kotlin/com/chuckerteam/chucker/util/TestTransactionFactory.kt
+++ b/library/src/test/kotlin/com/chuckerteam/chucker/util/TestTransactionFactory.kt
@@ -13,6 +13,7 @@ internal object TestTransactionFactory {
protocol = "HTTP",
method = method,
url = "http://localhost:80/getUsers",
+ hostIp = "192.168.1.1",
host = "localhost",
path = "/getUsers",
scheme = "",