Skip to content

Commit

Permalink
Merge branch 'develop' into release
Browse files Browse the repository at this point in the history
  • Loading branch information
vbuberen committed Jan 25, 2020
2 parents 7a024d3 + 37edfd1 commit ab39615
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 70 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
# Change Log

## Version 3.1.1 *(2020-01-25)*

This is hot-fix release to fix issue introduced in `3.1.0`.

### Summary of Changes

- Fixed an [issue](https://github.com/ChuckerTeam/chucker/issues/203) introduced in 3.1.0 where some of response bodies were shown as `null` and their sizes were 0 bytes.

## Version 3.1.0 *(2020-01-24)*

### This version shouldn't be used as dependency due to [#203](https://github.com/ChuckerTeam/chucker/issues/203). Use 3.1.1 instead.

This is a new minor release of Chucker. Please note that this minor release contains multiple new features (see below) as well as multiple bugfixes.

### Summary of Changes
Expand Down
32 changes: 11 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ repositories {

```groovy
dependencies {
debugImplementation "com.github.ChuckerTeam.Chucker:library:3.0.1"
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:3.0.1"
debugImplementation "com.github.ChuckerTeam.Chucker:library:3.1.1"
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:3.1.1"
}
```

Expand All @@ -63,7 +63,7 @@ Don't forget to check the [changelog](CHANGELOG.md) to have a look at all the ch

* Compatible with **OkHTTP 4**
* **API >= 16** compatible
* Easy to integrate (just a 2 gradle implementation line).
* Easy to integrate (just 2 gradle `implementation` lines).
* Works **out of the box**, no customization needed.
* **Empty release artifact** 🧼 (no traces of Chucker in your final APK).
* Support for body text search with **highlighting** 🕵️‍♂️
Expand Down Expand Up @@ -94,9 +94,9 @@ val chuckerInterceptor = ChuckerInterceptor(
context = this,
// The previously created Collector
collector = chuckerCollector,
// The max body content length, after this responses will be truncated.
// The max body content length in bytes, after this responses will be truncated.
maxContentLength = 250000L,
// List of headers to obfuscate in the Chucker UI
// List of headers to replace with ** in the Chucker UI
headersToRedact = setOf("Auth-Token"))

// Don't forget to plug the ChuckerInterceptor inside the OkHttpClient
Expand All @@ -107,7 +107,7 @@ val client = OkHttpClient.Builder()

### Throwables ☄️

Chucker supports also collecting and displaying **Throwables** of your application. To inform Chucker that a `Throwable` was fired you need to call the `onError` method of the `ChuckerCollector` (you need to retain an instance of your collector):
Chucker can also collect and display **Throwables** of your application. To inform Chucker that a `Throwable` was fired you need to call the `onError` method of the `ChuckerCollector` (you need to retain an instance of your collector):

```kotlin
try {
Expand Down Expand Up @@ -176,9 +176,8 @@ We're offering support for Chucker on the [#chucker](https://kotlinlang.slack.co

Short `TODO` List for new contributors:

- [ ] Kotlinize classes inside the `.internal` package.
- [x] Have a empty state graphics/message for requests with no headers.
- [ ] Increment the test coverage.
- Increment the test coverage.
- [Issues marked as `Help wanted`](https://github.com/ChuckerTeam/chucker/labels/help%20wanted)

## Acknowledgments 🌸

Expand All @@ -191,18 +190,9 @@ Chucker is currently developed and maintained by the [ChuckerTeam](https://githu
- [@redwarp](https://github.com/redwarp)
- [@vbuberen](https://github.com/vbuberen)

### Contributors
### Thanks

Big thanks to our contributors ❤️ Please add your name here once you submit a PR.

- [Ashok Varma](https://github.com/Ashok-Varma) Clean up
- [Bernat Borrás Paronella](https://github.com/alorma) Redact headers + HTTP methods in notifications
- [Hafiz Waleed Hussain](https://github.com/Hafiz-Waleed-Hussain) Search highlight in response tab
- [Karol Wrótniak](https://github.com/koral--) Fix race condition + Application name retrieval
- [OlliZi](https://github.com/OlliZi) Support for images
- [Paul Hawke](https://github.com/psh) API Clean
- [Paul Woitaschek](https://github.com/PaulWoitaschek) Fix typo in API
- [SeungHun Choe](https://github.com/uOOOO) Fix memory leak
Big thanks to our contributors ❤️

### Libraries

Expand All @@ -215,7 +205,7 @@ Chucker uses the following open source libraries:
## License 📄

```
Copyright (C) 2018 Chucker Team.
Copyright (C) 2018-2020 Chucker Team.
Copyright (C) 2017 Jeff Gilfelt.
Licensed under the Apache License, Version 2.0 (the "License");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
package com.chuckerteam.chucker.api

import android.content.Context
import android.util.Log
import com.chuckerteam.chucker.api.Chucker.LOG_TAG
import com.chuckerteam.chucker.internal.data.entity.HttpTransaction
import com.chuckerteam.chucker.internal.support.IOUtils
import com.chuckerteam.chucker.internal.support.hasBody
import java.io.IOException
import java.nio.charset.Charset
import java.nio.charset.UnsupportedCharsetException
import okhttp3.Headers
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response
import okhttp3.ResponseBody
import okio.Buffer
import okio.BufferedSource
import okio.GzipSource

private const val MAX_BLOB_SIZE = 1000_000L

Expand Down Expand Up @@ -110,7 +107,7 @@ class ChuckerInterceptor @JvmOverloads constructor(
* Processes a [Response] and populates corresponding fields of a [HttpTransaction].
*/
private fun processResponse(response: Response, transaction: HttpTransaction) {
val responseBody = response.body()
val responseBody = response.body()!!
val responseEncodingIsSupported = io.bodyHasSupportedEncoding(response.headers().get(CONTENT_ENCODING))

transaction.apply {
Expand All @@ -125,8 +122,8 @@ class ChuckerInterceptor @JvmOverloads constructor(
responseCode = response.code()
responseMessage = response.message()

responseContentType = responseBody?.contentType()?.toString()
responseContentLength = responseBody?.contentLength() ?: 0L
responseContentType = responseBody.contentType()?.toString()
responseContentLength = responseBody.contentLength()

tookMs = (response.receivedResponseAtMillis() - response.sentRequestAtMillis())
}
Expand All @@ -139,32 +136,36 @@ class ChuckerInterceptor @JvmOverloads constructor(
/**
* Processes a [ResponseBody] and populates corresponding fields of a [HttpTransaction].
*/
private fun processResponseBody(response: Response, responseBody: ResponseBody?, transaction: HttpTransaction) {
getNativeSource(response)?.use { source ->
source.request(java.lang.Long.MAX_VALUE)
val buffer = source.buffer()
var charset: Charset = UTF8
val contentType = responseBody?.contentType()
if (contentType != null) {
try {
charset = contentType.charset(UTF8) ?: UTF8
} catch (e: UnsupportedCharsetException) {
return
}
private fun processResponseBody(response: Response, responseBody: ResponseBody, transaction: HttpTransaction) {
val contentType = responseBody.contentType()
val charset: Charset = contentType?.charset(UTF8) ?: UTF8
val contentLength = responseBody.contentLength()

val source = responseBody.source()
source.request(Long.MAX_VALUE) // Buffer the entire body.
var buffer = source.buffer()

if (io.bodyIsGzipped(response.headers()[CONTENT_ENCODING])) {
GzipSource(buffer.clone()).use { gzippedResponseBody ->
buffer = Buffer()
buffer.writeAll(gzippedResponseBody)
}
if (io.isPlaintext(buffer)) {
val content = io.readFromBuffer(buffer, charset, maxContentLength)
transaction.responseBody = content
} else {
transaction.isResponseBodyPlainText = false
}

if (io.isPlaintext(buffer)) {
transaction.isResponseBodyPlainText = true
if (contentLength != 0L) {
transaction.responseBody = buffer.clone().readString(charset)
}
} else {
transaction.isResponseBodyPlainText = false

val isImageContentType = (transaction.responseContentType?.contains(CONTENT_TYPE_IMAGE) == true)
val isImageContentType =
(contentType?.toString()?.contains(CONTENT_TYPE_IMAGE, ignoreCase = true) == true)

if (isImageContentType && buffer.size() < MAX_BLOB_SIZE) {
transaction.responseImageData = buffer.readByteArray()
}
if (isImageContentType && buffer.size() < MAX_BLOB_SIZE) {
transaction.responseImageData = buffer.readByteArray()
}
transaction.responseContentLength = buffer.size()
}
}

Expand All @@ -179,24 +180,6 @@ class ChuckerInterceptor @JvmOverloads constructor(
return builder.build()
}

/**
* Returns a [BufferedSource] of a [Response] and UnGzip it if necessary.
*/
@Throws(IOException::class)
private fun getNativeSource(response: Response): BufferedSource? {
if (io.bodyIsGzipped(response.headers().get(CONTENT_ENCODING))) {
val source = response.peekBody(maxContentLength).source()
if (source.buffer().size() < maxContentLength) {
return io.getNativeSource(source, true)
} else {
Log.w(LOG_TAG, "gzip encoded response was too long")
}
}
// Let's clone the response Buffer in order to don't cause an IllegalStateException: closed
// if others interceptors are manipulating the body (see #192).
return response.body()?.source()?.buffer()?.clone()
}

companion object {
private val UTF8 = Charset.forName("UTF-8")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,9 @@ internal class IOUtils(private val context: Context) {
contentEncoding.equals("identity", ignoreCase = true) ||
contentEncoding.equals("gzip", ignoreCase = true)

fun bodyIsGzipped(contentEncoding: String?) = contentEncoding?.equals("gzip", ignoreCase = true) ?: false
fun bodyIsGzipped(contentEncoding: String?) = CONTENT_ENCODING_GZIP.equals(contentEncoding, ignoreCase = true)

private companion object {
const val CONTENT_ENCODING_GZIP = "gzip"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ class HttpBinClient(
private val httpClient =
OkHttpClient.Builder()
// Add a ChuckerInterceptor instance to your OkHttp client
.addInterceptor(chuckerInterceptor)
.addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
.addInterceptor(chuckerInterceptor)
.build()

private val api: HttpBinApi by lazy {
Expand Down

0 comments on commit ab39615

Please sign in to comment.