Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit a44aac8

Browse files
Fix regression not allowing disabling CookieStore, close #1714
Motivation: Setting CookieStore to null in conf should be supported to disable it. Latest commit introduced a NPE regression. Modification: * Protect against null CookieStore * Make sure to decrement CookieStore ref count when AHC instance is closed. Result: No more NPE when CookieStore is null.
1 parent 45b4561 commit a44aac8

File tree

2 files changed

+85
-59
lines changed

2 files changed

+85
-59
lines changed

‎client/src/main/java/org/asynchttpclient/DefaultAsyncHttpClient.java‎

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import io.netty.util.concurrent.DefaultThreadFactory;
2424
import org.asynchttpclient.channel.ChannelPool;
2525
import org.asynchttpclient.cookie.CookieEvictionTask;
26+
import org.asynchttpclient.cookie.CookieStore;
2627
import org.asynchttpclient.filter.FilterContext;
2728
import org.asynchttpclient.filter.FilterException;
2829
import org.asynchttpclient.filter.RequestFilter;
@@ -91,21 +92,17 @@ public DefaultAsyncHttpClient(AsyncHttpClientConfig config) {
9192
channelManager = new ChannelManager(config, nettyTimer);
9293
requestSender = new NettyRequestSender(config, channelManager, nettyTimer, new AsyncHttpClientState(closed));
9394
channelManager.configureBootstraps(requestSender);
94-
boolean scheduleCookieEviction = false;
9595

96-
final int cookieStoreCount = config.getCookieStore().incrementAndGet();
97-
if (!allowStopNettyTimer) {
98-
if (cookieStoreCount == 1) {
99-
// If this is the first AHC instance for the shared (user-provided) netty timer.
100-
scheduleCookieEviction = true;
96+
CookieStore cookieStore = config.getCookieStore();
97+
if (cookieStore != null) {
98+
int cookieStoreCount = config.getCookieStore().incrementAndGet();
99+
if (
100+
allowStopNettyTimer // timer is not shared
101+
|| cookieStoreCount == 1 // this is the first AHC instance for the shared (user-provided) timer
102+
) {
103+
nettyTimer.newTimeout(new CookieEvictionTask(config.expiredCookieEvictionDelay(), cookieStore),
104+
config.expiredCookieEvictionDelay(), TimeUnit.MILLISECONDS);
101105
}
102-
} else {
103-
// If Timer is not shared.
104-
scheduleCookieEviction = true;
105-
}
106-
if (scheduleCookieEviction) {
107-
nettyTimer.newTimeout(new CookieEvictionTask(config.expiredCookieEvictionDelay(), config.getCookieStore()),
108-
config.expiredCookieEvictionDelay(), TimeUnit.MILLISECONDS);
109106
}
110107
}
111108

@@ -124,6 +121,10 @@ public void close() {
124121
} catch (Throwable t) {
125122
LOGGER.warn("Unexpected error on ChannelManager close", t);
126123
}
124+
CookieStore cookieStore = config.getCookieStore();
125+
if (cookieStore != null) {
126+
cookieStore.decrementAndGet();
127+
}
127128
if (allowStopNettyTimer) {
128129
try {
129130
nettyTimer.stop();
Lines changed: 71 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
package org.asynchttpclient;
22

33
import io.netty.util.Timer;
4-
import org.asynchttpclient.DefaultAsyncHttpClientConfig.Builder;
54
import org.asynchttpclient.cookie.CookieEvictionTask;
65
import org.asynchttpclient.cookie.CookieStore;
76
import org.asynchttpclient.cookie.ThreadSafeCookieStore;
87
import org.testng.annotations.Test;
98

10-
import java.io.Closeable;
119
import java.io.IOException;
1210
import java.util.concurrent.TimeUnit;
1311

12+
import static org.asynchttpclient.Dsl.*;
1413
import static org.mockito.ArgumentMatchers.any;
1514
import static org.mockito.ArgumentMatchers.anyLong;
1615
import static org.mockito.Mockito.*;
@@ -20,62 +19,88 @@ public class DefaultAsyncHttpClientTest {
2019

2120
@Test
2221
public void testWithSharedNettyTimerShouldScheduleCookieEvictionOnlyOnce() throws IOException {
23-
final Timer nettyTimerMock = mock(Timer.class);
24-
final CookieStore cookieStore = new ThreadSafeCookieStore();
25-
final DefaultAsyncHttpClientConfig config = new Builder().setNettyTimer(nettyTimerMock).setCookieStore(cookieStore).build();
26-
final AsyncHttpClient client1 = new DefaultAsyncHttpClient(config);
27-
final AsyncHttpClient client2 = new DefaultAsyncHttpClient(config);
28-
29-
assertEquals(cookieStore.count(), 2);
30-
verify(nettyTimerMock, times(1)).newTimeout(any(CookieEvictionTask.class), anyLong(), any(TimeUnit.class));
31-
32-
closeSilently(client1);
33-
closeSilently(client2);
22+
Timer nettyTimerMock = mock(Timer.class);
23+
CookieStore cookieStore = new ThreadSafeCookieStore();
24+
AsyncHttpClientConfig config = config().setNettyTimer(nettyTimerMock).setCookieStore(cookieStore).build();
25+
26+
try (AsyncHttpClient client1 = asyncHttpClient(config)) {
27+
try (AsyncHttpClient client2 = asyncHttpClient(config)) {
28+
assertEquals(cookieStore.count(), 2);
29+
verify(nettyTimerMock, times(1)).newTimeout(any(CookieEvictionTask.class), anyLong(), any(TimeUnit.class));
30+
}
31+
}
3432
}
3533

3634
@Test
3735
public void testWitDefaultConfigShouldScheduleCookieEvictionForEachAHC() throws IOException {
38-
final AsyncHttpClientConfig config1 = new DefaultAsyncHttpClientConfig.Builder().build();
39-
final DefaultAsyncHttpClient client1 = new DefaultAsyncHttpClient(config1);
36+
AsyncHttpClientConfig config1 = config().build();
37+
try (AsyncHttpClient client1 = asyncHttpClient(config1)) {
38+
AsyncHttpClientConfig config2 = config().build();
39+
try (AsyncHttpClient client2 = asyncHttpClient(config2)) {
40+
assertEquals(config1.getCookieStore().count(), 1);
41+
assertEquals(config2.getCookieStore().count(), 1);
42+
}
43+
}
44+
}
4045

41-
final AsyncHttpClientConfig config2 = new DefaultAsyncHttpClientConfig.Builder().build();
42-
final DefaultAsyncHttpClient client2 = new DefaultAsyncHttpClient(config2);
46+
@Test
47+
public void testWithSharedCookieStoreButNonSharedTimerShouldScheduleCookieEvictionForFirstAHC() throws IOException {
48+
CookieStore cookieStore = new ThreadSafeCookieStore();
49+
Timer nettyTimerMock1 = mock(Timer.class);
50+
AsyncHttpClientConfig config1 = config()
51+
.setCookieStore(cookieStore).setNettyTimer(nettyTimerMock1).build();
52+
53+
try (AsyncHttpClient client1 = asyncHttpClient(config1)) {
54+
Timer nettyTimerMock2 = mock(Timer.class);
55+
AsyncHttpClientConfig config2 = config()
56+
.setCookieStore(cookieStore).setNettyTimer(nettyTimerMock2).build();
57+
try (AsyncHttpClient client2 = asyncHttpClient(config2)) {
58+
assertEquals(config1.getCookieStore().count(), 2);
59+
verify(nettyTimerMock1, times(1)).newTimeout(any(CookieEvictionTask.class), anyLong(), any(TimeUnit.class));
60+
verify(nettyTimerMock2, never()).newTimeout(any(CookieEvictionTask.class), anyLong(), any(TimeUnit.class));
61+
}
62+
}
4363

44-
assertEquals(config1.getCookieStore().count(), 1);
45-
assertEquals(config2.getCookieStore().count(), 1);
64+
Timer nettyTimerMock3 = mock(Timer.class);
65+
AsyncHttpClientConfig config3 = config()
66+
.setCookieStore(cookieStore).setNettyTimer(nettyTimerMock3).build();
4667

47-
closeSilently(client1);
48-
closeSilently(client2);
68+
try (AsyncHttpClient client2 = asyncHttpClient(config3)) {
69+
assertEquals(config1.getCookieStore().count(), 1);
70+
verify(nettyTimerMock3, times(1)).newTimeout(any(CookieEvictionTask.class), anyLong(), any(TimeUnit.class));
71+
}
4972
}
5073

5174
@Test
52-
public void testWithSharedCookieStoreButNonSharedTimerShouldScheduleCookieEvictionForFirstAHC() throws IOException {
53-
final CookieStore cookieStore = new ThreadSafeCookieStore();
54-
final Timer nettyTimerMock1 = mock(Timer.class);
55-
final AsyncHttpClientConfig config1 = new DefaultAsyncHttpClientConfig.Builder()
56-
.setCookieStore(cookieStore).setNettyTimer(nettyTimerMock1).build();
57-
final DefaultAsyncHttpClient client1 = new DefaultAsyncHttpClient(config1);
58-
59-
final Timer nettyTimerMock2 = mock(Timer.class);
60-
final AsyncHttpClientConfig config2 = new DefaultAsyncHttpClientConfig.Builder()
61-
.setCookieStore(cookieStore).setNettyTimer(nettyTimerMock2).build();
62-
final DefaultAsyncHttpClient client2 = new DefaultAsyncHttpClient(config2);
63-
64-
assertEquals(config1.getCookieStore().count(), 2);
65-
verify(nettyTimerMock1, times(1)).newTimeout(any(CookieEvictionTask.class), anyLong(), any(TimeUnit.class));
66-
verify(nettyTimerMock2, never()).newTimeout(any(CookieEvictionTask.class), anyLong(), any(TimeUnit.class));
67-
68-
closeSilently(client1);
69-
closeSilently(client2);
75+
public void testWithSharedCookieStoreButNonSharedTimerShouldReScheduleCookieEvictionWhenFirstInstanceGetClosed() throws IOException {
76+
CookieStore cookieStore = new ThreadSafeCookieStore();
77+
Timer nettyTimerMock1 = mock(Timer.class);
78+
AsyncHttpClientConfig config1 = config()
79+
.setCookieStore(cookieStore).setNettyTimer(nettyTimerMock1).build();
80+
81+
try (AsyncHttpClient client1 = asyncHttpClient(config1)) {
82+
assertEquals(config1.getCookieStore().count(), 1);
83+
verify(nettyTimerMock1, times(1)).newTimeout(any(CookieEvictionTask.class), anyLong(), any(TimeUnit.class));
84+
}
85+
86+
assertEquals(config1.getCookieStore().count(), 0);
87+
88+
Timer nettyTimerMock2 = mock(Timer.class);
89+
AsyncHttpClientConfig config2 = config()
90+
.setCookieStore(cookieStore).setNettyTimer(nettyTimerMock2).build();
91+
92+
try (AsyncHttpClient client2 = asyncHttpClient(config2)) {
93+
assertEquals(config1.getCookieStore().count(), 1);
94+
verify(nettyTimerMock2, times(1)).newTimeout(any(CookieEvictionTask.class), anyLong(), any(TimeUnit.class));
95+
}
7096
}
7197

72-
private static void closeSilently(Closeable closeable) {
73-
if (closeable != null) {
74-
try {
75-
closeable.close();
76-
} catch (IOException e) {
77-
// swallow
78-
}
98+
@Test
99+
public void testDisablingCookieStore() throws IOException {
100+
AsyncHttpClientConfig config = config()
101+
.setCookieStore(null).build();
102+
try (AsyncHttpClient client = asyncHttpClient(config)) {
103+
//
79104
}
80105
}
81106
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /