2

I need to reproduce a bug with OkHttp so I can file a bug or ask a question on StackOverflow.

What is the simplest way to do this without a lot of setup?

I've read https://stackoverflow.com/help/how-to-ask and https://stackoverflow.com/help/minimal-reproducible-example but I'm still stuck? Help me!

Yuri Schimke
  • 12,435
  • 3
  • 35
  • 69

6 Answers6

2

Make a Kotlin script in Intellij, place it outside any source folders and make sure it ends with .main.kts filename.

example.main.kts

#!/usr/bin/env kotlin

@file:Repository("https://repo1.maven.org/maven2/")
@file:DependsOn("com.squareup.okhttp3:okhttp:4.9.0")
@file:CompilerOptions("-jvm-target", "1.8")

import okhttp3.OkHttpClient
import okhttp3.Request

val client = OkHttpClient()

val request = Request.Builder()
  .url("https://raw.github.com/square/okhttp/master/README.md")
  .build()

val body = client.newCall(request).execute().use {
  it.body!!.string()
}

println(body)

enter image description here

The #! line means it will run like a shell script also

$ ./example.main.kts          
OkHttp
======

See the [project website][okhttp] for documentation and APIs.
...
Yuri Schimke
  • 12,435
  • 3
  • 35
  • 69
1

If you need to see events (connection, request, response, caching) then use the EventListener.

https://square.github.io/okhttp/events/

In Gradle add a dependency on com.squareup.okhttp3:logging-interceptor:4.9.1

val client = OkHttpClient.Builder()
  .eventListenerFactory(LoggingEventListener.Factory())
  .build()
[0 ms] callStart: Request{method=GET, url=https://httpbin.org/get}
[11 ms] proxySelectStart: https://httpbin.org/
[12 ms] proxySelectEnd: [DIRECT]
[12 ms] dnsStart: httpbin.org
[55 ms] dnsEnd: [httpbin.org/54.147.165.197, httpbin.org/34.231.30.52, httpbin.org/54.91.118.50, httpbin.org/18.214.80.1, httpbin.org/54.166.163.67, httpbin.org/34.199.75.4]
[62 ms] connectStart: httpbin.org/54.147.165.197:443 DIRECT
[176 ms] secureConnectStart
[747 ms] secureConnectEnd: Handshake{tlsVersion=TLS_1_2 cipherSuite=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 peerCertificates=[CN=httpbin.org, CN=Amazon, OU=Server CA 1B, O=Amazon, C=US, CN=Amazon Root CA 1, O=Amazon, C=US] localCertificates=[]}
[765 ms] connectEnd: h2
[767 ms] connectionAcquired: Connection{httpbin.org:443, proxy=DIRECT hostAddress=httpbin.org/54.147.165.197:443 cipherSuite=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 protocol=h2}
[775 ms] requestHeadersStart
[783 ms] requestHeadersEnd
[993 ms] responseHeadersStart
[994 ms] responseHeadersEnd: Response{protocol=h2, code=200, message=, url=https://httpbin.org/get}
[999 ms] responseBodyStart
[999 ms] responseBodyEnd: byteCount=267
[999 ms] connectionReleased
[1000 ms] callEnd

[0 ms] callStart: Request{method=GET, url=https://httpbin.org/get}
[1 ms] connectionAcquired: Connection{httpbin.org:443, proxy=DIRECT hostAddress=httpbin.org/54.147.165.197:443 cipherSuite=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 protocol=h2}
[1 ms] requestHeadersStart
[1 ms] requestHeadersEnd
[98 ms] responseHeadersStart
[99 ms] responseHeadersEnd: Response{protocol=h2, code=200, message=, url=https://httpbin.org/get}
[99 ms] responseBodyStart
[99 ms] responseBodyEnd: byteCount=267
[99 ms] connectionReleased
[99 ms] callEnd

enter image description here

Yuri Schimke
  • 12,435
  • 3
  • 35
  • 69
1

If you need to see HTTP/2 Frames https://square.github.io/okhttp/debug_logging/

[2021-02-27 11:49:39] >> CONNECTION 505249202a20485454502f322e300d0a0d0a534d0d0a0d0a 
[2021-02-27 11:49:39] >> 0x00000000     6 SETTINGS       
[2021-02-27 11:49:39] >> 0x00000000     4 WINDOW_UPDATE  
[2021-02-27 11:49:39] << 0x00000000    18 SETTINGS       
[2021-02-27 11:49:39] << 0x00000000     4 WINDOW_UPDATE  
[2021-02-27 11:49:39] >> 0x00000003    33 HEADERS       END_STREAM|END_HEADERS 
[2021-02-27 11:49:39] >> 0x00000000     0 SETTINGS      ACK 
[2021-02-27 11:49:39] << 0x00000000     0 SETTINGS      ACK 
[2021-02-27 11:49:39] << 0x00000003   113 HEADERS       END_HEADERS 
[2021-02-27 11:49:39] << 0x00000003   267 DATA           
[2021-02-27 11:49:39] << 0x00000003     0 DATA          END_STREAM 

Follow up request

[2021-02-27 11:49:39] >> 0x00000005    10 HEADERS       END_STREAM|END_HEADERS 
[2021-02-27 11:49:39] << 0x00000005   113 HEADERS       END_HEADERS 
[2021-02-27 11:49:39] << 0x00000005   267 DATA           
[2021-02-27 11:49:39] << 0x00000005     0 DATA          END_STREAM 
Yuri Schimke
  • 12,435
  • 3
  • 35
  • 69
1

To create an Android instrumentation test run on device or the emulator, use a test like.

https://github.com/square/okhttp/blob/master/regression-test/src/androidTest/java/okhttp/regression/compare/OkHttpClientTest.java

@RunWith(AndroidJUnit4.class)
public class OkHttpClientTest {
  @Test public void get() throws IOException {
    OkHttpClient client = new OkHttpClient();
    Request request = new Request.Builder()
        .url("https://google.com/robots.txt")
        .build();
    try (Response response = client.newCall(request).execute()) {
      assertEquals(200, response.code());
      assertEquals(Protocol.HTTP_2, response.protocol());
    }
  }
}

Steps to run https://github.com/square/okhttp/tree/master/regression-test

Yuri Schimke
  • 12,435
  • 3
  • 35
  • 69
1

If you need to see network traffic via Wireshark for a JVM client (JSSE and TLSv1.2) https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/kt/WiresharkExample.kt

Copy WireSharkKeyLoggerListener to your test code to use in development.

This logs TLSv1.2 on a JVM (OpenJDK 11+) without any additional code. For TLSv1.3 an existing external tool is required.

Steps to run in your own code

  1. In your main method WireSharkListenerFactory.register()
  2. Create Listener factory val eventListenerFactory = WireSharkListenerFactory( logFile = File("/tmp/key.log"), tlsVersions = tlsVersions, launch = launch)
  3. Register with client.eventListenerFactory(eventListenerFactory)
  4. Launch wireshark if not done externally val process = eventListenerFactory.launchWireShark()
Capturing on 'Wi-Fi: en0'
Frame 20: 110 bytes on wire (880 bits), 110 bytes captured (880 bits) on interface en0, id 0
Ethernet II, Src: Google_fc:86:a2 (28:bd:89:fc:86:a2), Dst: Apple_6b:3b:e5 (f0:18:98:6b:3b:e5)
Internet Protocol Version 4, Src: 104.244.42.130, Dst: 192.168.86.23
Transmission Control Protocol, Src Port: 443, Dst Port: 57669, Seq: 3531, Ack: 383, Len: 44
Transport Layer Security
    TLSv1.2 Record Layer: Application Data Protocol: http2
        Content Type: Application Data (23)
        Version: TLS 1.2 (0x0303)
        Length: 39
        Encrypted Application Data: cfb509e24e2ca451923820e45c3943fa521e1f3f1a821fe3468c0a7294e1d07c0ab7ab90…
        [Application Data Protocol: http2]
HyperText Transfer Protocol 2
    Stream: SETTINGS, Stream ID: 0, Length 6
        Length: 6
        Type: SETTINGS (4)
        Flags: 0x00
            0000 000. = Unused: 0x00
            .... ...0 = ACK: False
        0... .... .... .... .... .... .... .... = Reserved: 0x0
        .000 0000 0000 0000 0000 0000 0000 0000 = Stream Identifier: 0
        Settings - Initial Windows size : 65536
            Settings Identifier: Initial Windows size (4)
            Initial Windows Size: 65536
...
HyperText Transfer Protocol 2
    Stream: HEADERS, Stream ID: 3, Length 53, GET /robots.txt?s=tw
        Length: 53
        Type: HEADERS (1)
        Flags: 0x05, End Headers, End Stream
            00.0 ..0. = Unused: 0x00
            ..0. .... = Priority: False
            .... 0... = Padded: False
            .... .1.. = End Headers: True
            .... ...1 = End Stream: True
        0... .... .... .... .... .... .... .... = Reserved: 0x0
        .000 0000 0000 0000 0000 0000 0000 0011 = Stream Identifier: 3
        [Pad Length: 0]
        Header Block Fragment: 82048c62c3c674a174f94ff88813e3418b1d665d3e0c9496c5c87a7f8750839bd9ab7a91…
        [Header Length: 166]
        [Header Count: 6]
        Header: :method: GET
            Name Length: 7
...

You will need to point Wireshark at your key log file

enter image description here

Yuri Schimke
  • 12,435
  • 3
  • 35
  • 69