使用OkHttp在通话期间访问基础TCP流

时间:2019-07-04 10:53:37

标签: okhttp

我已经为Docker API实现了一个客户端。

用于附加到容器输出的端点有点不寻常,因为您需要劫持基础TCP流,并使用该流从容器中读取输出。

API端点的文档:https://docs.docker.com/engine/api/v1.37/#operation/ContainerAttach(很遗憾,此端点的Web套接字版本为broken on OS X,所以我不能使用它。)

我一直在使用this code来访问直至和包括OkHttp v3.13.1的流:

class ConnectionHijacker : Interceptor {
    var source: BufferedSource? = null
    var sink: BufferedSink? = null

    override fun intercept(chain: Interceptor.Chain): Response {
        val connection = chain.connection() as RealConnection
        val streams = connection.newWebSocketStreams(connection.allocations.single().get())

        sink = streams.sink
        source = streams.source

        return chain.proceed(chain.request())
    }
}

这很好用。

但是,在最新版本中,OkHttp API发生了重大变化。像这样的东西可以在v1.13.1上运行,并可以在更高版本中进行编译,但是在流中却没有任何输出。

class ConnectionHijacker : Interceptor {
    var source: BufferedSource? = null
    var sink: BufferedSink? = null

    override fun intercept(chain: Interceptor.Chain): Response {
        val connection = chain.connection() as RealConnection

        sink = connection.sink
        source = connection.source

        return chain.proceed(chain.request())
    }

    private val RealConnection.sink: BufferedSink
        get() {
            val property = RealConnection::class.declaredMemberProperties.single { it.name == "sink" }
            property.isAccessible = true
            return property.get(this) as BufferedSink
        }

    private val RealConnection.source: BufferedSource
        get() {
            val property = RealConnection::class.declaredMemberProperties.single { it.name == "source" }
            property.isAccessible = true
            return property.get(this) as BufferedSource
        }
}

我意识到这是在另一种黑客之上的黑客,并且完全不受支持,但是有人对我如何实现这项工作有任何想法吗?

1 个答案:

答案 0 :(得分:1)

如果可以使用HTTP / 2,请查看RequestBody.isDuplex()。它可以让您访问请求输出和响应输入以完成您喜欢的事情。