flipper83
flipper83

Reputation: 819

Problems after override SocketFactory with OkHttp

I was having troubles with https request after update my app to api 21. After a deep code review I found a funny bug.

My app has been compiled with api-21 now, and this api has a new version of okHttp inside the sdk, version 2.2.0. The old version of the app used the version of okHttp 2.0.0.

With the version 2.2.0 I have an exception when I try open a new https request. the exception is:

java.net.SocketException: Unconnected sockets not implemented
        at javax.net.SocketFactory.createSocket(SocketFactory.java:64)
        at com.squareup.okhttp.Connection.connect(Connection.java:144)
        at com.squareup.okhttp.Connection.connectAndSetOwner(Connection.java:169)
        at com.squareup.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:119)
        at com.squareup.okhttp.internal.http.RouteSelector.next(RouteSelector.java:134)
        at com.squareup.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:314)
        at com.squareup.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:237)
        at com.squareup.okhttp.Call.getResponse(Call.java:233)
        at com.squareup.okhttp.Call.execute(Call.java:84) 

The problem is okHttp changed the way that Connection class works on version 2.1.0. On version 2.0.0 the connection create a new plain Socket directly but know the request this socket to the socket factory this socket will be upgrade to a TLS. The change is:

socket = route.address.socketFactory.createSocket();

My problem is that I have overrited the socketFactory for NotHttpSocketFactory, and this implementation does nothing (it's ok, you want remove http connections) and the method createSocket(), has not been overrited. I dont like allow http requests.

And I override the SocketFactory.

client.setSocketFactory(new BlackphoneStubSocketFactory());

I don't understand why I need a plain socket, with I'm creating a https requests. Is this necessary? I can override the method createSocket() and return an empty socket, but it is necessary or it is a bug on OkHttp.

Upvotes: 4

Views: 3886

Answers (2)

tmm1
tmm1

Reputation: 2115

Make sure that you define createSocket() on your custom factory.

val httpClient = OkHttpClient.Builder()
    .connectTimeout(5, TimeUnit.SECONDS)
    .retryOnConnectionFailure(false)
    .socketFactory(object: SocketFactory() {
        val factory = SocketFactory.getDefault()

        override fun createSocket(): Socket {
            return wrap(factory.createSocket())
        }

        override fun createSocket(p0: String?, p1: Int): Socket {
            return wrap(factory.createSocket(p0, p1))
        }

        override fun createSocket(p0: InetAddress?, p1: Int): Socket {
            return wrap(factory.createSocket(p0, p1))
        }

        override fun createSocket(p0: String?, p1: Int, p2: InetAddress?, p3: Int): Socket {
            return wrap(factory.createSocket(p0, p1, p2, p3))
        }

        override fun createSocket(p0: InetAddress?, p1: Int, p2: InetAddress?, p3: Int): Socket {
            return wrap(factory.createSocket(p0, p1, p2, p3))
        }

        private fun wrap(s: Socket): Socket {
            s.receiveBufferSize = 32*1024*1024
            return s
        }
    })
    .build()

Upvotes: 2

Jesse Wilson
Jesse Wilson

Reputation: 40623

If you want to do this with OkHttp 2.2, use ConnectionSpec to disable plaintext connections. For example:

client.setConnectionSpecs(Collections.singletonList(ConnectionSpec.MODERN_TLS));  

This will drop support for cleartext connections, and also TLS fallbacks.

Upvotes: 0

Related Questions