1
0
mirror of https://github.com/square/okhttp.git synced 2026-01-15 20:56:41 +03:00

Merge pull request #3425 from square/dr.0623.event-docs

Add more detail to dns/secure event docs; confirm it with test cases.
This commit is contained in:
Jesse Wilson
2017-06-23 10:24:34 -04:00
committed by GitHub
2 changed files with 154 additions and 20 deletions

View File

@@ -24,6 +24,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Deque;
import java.util.List;
import okhttp3.internal.DoubleInetAddressDns;
import okhttp3.internal.SingleInetAddressDns;
import okhttp3.internal.tls.SslClient;
import okhttp3.mockwebserver.MockResponse;
@@ -34,6 +35,7 @@ import org.junit.Rule;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
@@ -44,12 +46,13 @@ public final class EventListenerTest {
@Rule public final MockWebServer server = new MockWebServer();
private OkHttpClient client;
private final SingleInetAddressDns singleDns = new SingleInetAddressDns();
private final RecordingEventListener listener = new RecordingEventListener();
private final SslClient sslClient = SslClient.localhost();
@Before public void setUp() {
client = new OkHttpClient.Builder()
.dns(new SingleInetAddressDns())
.dns(singleDns)
.eventListener(listener)
.build();
}
@@ -95,17 +98,70 @@ public final class EventListenerTest {
assertEquals(200, response.code());
response.body().close();
DnsStart dnsStart = listener.findNextEvent(DnsStart.class);
DnsStart dnsStart = listener.removeUpToEvent(DnsStart.class);
assertSame(call, dnsStart.call);
assertEquals("localhost", dnsStart.domainName);
DnsEnd dnsEnd = listener.findNextEvent(DnsEnd.class);
DnsEnd dnsEnd = listener.removeUpToEvent(DnsEnd.class);
assertSame(call, dnsEnd.call);
assertEquals("localhost", dnsEnd.domainName);
assertEquals(1, dnsEnd.inetAddressList.size());
assertNull(dnsEnd.throwable);
}
@Test public void noDnsLookupOnPooledConnection() throws IOException {
server.enqueue(new MockResponse());
server.enqueue(new MockResponse());
// Seed the pool.
Call call1 = client.newCall(new Request.Builder()
.url(server.url("/"))
.build());
Response response1 = call1.execute();
assertEquals(200, response1.code());
response1.body().close();
listener.clearAllEvents();
Call call2 = client.newCall(new Request.Builder()
.url(server.url("/"))
.build());
Response response2 = call2.execute();
assertEquals(200, response2.code());
response2.body().close();
List<Class<?>> recordedEvents = listener.recordedEventTypes();
assertFalse(recordedEvents.contains(DnsStart.class));
assertFalse(recordedEvents.contains(DnsEnd.class));
}
@Test public void multipleDnsLookupsForSingleCall() throws IOException {
server.enqueue(new MockResponse()
.setResponseCode(301)
.setHeader("Location", "http://www.fakeurl:" + server.getPort()));
server.enqueue(new MockResponse());
FakeDns dns = new FakeDns();
dns.set("fakeurl", singleDns.lookup(server.getHostName()));
dns.set("www.fakeurl", singleDns.lookup(server.getHostName()));
client = client.newBuilder()
.dns(dns)
.build();
Call call = client.newCall(new Request.Builder()
.url("http://fakeurl:" + server.getPort())
.build());
Response response = call.execute();
assertEquals(200, response.code());
response.body().close();
listener.removeUpToEvent(DnsStart.class);
listener.removeUpToEvent(DnsEnd.class);
listener.removeUpToEvent(DnsStart.class);
listener.removeUpToEvent(DnsEnd.class);
}
@Test public void failedDnsLookup() {
client = client.newBuilder()
.dns(new FakeDns())
@@ -119,9 +175,9 @@ public final class EventListenerTest {
} catch (IOException expected) {
}
listener.findNextEvent(DnsStart.class);
listener.removeUpToEvent(DnsStart.class);
DnsEnd dnsEnd = listener.findNextEvent(DnsEnd.class);
DnsEnd dnsEnd = listener.removeUpToEvent(DnsEnd.class);
assertSame(call, dnsEnd.call);
assertEquals("fakeurl", dnsEnd.domainName);
assertNull(dnsEnd.inetAddressList);
@@ -147,9 +203,9 @@ public final class EventListenerTest {
} catch (IOException expected) {
}
listener.findNextEvent(DnsStart.class);
listener.removeUpToEvent(DnsStart.class);
DnsEnd dnsEnd = listener.findNextEvent(DnsEnd.class);
DnsEnd dnsEnd = listener.removeUpToEvent(DnsEnd.class);
assertSame(call, dnsEnd.call);
assertEquals("fakeurl", dnsEnd.domainName);
assertNull(dnsEnd.inetAddressList);
@@ -167,10 +223,10 @@ public final class EventListenerTest {
assertEquals(200, response.code());
response.body().close();
SecureConnectStart secureStart = listener.findNextEvent(SecureConnectStart.class);
SecureConnectStart secureStart = listener.removeUpToEvent(SecureConnectStart.class);
assertSame(call, secureStart.call);
SecureConnectEnd secureEnd = listener.findNextEvent(SecureConnectEnd.class);
SecureConnectEnd secureEnd = listener.removeUpToEvent(SecureConnectEnd.class);
assertSame(call, secureEnd.call);
assertNotNull(secureEnd.handshake);
assertNull(secureEnd.throwable);
@@ -190,10 +246,10 @@ public final class EventListenerTest {
} catch (IOException expected) {
}
SecureConnectStart secureStart = listener.findNextEvent(SecureConnectStart.class);
SecureConnectStart secureStart = listener.removeUpToEvent(SecureConnectStart.class);
assertSame(call, secureStart.call);
SecureConnectEnd secureEnd = listener.findNextEvent(SecureConnectEnd.class);
SecureConnectEnd secureEnd = listener.removeUpToEvent(SecureConnectEnd.class);
assertSame(call, secureEnd.call);
assertNull(secureEnd.handshake);
assertTrue(secureEnd.throwable instanceof IOException);
@@ -216,15 +272,70 @@ public final class EventListenerTest {
assertEquals(200, response.code());
response.body().close();
SecureConnectStart secureStart = listener.findNextEvent(SecureConnectStart.class);
SecureConnectStart secureStart = listener.removeUpToEvent(SecureConnectStart.class);
assertSame(call, secureStart.call);
SecureConnectEnd secureEnd = listener.findNextEvent(SecureConnectEnd.class);
SecureConnectEnd secureEnd = listener.removeUpToEvent(SecureConnectEnd.class);
assertSame(call, secureEnd.call);
assertNotNull(secureEnd.handshake);
assertNull(secureEnd.throwable);
}
@Test public void multipleSecureConnectsForSingleCall() throws IOException {
enableTls(false);
server.enqueue(new MockResponse()
.setSocketPolicy(SocketPolicy.FAIL_HANDSHAKE));
server.enqueue(new MockResponse());
client = client.newBuilder()
.dns(new DoubleInetAddressDns())
.build();
Call call = client.newCall(new Request.Builder()
.url(server.url("/"))
.build());
Response response = call.execute();
assertEquals(200, response.code());
response.body().close();
listener.removeUpToEvent(SecureConnectStart.class);
listener.removeUpToEvent(SecureConnectEnd.class);
listener.removeUpToEvent(SecureConnectStart.class);
listener.removeUpToEvent(SecureConnectEnd.class);
}
@Test public void noSecureConnectsOnPooledConnection() throws IOException {
enableTls(false);
server.enqueue(new MockResponse());
server.enqueue(new MockResponse());
client = client.newBuilder()
.dns(new DoubleInetAddressDns())
.build();
// Seed the pool.
Call call1 = client.newCall(new Request.Builder()
.url(server.url("/"))
.build());
Response response1 = call1.execute();
assertEquals(200, response1.code());
response1.body().close();
listener.clearAllEvents();
Call call2 = client.newCall(new Request.Builder()
.url(server.url("/"))
.build());
Response response2 = call2.execute();
assertEquals(200, response2.code());
response2.body().close();
List<Class<?>> recordedEvents = listener.recordedEventTypes();
assertFalse(recordedEvents.contains(SecureConnectStart.class));
assertFalse(recordedEvents.contains(SecureConnectEnd.class));
}
private void enableTls(boolean tunnelProxy) {
client = client.newBuilder()
.sslSocketFactory(sslClient.socketFactory, sslClient.trustManager)
@@ -280,14 +391,16 @@ public final class EventListenerTest {
static final class RecordingEventListener extends EventListener {
final Deque<Object> eventSequence = new ArrayDeque<>();
<T> T findNextEvent(Class<T> eventClass) {
/**
* Removes recorded events up to (and including) an event is found whose class equals
* {@code eventClass} and returns it.
*/
<T> T removeUpToEvent(Class<T> eventClass) {
Object event = eventSequence.poll();
while (event != null && !eventClass.isInstance(event)) {
event = eventSequence.poll();
}
if (event == null) {
fail("Expected event type: " + eventClass.getName());
}
if (event == null) throw new AssertionError();
return (T) event;
}
@@ -299,6 +412,10 @@ public final class EventListenerTest {
return eventTypes;
}
void clearAllEvents() {
eventSequence.clear();
}
@Override public void dnsStart(Call call, String domainName) {
eventSequence.offer(new DnsStart(call, domainName));
}

View File

@@ -34,13 +34,23 @@ public abstract class EventListener {
public void fetchStart(Call call) {
}
/** Invoked just prior to a DNS lookup. See {@link Dns#lookup(String)}. */
/**
* Invoked just prior to a DNS lookup. See {@link Dns#lookup(String)}.
*
* <p>This can be invoked more than 1 time for a single {@link Call}. For example, if the response
* to the {@link Call#request()} is a redirect to a different host.
*
* <p>If the {@link Call} is able to reuse an existing pooled connection, this method will not be
* invoked. See {@link ConnectionPool}.
*/
public void dnsStart(Call call, String domainName) {
}
/**
* Invoked immediately after a DNS lookup.
*
* <p>This method is always invoked after {@link #dnsStart(Call, String)}.
*
* <p>{@code inetAddressList} will be non-null and {@code throwable} will be null in the case of a
* successful DNS lookup.
*
@@ -57,7 +67,14 @@ public abstract class EventListener {
/**
* Invoked just prior to initiating a TLS connection.
*
* <p>If the {@link Call#request()} does not use TLS, this method will not be invoked.
* <p>This method is invoked if the following conditions are met:
* <ul>
* <li>The {@link Call#request()} requires TLS.</li>
* <li>No existing connection from the {@link ConnectionPool} can be reused.</li>
* </ul>
*
* <p>This can be invoked more than 1 time for a single {@link Call}. For example, if the response
* to the {@link Call#request()} is a redirect to a different address, or a connection is retried.
*/
public void secureConnectStart(Call call) {
}
@@ -65,7 +82,7 @@ public abstract class EventListener {
/**
* Invoked immediately after a TLS connection was attempted.
*
* <p>If the {@link Call#request()} does not use TLS, this method will not be invoked.
* <p>This method is always invoked after {@link #secureConnectStart(Call)}.
*
* <p>{@code handshake} will be non-null and {@code throwable} will be null in the case of a
* successful TLS connection.