mirror of
https://github.com/apache/jclouds.git
synced 2025-02-27 13:05:05 +00:00
jclouds was not properly retrying on an expect: 100-continue PUT request that requires re-athentication because of java protocol code
JCLOUDS-1179 This fix also addresses the same problem with other providers No currently working tests because of https://github.com/square/okhttp/issues/675 This is a common problem in other tools as well https://curl.haxx.se/mail/lib-2004-08/0002.html
This commit is contained in:
parent
b06795ebe4
commit
00f7ee0738
@ -255,6 +255,77 @@ public class ObjectApiMockTest extends BaseOpenStackMockTest<SwiftApi> {
|
||||
}
|
||||
}
|
||||
|
||||
public void testCreateWith401Retry() throws Exception {
|
||||
// TODO: requires upgrade to okhttp mockwebserver 3.6
|
||||
|
||||
MockWebServer server = mockOpenStackServer();
|
||||
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access.json"))));
|
||||
|
||||
// PUT 1 - establishes auth tokens
|
||||
// Respond to request
|
||||
// This part will work in mockwebserver 3.6+
|
||||
// server.enqueue(new MockResponse().setResponseCode(100).setStatus("Continue"));
|
||||
|
||||
// Finish request
|
||||
server.enqueue(addCommonHeaders(new MockResponse()
|
||||
.setResponseCode(201)
|
||||
.addHeader("ETag", "d9f5eb4bba4e2f2f046e54611bc8196b")));
|
||||
|
||||
// PUT 2
|
||||
// Respond to request
|
||||
// server.enqueue(new MockResponse().setStatus("HTTP/1.1 100 Continue").clearHeaders());
|
||||
// token expired!
|
||||
server.enqueue(addCommonHeaders(new MockResponse().setResponseCode(401).setBody("401 Unauthorized")));
|
||||
// re-auth
|
||||
server.enqueue(addCommonHeaders(new MockResponse().setBody(stringFromResource("/access2.json"))));
|
||||
|
||||
// Finally success
|
||||
server.enqueue(addCommonHeaders(new MockResponse()
|
||||
.setResponseCode(201)
|
||||
.addHeader("ETag", "d9f5eb4bba4e2f2f046e54611bc8196b")));
|
||||
|
||||
try {
|
||||
Properties overrides = new Properties();
|
||||
overrides.setProperty(PROPERTY_MAX_RETRIES, 5 + "");
|
||||
|
||||
SwiftApi api = api(server.getUrl("/").toString(), "openstack-swift", overrides);
|
||||
assertEquals(
|
||||
api.getObjectApi("DFW", "myContainer").put("myObject1", PAYLOAD,
|
||||
metadata(metadata)), "d9f5eb4bba4e2f2f046e54611bc8196b");
|
||||
|
||||
assertEquals(
|
||||
api.getObjectApi("DFW", "myContainer").put("myObject2", PAYLOAD,
|
||||
metadata(metadata)), "d9f5eb4bba4e2f2f046e54611bc8196b");
|
||||
|
||||
assertEquals(server.getRequestCount(), 5);
|
||||
|
||||
//////
|
||||
|
||||
// First auth (auth cache empty
|
||||
assertAuthentication(server);
|
||||
|
||||
// PUT 1 request
|
||||
RecordedRequest replace = server.takeRequest();
|
||||
assertRequest(replace, "PUT", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/myObject1");
|
||||
|
||||
// token expired
|
||||
|
||||
// PUT 2 request
|
||||
replace = server.takeRequest();
|
||||
assertRequest(replace, "PUT", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/myObject2");
|
||||
|
||||
// PUT 2 request re-auth
|
||||
assertAuthentication(server);
|
||||
|
||||
// PUT 2 request retry
|
||||
replace = server.takeRequest();
|
||||
assertRequest(replace, "PUT", "/v1/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9/myContainer/myObject2");
|
||||
|
||||
} finally {
|
||||
server.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
/** upper-cases first char, and lower-cases rest!! **/
|
||||
public void testGetWithoutKnowingServerMessesWithMetadataKeyCaseFormat() throws Exception {
|
||||
MockWebServer server = mockOpenStackServer();
|
||||
|
249
apis/openstack-swift/src/test/resources/access2.json
Normal file
249
apis/openstack-swift/src/test/resources/access2.json
Normal file
@ -0,0 +1,249 @@
|
||||
{
|
||||
"access":{
|
||||
"token":{
|
||||
"id":"bb03a23aa8271291a7bbb9bbb2aaaaaa",
|
||||
"expires":"2013-08-02T16:55:24.229-05:00",
|
||||
"tenant":{
|
||||
"id":"888888",
|
||||
"name":"888888"
|
||||
},
|
||||
"RAX-AUTH:authenticatedBy":[
|
||||
"PASSWORD"
|
||||
]
|
||||
},
|
||||
"serviceCatalog":[
|
||||
{
|
||||
"name":"cloudFilesCDN",
|
||||
"endpoints":[
|
||||
{
|
||||
"region":"ORD",
|
||||
"tenantId":"MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9",
|
||||
"publicURL":"URL/v1\/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9"
|
||||
},
|
||||
{
|
||||
"region":"DFW",
|
||||
"tenantId":"MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9",
|
||||
"publicURL":"URL/v1\/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9"
|
||||
},
|
||||
{
|
||||
"region":"SYD",
|
||||
"tenantId":"MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9",
|
||||
"publicURL":"URL/v1\/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9"
|
||||
}
|
||||
],
|
||||
"type":"rax:object-cdn"
|
||||
},
|
||||
{
|
||||
"name":"cloudFiles",
|
||||
"endpoints":[
|
||||
{
|
||||
"region":"ORD",
|
||||
"tenantId":"MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9",
|
||||
"publicURL":"URL/v1\/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9",
|
||||
"internalURL":"URL/v1\/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9"
|
||||
},
|
||||
{
|
||||
"region":"DFW",
|
||||
"tenantId":"MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9",
|
||||
"publicURL":"URL/v1\/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9",
|
||||
"internalURL":"URL/v1\/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9"
|
||||
},
|
||||
{
|
||||
"region":"SYD",
|
||||
"tenantId":"MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9",
|
||||
"publicURL":"URL/v1\/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9",
|
||||
"internalURL":"URL/v1\/MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9"
|
||||
}
|
||||
],
|
||||
"type":"object-store"
|
||||
},
|
||||
{
|
||||
"name":"cloudLoadBalancers",
|
||||
"endpoints":[
|
||||
{
|
||||
"region":"SYD",
|
||||
"tenantId":"888888",
|
||||
"publicURL":"URL/v1.0\/888888"
|
||||
},
|
||||
{
|
||||
"region":"DFW",
|
||||
"tenantId":"888888",
|
||||
"publicURL":"URL/v1.0\/888888"
|
||||
},
|
||||
{
|
||||
"region":"ORD",
|
||||
"tenantId":"888888",
|
||||
"publicURL":"URL/v1.0\/888888"
|
||||
}
|
||||
],
|
||||
"type":"rax:load-balancer"
|
||||
},
|
||||
{
|
||||
"name":"cloudDatabases",
|
||||
"endpoints":[
|
||||
{
|
||||
"region":"SYD",
|
||||
"tenantId":"888888",
|
||||
"publicURL":"URL/v1.0\/888888"
|
||||
},
|
||||
{
|
||||
"region":"DFW",
|
||||
"tenantId":"888888",
|
||||
"publicURL":"URL/v1.0\/888888"
|
||||
},
|
||||
{
|
||||
"region":"ORD",
|
||||
"tenantId":"888888",
|
||||
"publicURL":"URL/v1.0\/888888"
|
||||
}
|
||||
],
|
||||
"type":"rax:database"
|
||||
},
|
||||
{
|
||||
"name":"cloudBlockStorage",
|
||||
"endpoints":[
|
||||
{
|
||||
"region":"SYD",
|
||||
"tenantId":"888888",
|
||||
"publicURL":"URL/v1\/888888"
|
||||
},
|
||||
{
|
||||
"region":"DFW",
|
||||
"tenantId":"888888",
|
||||
"publicURL":"URL/v1\/888888"
|
||||
},
|
||||
{
|
||||
"region":"ORD",
|
||||
"tenantId":"888888",
|
||||
"publicURL":"URL/v1\/888888"
|
||||
}
|
||||
],
|
||||
"type":"volume"
|
||||
},
|
||||
{
|
||||
"name":"cloudServersOpenStack",
|
||||
"endpoints":[
|
||||
{
|
||||
"region":"SYD",
|
||||
"tenantId":"888888",
|
||||
"publicURL":"URL/v2\/888888",
|
||||
"versionInfo":"https:\/\/syd.servers.api.rackspacecloud.com\/v2",
|
||||
"versionList":"https:\/\/syd.servers.api.rackspacecloud.com\/",
|
||||
"versionId":"2"
|
||||
},
|
||||
{
|
||||
"region":"DFW",
|
||||
"tenantId":"888888",
|
||||
"publicURL":"URL/v2\/888888",
|
||||
"versionInfo":"https:\/\/dfw.servers.api.rackspacecloud.com\/v2",
|
||||
"versionList":"https:\/\/dfw.servers.api.rackspacecloud.com\/",
|
||||
"versionId":"2"
|
||||
},
|
||||
{
|
||||
"region":"ORD",
|
||||
"tenantId":"888888",
|
||||
"publicURL":"URL/v2\/888888",
|
||||
"versionInfo":"https:\/\/ord.servers.api.rackspacecloud.com\/v2",
|
||||
"versionList":"https:\/\/ord.servers.api.rackspacecloud.com\/",
|
||||
"versionId":"2"
|
||||
}
|
||||
],
|
||||
"type":"compute"
|
||||
},
|
||||
{
|
||||
"name":"autoscale",
|
||||
"endpoints":[
|
||||
{
|
||||
"region":"ORD",
|
||||
"tenantId":"888888",
|
||||
"publicURL":"URL/v1.0\/888888",
|
||||
"versionInfo":null,
|
||||
"versionList":null,
|
||||
"versionId":"1.0"
|
||||
},
|
||||
{
|
||||
"region":"DFW",
|
||||
"tenantId":"888888",
|
||||
"publicURL":"URL/v1.0\/888888",
|
||||
"versionInfo":null,
|
||||
"versionList":null,
|
||||
"versionId":"1.0"
|
||||
}
|
||||
],
|
||||
"type":"rax:autoscale"
|
||||
},
|
||||
{
|
||||
"name":"cloudMonitoring",
|
||||
"endpoints":[
|
||||
{
|
||||
"tenantId":"888888",
|
||||
"publicURL":"URL/v1.0\/888888"
|
||||
}
|
||||
],
|
||||
"type":"rax:monitor"
|
||||
},
|
||||
{
|
||||
"name":"cloudBackup",
|
||||
"endpoints":[
|
||||
{
|
||||
"tenantId":"888888",
|
||||
"publicURL":"URL/v1.0\/888888"
|
||||
}
|
||||
],
|
||||
"type":"rax:backup"
|
||||
},
|
||||
{
|
||||
"name":"cloudServers",
|
||||
"endpoints":[
|
||||
{
|
||||
"tenantId":"888888",
|
||||
"publicURL":"URL/v1.0\/888888",
|
||||
"versionInfo":"https:\/\/servers.api.rackspacecloud.com\/v1.0",
|
||||
"versionList":"https:\/\/servers.api.rackspacecloud.com\/",
|
||||
"versionId":"1.0"
|
||||
}
|
||||
],
|
||||
"type":"compute"
|
||||
},
|
||||
{
|
||||
"name":"cloudDNS",
|
||||
"endpoints":[
|
||||
{
|
||||
"tenantId":"888888",
|
||||
"publicURL":"URL/v1.0\/888888"
|
||||
}
|
||||
],
|
||||
"type":"rax:dns"
|
||||
}
|
||||
],
|
||||
"user":{
|
||||
"id":"335853",
|
||||
"roles":[
|
||||
{
|
||||
"id":"10000150",
|
||||
"description":"Checkmate Access role",
|
||||
"name":"checkmate"
|
||||
},
|
||||
{
|
||||
"tenantId":"MossoCloudFS_5bcf396e-39dd-45ff-93a1-712b9aba90a9",
|
||||
"id":"5",
|
||||
"description":"A Role that allows a user access to keystone Service methods",
|
||||
"name":"object-store:default"
|
||||
},
|
||||
{
|
||||
"tenantId":"888888",
|
||||
"id":"6",
|
||||
"description":"A Role that allows a user access to keystone Service methods",
|
||||
"name":"compute:default"
|
||||
},
|
||||
{
|
||||
"id":"3",
|
||||
"description":"User Admin Role.",
|
||||
"name":"identity:user-admin"
|
||||
}
|
||||
],
|
||||
"name":"test",
|
||||
"RAX-AUTH:defaultRegion":"ORD"
|
||||
}
|
||||
}
|
||||
}
|
@ -25,6 +25,7 @@ import static org.jclouds.http.HttpUtils.wirePayloadIfEnabled;
|
||||
import static org.jclouds.util.Throwables2.getFirstThrowableOfType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ProtocolException;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
@ -145,6 +146,16 @@ public abstract class BaseHttpCommandExecutorService<Q> implements HttpCommandEx
|
||||
}
|
||||
|
||||
boolean shouldContinue(HttpCommand command, IOException response) {
|
||||
// Even though Java does not want to handle it this way,
|
||||
// treat a Protocol Exception on PUT with 100-Continue as a case of Unauthorized (and attempt to retry)
|
||||
if (command.getCurrentRequest().getMethod().equals("PUT")
|
||||
&& command.getCurrentRequest().getHeaders().containsEntry("Expect", "100-continue")
|
||||
&& response instanceof ProtocolException
|
||||
&& response.getMessage().equals("Server rejected operation")
|
||||
) {
|
||||
logger.debug("Caught a protocol exception on a 100-continue PUT request. Attempting to retry.");
|
||||
return isIdempotent(command) && retryHandler.shouldRetryRequest(command, HttpResponse.builder().statusCode(401).message("Unauthorized").build());
|
||||
}
|
||||
return isIdempotent(command) && ioRetryHandler.shouldRetryRequest(command, response);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user