Skip to content

Commit dd51c23

Browse files
authored
Create new handlers for every new request in GoogleCloudStorageService (#27339)
This commit changes the DefaultHttpRequestInitializer in order to make it create new HttpIOExceptionHandler and HttpUnsuccessfulResponseHandler for every new HTTP request instead of reusing the same two handlers for all requests. Closes #27092
1 parent 1caa5c8 commit dd51c23

File tree

2 files changed

+72
-24
lines changed

2 files changed

+72
-24
lines changed

plugins/repository-gcs/src/main/java/org/elasticsearch/repositories/gcs/GoogleCloudStorageService.java

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
2424
import com.google.api.client.http.HttpBackOffIOExceptionHandler;
2525
import com.google.api.client.http.HttpBackOffUnsuccessfulResponseHandler;
26-
import com.google.api.client.http.HttpIOExceptionHandler;
2726
import com.google.api.client.http.HttpRequest;
2827
import com.google.api.client.http.HttpRequestInitializer;
2928
import com.google.api.client.http.HttpUnsuccessfulResponseHandler;
@@ -34,9 +33,7 @@
3433
import com.google.api.services.storage.StorageScopes;
3534
import org.elasticsearch.ElasticsearchException;
3635
import org.elasticsearch.common.component.AbstractComponent;
37-
import org.elasticsearch.common.inject.Inject;
3836
import org.elasticsearch.common.settings.SecureSetting;
39-
import org.elasticsearch.common.settings.SecureString;
4037
import org.elasticsearch.common.settings.Setting;
4138
import org.elasticsearch.common.settings.Settings;
4239
import org.elasticsearch.common.unit.TimeValue;
@@ -46,8 +43,6 @@
4643
import java.io.IOException;
4744
import java.io.InputStream;
4845
import java.io.UncheckedIOException;
49-
import java.nio.file.Files;
50-
import java.nio.file.Path;
5146
import java.util.Collections;
5247
import java.util.HashMap;
5348
import java.util.Map;
@@ -76,16 +71,11 @@ Storage createClient(String clientName, String application,
7671
*/
7772
class InternalGoogleCloudStorageService extends AbstractComponent implements GoogleCloudStorageService {
7873

79-
private static final String DEFAULT = "_default_";
80-
81-
private final Environment environment;
82-
8374
/** Credentials identified by client name. */
8475
private final Map<String, GoogleCredential> credentials;
8576

8677
InternalGoogleCloudStorageService(Environment environment, Map<String, GoogleCredential> credentials) {
8778
super(environment.settings());
88-
this.environment = environment;
8979
this.credentials = credentials;
9080
}
9181

@@ -131,15 +121,11 @@ class DefaultHttpRequestInitializer implements HttpRequestInitializer {
131121
private final TimeValue connectTimeout;
132122
private final TimeValue readTimeout;
133123
private final GoogleCredential credential;
134-
private final HttpUnsuccessfulResponseHandler handler;
135-
private final HttpIOExceptionHandler ioHandler;
136124

137125
DefaultHttpRequestInitializer(GoogleCredential credential, TimeValue connectTimeout, TimeValue readTimeout) {
138126
this.credential = credential;
139127
this.connectTimeout = connectTimeout;
140128
this.readTimeout = readTimeout;
141-
this.handler = new HttpBackOffUnsuccessfulResponseHandler(newBackOff());
142-
this.ioHandler = new HttpBackOffIOExceptionHandler(newBackOff());
143129
}
144130

145131
@Override
@@ -151,13 +137,14 @@ public void initialize(HttpRequest request) throws IOException {
151137
request.setReadTimeout((int) readTimeout.millis());
152138
}
153139

154-
request.setIOExceptionHandler(ioHandler);
140+
request.setIOExceptionHandler(new HttpBackOffIOExceptionHandler(newBackOff()));
155141
request.setInterceptor(credential);
156142

143+
final HttpUnsuccessfulResponseHandler handler = new HttpBackOffUnsuccessfulResponseHandler(newBackOff());
157144
request.setUnsuccessfulResponseHandler((req, resp, supportsRetry) -> {
158-
// Let the credential handle the response. If it failed, we rely on our backoff handler
159-
return credential.handleResponse(req, resp, supportsRetry) || handler.handleResponse(req, resp, supportsRetry);
160-
}
145+
// Let the credential handle the response. If it failed, we rely on our backoff handler
146+
return credential.handleResponse(req, resp, supportsRetry) || handler.handleResponse(req, resp, supportsRetry);
147+
}
161148
);
162149
}
163150

plugins/repository-gcs/src/test/java/org/elasticsearch/repositories/gcs/GoogleCloudStorageServiceTests.java

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,36 @@
1919

2020
package org.elasticsearch.repositories.gcs;
2121

22-
import java.io.IOException;
23-
import java.io.InputStream;
24-
import java.util.Collections;
25-
import java.util.Map;
26-
2722
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
23+
import com.google.api.client.http.GenericUrl;
24+
import com.google.api.client.http.HttpIOExceptionHandler;
25+
import com.google.api.client.http.HttpRequest;
26+
import com.google.api.client.http.HttpRequestFactory;
27+
import com.google.api.client.http.HttpRequestInitializer;
28+
import com.google.api.client.http.HttpResponse;
29+
import com.google.api.client.http.HttpUnsuccessfulResponseHandler;
30+
import com.google.api.client.testing.http.MockHttpTransport;
2831
import org.elasticsearch.common.settings.Settings;
32+
import org.elasticsearch.common.unit.TimeValue;
2933
import org.elasticsearch.env.Environment;
3034
import org.elasticsearch.env.TestEnvironment;
3135
import org.elasticsearch.repositories.gcs.GoogleCloudStorageService.InternalGoogleCloudStorageService;
3236
import org.elasticsearch.test.ESTestCase;
3337

38+
import java.io.IOException;
39+
import java.io.InputStream;
40+
import java.util.Collections;
41+
import java.util.Map;
42+
43+
import static java.util.Collections.emptyMap;
44+
import static java.util.Collections.singletonMap;
45+
import static org.mockito.Matchers.any;
46+
import static org.mockito.Matchers.anyBoolean;
47+
import static org.mockito.Mockito.mock;
48+
import static org.mockito.Mockito.times;
49+
import static org.mockito.Mockito.verify;
50+
import static org.mockito.Mockito.when;
51+
3452
public class GoogleCloudStorageServiceTests extends ESTestCase {
3553

3654
private InputStream getDummyCredentialStream() throws IOException {
@@ -47,13 +65,56 @@ GoogleCredential getDefaultCredential() throws IOException {
4765
}
4866
};
4967
assertSame(cred, service.getCredential("default"));
68+
69+
service.new DefaultHttpRequestInitializer(cred, null, null);
5070
}
5171

5272
public void testClientCredential() throws Exception {
5373
GoogleCredential cred = GoogleCredential.fromStream(getDummyCredentialStream());
54-
Map<String, GoogleCredential> credentials = Collections.singletonMap("clientname", cred);
74+
Map<String, GoogleCredential> credentials = singletonMap("clientname", cred);
5575
Environment env = TestEnvironment.newEnvironment(Settings.builder().put("path.home", createTempDir()).build());
5676
InternalGoogleCloudStorageService service = new InternalGoogleCloudStorageService(env, credentials);
5777
assertSame(cred, service.getCredential("clientname"));
5878
}
79+
80+
/**
81+
* Test that the {@link InternalGoogleCloudStorageService.DefaultHttpRequestInitializer} attaches new instances
82+
* of {@link HttpIOExceptionHandler} and {@link HttpUnsuccessfulResponseHandler} for every HTTP requests.
83+
*/
84+
public void testDefaultHttpRequestInitializer() throws IOException {
85+
final Environment environment = mock(Environment.class);
86+
when(environment.settings()).thenReturn(Settings.EMPTY);
87+
88+
final GoogleCredential credential = mock(GoogleCredential.class);
89+
when(credential.handleResponse(any(HttpRequest.class), any(HttpResponse.class), anyBoolean())).thenReturn(false);
90+
91+
final TimeValue readTimeout = TimeValue.timeValueSeconds(randomIntBetween(1, 120));
92+
final TimeValue connectTimeout = TimeValue.timeValueSeconds(randomIntBetween(1, 120));
93+
94+
final InternalGoogleCloudStorageService service = new InternalGoogleCloudStorageService(environment, emptyMap());
95+
final HttpRequestInitializer initializer = service.new DefaultHttpRequestInitializer(credential, connectTimeout, readTimeout);
96+
final HttpRequestFactory requestFactory = new MockHttpTransport().createRequestFactory(initializer);
97+
98+
final HttpRequest request1 = requestFactory.buildGetRequest(new GenericUrl());
99+
assertEquals((int) connectTimeout.millis(), request1.getConnectTimeout());
100+
assertEquals((int) readTimeout.millis(), request1.getReadTimeout());
101+
assertSame(credential, request1.getInterceptor());
102+
assertNotNull(request1.getIOExceptionHandler());
103+
assertNotNull(request1.getUnsuccessfulResponseHandler());
104+
105+
final HttpRequest request2 = requestFactory.buildGetRequest(new GenericUrl());
106+
assertEquals((int) connectTimeout.millis(), request2.getConnectTimeout());
107+
assertEquals((int) readTimeout.millis(), request2.getReadTimeout());
108+
assertSame(request1.getInterceptor(), request2.getInterceptor());
109+
assertNotNull(request2.getIOExceptionHandler());
110+
assertNotSame(request1.getIOExceptionHandler(), request2.getIOExceptionHandler());
111+
assertNotNull(request2.getUnsuccessfulResponseHandler());
112+
assertNotSame(request1.getUnsuccessfulResponseHandler(), request2.getUnsuccessfulResponseHandler());
113+
114+
request1.getUnsuccessfulResponseHandler().handleResponse(null, null, false);
115+
verify(credential, times(1)).handleResponse(any(HttpRequest.class), any(HttpResponse.class), anyBoolean());
116+
117+
request2.getUnsuccessfulResponseHandler().handleResponse(null, null, false);
118+
verify(credential, times(2)).handleResponse(any(HttpRequest.class), any(HttpResponse.class), anyBoolean());
119+
}
59120
}

0 commit comments

Comments
 (0)