mirror of https://github.com/apache/jclouds.git
Updates to Http: separate md5 from etag, switch from URL to URI
git-svn-id: http://jclouds.googlecode.com/svn/trunk@1909 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
parent
09f81b222a
commit
ffd34b36c2
|
@ -23,6 +23,7 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.http;
|
package org.jclouds.http;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
@ -57,6 +58,8 @@ public class HttpRequest extends HttpMessage implements Request<URI> {
|
||||||
public HttpRequest(String method, URI endPoint) {
|
public HttpRequest(String method, URI endPoint) {
|
||||||
this.method = checkNotNull(method, "method");
|
this.method = checkNotNull(method, "method");
|
||||||
this.endpoint = checkNotNull(endPoint, "endPoint");
|
this.endpoint = checkNotNull(endPoint, "endPoint");
|
||||||
|
checkArgument(endPoint.getHost() != null, String.format("endPoint.getHost() is null for %s",
|
||||||
|
endPoint));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -82,7 +85,7 @@ public class HttpRequest extends HttpMessage implements Request<URI> {
|
||||||
@Nullable Object entity) {
|
@Nullable Object entity) {
|
||||||
this(method, endPoint);
|
this(method, endPoint);
|
||||||
setHeaders(checkNotNull(headers, "headers"));
|
setHeaders(checkNotNull(headers, "headers"));
|
||||||
setEntity("entity");
|
setEntity(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -92,6 +95,7 @@ public class HttpRequest extends HttpMessage implements Request<URI> {
|
||||||
sb.append("{endPoint='").append(endpoint).append('\'');
|
sb.append("{endPoint='").append(endpoint).append('\'');
|
||||||
sb.append(", method='").append(method).append('\'');
|
sb.append(", method='").append(method).append('\'');
|
||||||
sb.append(", headers=").append(headers);
|
sb.append(", headers=").append(headers);
|
||||||
|
sb.append(", filters=").append(requestFilters);
|
||||||
if (entity != null && entity instanceof String) {
|
if (entity != null && entity instanceof String) {
|
||||||
sb.append(", entity=").append(entity);
|
sb.append(", entity=").append(entity);
|
||||||
} else {
|
} else {
|
||||||
|
@ -102,7 +106,9 @@ public class HttpRequest extends HttpMessage implements Request<URI> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We cannot return an enum, as per specification custom methods are allowed. Enums are not extensible.
|
* We cannot return an enum, as per specification custom methods are allowed. Enums are not
|
||||||
|
* extensible.
|
||||||
|
*
|
||||||
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.1
|
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.1
|
||||||
*/
|
*/
|
||||||
public String getMethod() {
|
public String getMethod() {
|
||||||
|
|
|
@ -101,19 +101,19 @@ public class HttpUtils {
|
||||||
return hmacBase64(toEncode, key, digest);
|
return hmacBase64(toEncode, key, digest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String eTagHex(byte[] toEncode) throws NoSuchAlgorithmException,
|
public static String md5Hex(byte[] toEncode) throws NoSuchAlgorithmException,
|
||||||
NoSuchProviderException, InvalidKeyException, UnsupportedEncodingException {
|
NoSuchProviderException, InvalidKeyException, UnsupportedEncodingException {
|
||||||
byte[] resBuf = eTag(toEncode);
|
byte[] resBuf = md5(toEncode);
|
||||||
return toHexString(resBuf);
|
return toHexString(resBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String eTagBase64(byte[] toEncode) throws NoSuchAlgorithmException,
|
public static String md5Base64(byte[] toEncode) throws NoSuchAlgorithmException,
|
||||||
NoSuchProviderException, InvalidKeyException {
|
NoSuchProviderException, InvalidKeyException {
|
||||||
byte[] resBuf = eTag(toEncode);
|
byte[] resBuf = md5(toEncode);
|
||||||
return toBase64String(resBuf);
|
return toBase64String(resBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] eTag(byte[] plainBytes) {
|
public static byte[] md5(byte[] plainBytes) {
|
||||||
MD5Digest eTag = new MD5Digest();
|
MD5Digest eTag = new MD5Digest();
|
||||||
byte[] resBuf = new byte[eTag.getDigestSize()];
|
byte[] resBuf = new byte[eTag.getDigestSize()];
|
||||||
eTag.update(plainBytes, 0, plainBytes.length);
|
eTag.update(plainBytes, 0, plainBytes.length);
|
||||||
|
@ -121,7 +121,7 @@ public class HttpUtils {
|
||||||
return resBuf;
|
return resBuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] eTag(File toEncode) throws IOException {
|
public static byte[] md5(File toEncode) throws IOException {
|
||||||
MD5Digest eTag = new MD5Digest();
|
MD5Digest eTag = new MD5Digest();
|
||||||
byte[] resBuf = new byte[eTag.getDigestSize()];
|
byte[] resBuf = new byte[eTag.getDigestSize()];
|
||||||
byte[] buffer = new byte[1024];
|
byte[] buffer = new byte[1024];
|
||||||
|
@ -160,24 +160,24 @@ public class HttpUtils {
|
||||||
/**
|
/**
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public static byte[] eTag(Object data) throws IOException {
|
public static byte[] md5(Object data) throws IOException {
|
||||||
checkNotNull(data, "data must be set before calling generateETag()");
|
checkNotNull(data, "data must be set before calling generateETag()");
|
||||||
byte[] eTag = null;
|
byte[] md5 = null;
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
} else if (data instanceof byte[]) {
|
} else if (data instanceof byte[]) {
|
||||||
eTag = eTag((byte[]) data);
|
md5 = md5((byte[]) data);
|
||||||
} else if (data instanceof String) {
|
} else if (data instanceof String) {
|
||||||
eTag = eTag(((String) data).getBytes());
|
md5 = md5(((String) data).getBytes());
|
||||||
} else if (data instanceof File) {
|
} else if (data instanceof File) {
|
||||||
eTag = eTag(((File) data));
|
md5 = md5(((File) data));
|
||||||
} else {
|
} else {
|
||||||
throw new UnsupportedOperationException("Content not supported " + data.getClass());
|
throw new UnsupportedOperationException("Content not supported " + data.getClass());
|
||||||
}
|
}
|
||||||
return eTag;
|
return md5;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ETagInputStreamResult generateETagResult(InputStream toEncode) throws IOException {
|
public static MD5InputStreamResult generateMD5Result(InputStream toEncode) throws IOException {
|
||||||
MD5Digest eTag = new MD5Digest();
|
MD5Digest eTag = new MD5Digest();
|
||||||
byte[] resBuf = new byte[eTag.getDigestSize()];
|
byte[] resBuf = new byte[eTag.getDigestSize()];
|
||||||
byte[] buffer = new byte[1024];
|
byte[] buffer = new byte[1024];
|
||||||
|
@ -198,15 +198,15 @@ public class HttpUtils {
|
||||||
IOUtils.closeQuietly(toEncode);
|
IOUtils.closeQuietly(toEncode);
|
||||||
}
|
}
|
||||||
eTag.doFinal(resBuf, 0);
|
eTag.doFinal(resBuf, 0);
|
||||||
return new ETagInputStreamResult(out.toByteArray(), resBuf, length);
|
return new MD5InputStreamResult(out.toByteArray(), resBuf, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ETagInputStreamResult {
|
public static class MD5InputStreamResult {
|
||||||
public final byte[] data;
|
public final byte[] data;
|
||||||
public final byte[] eTag;
|
public final byte[] eTag;
|
||||||
public final long length;
|
public final long length;
|
||||||
|
|
||||||
ETagInputStreamResult(byte[] data, byte[] eTag, long length) {
|
MD5InputStreamResult(byte[] data, byte[] eTag, long length) {
|
||||||
this.data = checkNotNull(data, "data");
|
this.data = checkNotNull(data, "data");
|
||||||
this.eTag = checkNotNull(eTag, "eTag");
|
this.eTag = checkNotNull(eTag, "eTag");
|
||||||
checkArgument(length >= 0, "length cannot me negative");
|
checkArgument(length >= 0, "length cannot me negative");
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
* ====================================================================
|
||||||
|
*/
|
||||||
|
package org.jclouds.http.functions;
|
||||||
|
|
||||||
|
import org.jclouds.http.HttpResponseException;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
|
||||||
|
public class ReturnTrueOn404 implements Function<Exception, Boolean> {
|
||||||
|
|
||||||
|
public Boolean apply(Exception from) {
|
||||||
|
if (from instanceof HttpResponseException) {
|
||||||
|
HttpResponseException responseException = (HttpResponseException) from;
|
||||||
|
if (responseException.getResponse().getStatusCode() == 404) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -73,10 +73,11 @@ public abstract class BaseHttpCommandExecutorService<Q> implements HttpCommandEx
|
||||||
HttpRequest request = command.getRequest();
|
HttpRequest request = command.getRequest();
|
||||||
Q nativeRequest = null;
|
Q nativeRequest = null;
|
||||||
try {
|
try {
|
||||||
logger.trace("%s - converting request %s", request.getEndpoint(), request);
|
logger.trace("%s - filtering request %s", request.getEndpoint(), request);
|
||||||
for (HttpRequestFilter filter : request.getFilters()) {
|
for (HttpRequestFilter filter : request.getFilters()) {
|
||||||
filter.filter(request);
|
filter.filter(request);
|
||||||
}
|
}
|
||||||
|
logger.trace("%s - request now %s", request.getEndpoint(), request);
|
||||||
nativeRequest = convert(request);
|
nativeRequest = convert(request);
|
||||||
response = invoke(nativeRequest);
|
response = invoke(nativeRequest);
|
||||||
int statusCode = response.getStatusCode();
|
int statusCode = response.getStatusCode();
|
||||||
|
|
|
@ -30,6 +30,7 @@ import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
@ -90,7 +91,12 @@ public class JavaUrlHttpCommandExecutorService extends
|
||||||
protected HttpResponse invoke(HttpURLConnection connection) throws IOException {
|
protected HttpResponse invoke(HttpURLConnection connection) throws IOException {
|
||||||
logger.trace("%s - submitting request %s; %s", connection.getURL().getHost(), connection
|
logger.trace("%s - submitting request %s; %s", connection.getURL().getHost(), connection
|
||||||
.getURL(), connection.getHeaderFields().toString());
|
.getURL(), connection.getHeaderFields().toString());
|
||||||
HttpResponse response = new HttpResponse(connection.getURL());
|
HttpResponse response;
|
||||||
|
try {
|
||||||
|
response = new HttpResponse(connection.getURL().toURI());
|
||||||
|
} catch (URISyntaxException e1) {
|
||||||
|
throw new RuntimeException(e1);
|
||||||
|
}
|
||||||
InputStream in;
|
InputStream in;
|
||||||
try {
|
try {
|
||||||
in = connection.getInputStream();
|
in = connection.getInputStream();
|
||||||
|
@ -128,12 +134,12 @@ public class JavaUrlHttpCommandExecutorService extends
|
||||||
for (String header : request.getHeaders().keySet()) {
|
for (String header : request.getHeaders().keySet()) {
|
||||||
for (String value : request.getHeaders().get(header)) {
|
for (String value : request.getHeaders().get(header)) {
|
||||||
connection.setRequestProperty(header, value);
|
connection.setRequestProperty(header, value);
|
||||||
|
|
||||||
if ("Transfer-Encoding".equals(header) && "chunked".equals(value)) {
|
if ("Transfer-Encoding".equals(header) && "chunked".equals(value)) {
|
||||||
connection.setChunkedStreamingMode(8192);
|
connection.setChunkedStreamingMode(8192);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
connection.setRequestProperty(HttpHeaders.HOST, request.getEndpoint().getHost());
|
connection.setRequestProperty(HttpHeaders.HOST, request.getEndpoint().getHost());
|
||||||
if (request.getEntity() != null) {
|
if (request.getEntity() != null) {
|
||||||
OutputStream out = connection.getOutputStream();
|
OutputStream out = connection.getOutputStream();
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.http.pool;
|
package org.jclouds.http.pool;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
@ -67,6 +69,8 @@ public class ConnectionPoolTransformingHttpCommandExecutorService<C> extends Bas
|
||||||
// TODO inject this.
|
// TODO inject this.
|
||||||
poolMap = new MapMaker().makeComputingMap(new Function<URI, HttpCommandConnectionPool<C>>() {
|
poolMap = new MapMaker().makeComputingMap(new Function<URI, HttpCommandConnectionPool<C>>() {
|
||||||
public HttpCommandConnectionPool<C> apply(URI endPoint) {
|
public HttpCommandConnectionPool<C> apply(URI endPoint) {
|
||||||
|
checkArgument(endPoint.getHost() != null, String.format(
|
||||||
|
"endPoint.getHost() is null for %s", endPoint));
|
||||||
try {
|
try {
|
||||||
HttpCommandConnectionPool<C> pool = poolFactory.create(endPoint);
|
HttpCommandConnectionPool<C> pool = poolFactory.create(endPoint);
|
||||||
addDependency(pool);
|
addDependency(pool);
|
||||||
|
@ -159,10 +163,10 @@ public class ConnectionPoolTransformingHttpCommandExecutorService<C> extends Bas
|
||||||
*/
|
*/
|
||||||
protected void invoke(HttpCommandRendezvous<?> command) {
|
protected void invoke(HttpCommandRendezvous<?> command) {
|
||||||
exceptionIfNotActive();
|
exceptionIfNotActive();
|
||||||
URI endpoint = command.getCommand().getRequest().getEndpoint();
|
|
||||||
URI specificEndpoint = URI.create(endpoint.getScheme() + "://" + endpoint.getHost() + ":"
|
URI endpoint = createBaseEndpointFor(command);
|
||||||
+ endpoint.getPort());
|
|
||||||
HttpCommandConnectionPool<C> pool = poolMap.get(specificEndpoint);
|
HttpCommandConnectionPool<C> pool = poolMap.get(endpoint);
|
||||||
if (pool == null) {
|
if (pool == null) {
|
||||||
// TODO limit;
|
// TODO limit;
|
||||||
logger.warn("pool not available for command %s; retrying", command);
|
logger.warn("pool not available for command %s; retrying", command);
|
||||||
|
@ -182,6 +186,12 @@ public class ConnectionPoolTransformingHttpCommandExecutorService<C> extends Bas
|
||||||
command, pool);
|
command, pool);
|
||||||
commandQueue.add(command);
|
commandQueue.add(command);
|
||||||
return;
|
return;
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
logger.warn(e, "Error getting a connection for command %s on pool %s; retrying", command,
|
||||||
|
pool);
|
||||||
|
discardPool(endpoint, pool);
|
||||||
|
commandQueue.add(command);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connectionHandle == null) {
|
if (connectionHandle == null) {
|
||||||
|
@ -192,6 +202,26 @@ public class ConnectionPoolTransformingHttpCommandExecutorService<C> extends Bas
|
||||||
connectionHandle.startConnection();
|
connectionHandle.startConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void discardPool(URI endpoint, HttpCommandConnectionPool<C> pool) {
|
||||||
|
poolMap.remove(endpoint, pool);
|
||||||
|
pool.shutdown();
|
||||||
|
this.dependencies.remove(pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* keys to the map are only used for socket information, not path. In this case, you should
|
||||||
|
* remove any path or query details from the URI.
|
||||||
|
*/
|
||||||
|
private URI createBaseEndpointFor(HttpCommandRendezvous<?> command) {
|
||||||
|
URI endpoint = command.getCommand().getRequest().getEndpoint();
|
||||||
|
if (endpoint.getPort() == -1) {
|
||||||
|
return URI.create(String.format("%s://%s", endpoint.getScheme(), endpoint.getHost()));
|
||||||
|
} else {
|
||||||
|
return URI.create(String.format("%s://%s:%d", endpoint.getScheme(), endpoint.getHost(),
|
||||||
|
endpoint.getPort()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
|
|
@ -159,7 +159,7 @@ public abstract class HttpCommandConnectionPool<C> extends BaseLifeCycle {
|
||||||
|
|
||||||
protected abstract boolean isReplayable(HttpCommandRendezvous<?> rendezvous);
|
protected abstract boolean isReplayable(HttpCommandRendezvous<?> rendezvous);
|
||||||
|
|
||||||
HttpCommandRendezvous<?> getCommandFromConnection(C connection) {
|
protected HttpCommandRendezvous<?> getCommandFromConnection(C connection) {
|
||||||
HttpCommandConnectionHandle<C> handle = getHandleFromConnection(connection);
|
HttpCommandConnectionHandle<C> handle = getHandleFromConnection(connection);
|
||||||
if (handle != null && handle.getCommandRendezvous() != null) {
|
if (handle != null && handle.getCommandRendezvous() != null) {
|
||||||
return handle.getCommandRendezvous();
|
return handle.getCommandRendezvous();
|
||||||
|
@ -174,7 +174,7 @@ public abstract class HttpCommandConnectionPool<C> extends BaseLifeCycle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setExceptionOnCommand(Exception e, HttpCommandRendezvous<?> rendezvous) {
|
protected void setExceptionOnCommand(Exception e, HttpCommandRendezvous<?> rendezvous) {
|
||||||
logger.warn(e, "exception in rendezvous: %s", rendezvous);
|
logger.warn(e, "exception in rendezvous: %s", rendezvous);
|
||||||
try {
|
try {
|
||||||
rendezvous.setException(e);
|
rendezvous.setException(e);
|
||||||
|
|
|
@ -1,94 +0,0 @@
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
|
|
||||||
*
|
|
||||||
* ====================================================================
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
* ====================================================================
|
|
||||||
*/
|
|
||||||
package org.jclouds.concurrent;
|
|
||||||
|
|
||||||
import static org.testng.Assert.assertEquals;
|
|
||||||
|
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
|
|
||||||
import org.testng.annotations.Test;
|
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests behavior of FutureExceptionParser
|
|
||||||
*
|
|
||||||
* @author Adrian Cole
|
|
||||||
*/
|
|
||||||
@Test(groups = "unit", testName = "concurrent.FutureExceptionParserTest")
|
|
||||||
public class FutureExceptionParserTest {
|
|
||||||
ExecutorService executorService = new WithinThreadExecutorService();
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGet() throws InterruptedException, ExecutionException {
|
|
||||||
Future<?> future = createFuture(new RuntimeException("foo"));
|
|
||||||
assertEquals(future.get(), "foo");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expectedExceptions = ExecutionException.class)
|
|
||||||
public void testGetUnmatched() throws InterruptedException, ExecutionException {
|
|
||||||
Future<?> future = createFuture(new Exception("foo"));
|
|
||||||
assertEquals(future.get(), "foo");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetLongTimeUnit() throws InterruptedException, ExecutionException,
|
|
||||||
TimeoutException {
|
|
||||||
Future<?> future = createFuture(new RuntimeException("foo"));
|
|
||||||
assertEquals(future.get(1, TimeUnit.SECONDS), "foo");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expectedExceptions = ExecutionException.class)
|
|
||||||
public void testGetLongTimeUnitUnmatched() throws InterruptedException, ExecutionException,
|
|
||||||
TimeoutException {
|
|
||||||
Future<?> future = createFuture(new Exception("foo"));
|
|
||||||
assertEquals(future.get(1, TimeUnit.SECONDS), "foo");
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private Future<?> createFuture(final Exception exception) {
|
|
||||||
Future<?> future = executorService.submit(new Callable<String>() {
|
|
||||||
|
|
||||||
public String call() throws Exception {
|
|
||||||
throw exception;
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
future = new FutureExceptionParser(future, new Function<Exception, String>() {
|
|
||||||
|
|
||||||
public String apply(Exception from) {
|
|
||||||
return (from instanceof RuntimeException) ? from.getMessage() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
return future;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -32,6 +32,7 @@ import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
import org.jclouds.http.options.GetOptions;
|
import org.jclouds.http.options.GetOptions;
|
||||||
|
import org.testng.annotations.DataProvider;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,6 +51,8 @@ public abstract class BaseHttpCommandExecutorServiceTest extends BaseJettyTest {
|
||||||
assertEquals(get.get(10, TimeUnit.SECONDS).trim(), "test");
|
assertEquals(get.get(10, TimeUnit.SECONDS).trim(), "test");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: filtering redirect test
|
||||||
|
|
||||||
@Test(invocationCount = 50, timeOut = 5000)
|
@Test(invocationCount = 50, timeOut = 5000)
|
||||||
public void testGetStringWithHeader() throws MalformedURLException, ExecutionException,
|
public void testGetStringWithHeader() throws MalformedURLException, ExecutionException,
|
||||||
InterruptedException, TimeoutException {
|
InterruptedException, TimeoutException {
|
||||||
|
@ -64,11 +67,17 @@ public abstract class BaseHttpCommandExecutorServiceTest extends BaseJettyTest {
|
||||||
assertEquals(get.get(10, TimeUnit.SECONDS).trim(), XML);
|
assertEquals(get.get(10, TimeUnit.SECONDS).trim(), XML);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(invocationCount = 50, timeOut = 5000)
|
@DataProvider(name = "gets")
|
||||||
public void testGetStringSynch() throws MalformedURLException, ExecutionException,
|
public Object[][] createData() {
|
||||||
|
return new Object[][] { { "object" }, { "/path" }, { "sp ace" }, { "unic¿de" },
|
||||||
|
{ "qu?stion" } };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(invocationCount = 50, timeOut = 5000, dataProvider = "gets")
|
||||||
|
public void testGetStringSynch(String uri) throws MalformedURLException, ExecutionException,
|
||||||
InterruptedException, TimeoutException {
|
InterruptedException, TimeoutException {
|
||||||
// TODO why need trim?
|
// TODO why need trim?
|
||||||
assertEquals(client.synch("").trim(), XML);
|
assertEquals(client.synch(uri).trim(), XML);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(invocationCount = 50, timeOut = 5000)
|
@Test(invocationCount = 50, timeOut = 5000)
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
* ====================================================================
|
||||||
|
*/
|
||||||
|
package org.jclouds.http;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests parsing of a request
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Test(testName = "httpnio.HttpRequestTest")
|
||||||
|
public class HttpRequestTest {
|
||||||
|
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||||
|
public void testConstructorHostNull() throws Exception {
|
||||||
|
URI uri = URI.create("http://adriancole.blobstore1138eu.s3-external-3.amazonaws.com:-1");
|
||||||
|
assert uri.getHost() == null : "test requires something to produce a uri with a null hostname";
|
||||||
|
|
||||||
|
new HttpRequest("GET", uri);
|
||||||
|
}
|
||||||
|
}
|
|
@ -61,8 +61,8 @@ public interface IntegrationTestClient {
|
||||||
Future<String> download(@PathParam("id") String id);
|
Future<String> download(@PathParam("id") String id);
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Path("objects/{id}")
|
@Path("{path}")
|
||||||
String synch(@PathParam("id") String id);
|
String synch(@PathParam("path") String id);
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Path("objects/{id}")
|
@Path("objects/{id}")
|
||||||
|
|
|
@ -29,7 +29,6 @@ import static org.testng.Assert.assertTrue;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URL;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
@ -100,7 +99,7 @@ public class BackoffLimitedRetryHandlerTest {
|
||||||
void testClosesInputStream() throws InterruptedException, IOException {
|
void testClosesInputStream() throws InterruptedException, IOException {
|
||||||
HttpCommand command = createCommand();
|
HttpCommand command = createCommand();
|
||||||
|
|
||||||
HttpResponse response = new HttpResponse(new URL("file:///unused"));
|
HttpResponse response = new HttpResponse(URI.create("http://localhost"));
|
||||||
InputStream inputStream = new InputStream() {
|
InputStream inputStream = new InputStream() {
|
||||||
boolean isOpen = true;
|
boolean isOpen = true;
|
||||||
|
|
||||||
|
@ -151,7 +150,7 @@ public class BackoffLimitedRetryHandlerTest {
|
||||||
@Test
|
@Test
|
||||||
void testIncrementsFailureCount() throws InterruptedException, IOException {
|
void testIncrementsFailureCount() throws InterruptedException, IOException {
|
||||||
HttpCommand command = createCommand();
|
HttpCommand command = createCommand();
|
||||||
HttpResponse response = new HttpResponse(new URL("file:///unused"));
|
HttpResponse response = new HttpResponse(URI.create("http://localhost"));
|
||||||
|
|
||||||
handler.shouldRetryRequest(command, response);
|
handler.shouldRetryRequest(command, response);
|
||||||
assertEquals(command.getFailureCount(), 1);
|
assertEquals(command.getFailureCount(), 1);
|
||||||
|
@ -166,7 +165,7 @@ public class BackoffLimitedRetryHandlerTest {
|
||||||
@Test
|
@Test
|
||||||
void testDisallowsExcessiveRetries() throws InterruptedException, IOException {
|
void testDisallowsExcessiveRetries() throws InterruptedException, IOException {
|
||||||
HttpCommand command = createCommand();
|
HttpCommand command = createCommand();
|
||||||
HttpResponse response = new HttpResponse(new URL("file:///unused"));
|
HttpResponse response = new HttpResponse(URI.create("http://localhost"));
|
||||||
|
|
||||||
assertEquals(handler.shouldRetryRequest(command, response), true); // Failure 1
|
assertEquals(handler.shouldRetryRequest(command, response), true); // Failure 1
|
||||||
|
|
||||||
|
|
|
@ -117,7 +117,7 @@ public class HttpUtilsTest extends PerformanceTest {
|
||||||
public void testBouncyCastleMD5Digest(String message, String base64Digest)
|
public void testBouncyCastleMD5Digest(String message, String base64Digest)
|
||||||
throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException,
|
throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException,
|
||||||
UnsupportedEncodingException {
|
UnsupportedEncodingException {
|
||||||
String b64 = HttpUtils.eTagHex(message.getBytes());
|
String b64 = HttpUtils.md5Hex(message.getBytes());
|
||||||
assertEquals(base64Digest, b64);
|
assertEquals(base64Digest, b64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,8 @@ import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
@ -106,8 +108,8 @@ public class GaeHttpCommandExecutorService extends BaseHttpCommandExecutorServic
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
protected HttpResponse convert(URL requestURL, HTTPResponse gaeResponse) {
|
protected HttpResponse convert(URI uri, HTTPResponse gaeResponse) {
|
||||||
HttpResponse response = new HttpResponse(requestURL);
|
HttpResponse response = new HttpResponse(uri);
|
||||||
response.setStatusCode(gaeResponse.getResponseCode());
|
response.setStatusCode(gaeResponse.getResponseCode());
|
||||||
for (HTTPHeader header : gaeResponse.getHeaders()) {
|
for (HTTPHeader header : gaeResponse.getHeaders()) {
|
||||||
response.getHeaders().put(header.getName(), header.getValue());
|
response.getHeaders().put(header.getName(), header.getValue());
|
||||||
|
@ -169,12 +171,16 @@ public class GaeHttpCommandExecutorService extends BaseHttpCommandExecutorServic
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected HttpResponse invoke(HTTPRequest request) throws IOException {
|
protected HttpResponse invoke(HTTPRequest request) throws IOException {
|
||||||
logger.trace("%1$s - submitting request %2$s, headers: %3$s", request.getURL().getHost(),
|
logger.trace("%s - submitting request %s, headers: %s", request.getURL().getHost(), request
|
||||||
request.getURL(), headersAsString(request.getHeaders()));
|
.getURL(), headersAsString(request.getHeaders()));
|
||||||
HTTPResponse response = urlFetchService.fetch(request);
|
HTTPResponse response = urlFetchService.fetch(request);
|
||||||
logger.info("%1$s - received response code %2$s, headers: %3$s", request.getURL().getHost(),
|
logger.trace("%s - received response code %s, headers: %s", request.getURL().getHost(),
|
||||||
response.getResponseCode(), headersAsString(response.getHeaders()));
|
response.getResponseCode(), headersAsString(response.getHeaders()));
|
||||||
return convert(request.getURL(), response);
|
try {
|
||||||
|
return convert(request.getURL().toURI(), response);
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String headersAsString(List<HTTPHeader> headers) {
|
String headersAsString(List<HTTPHeader> headers) {
|
||||||
|
|
|
@ -26,6 +26,7 @@ package org.jclouds.gae;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
@ -37,6 +38,7 @@ import org.jclouds.http.BaseHttpCommandExecutorServiceTest;
|
||||||
import org.testng.annotations.BeforeMethod;
|
import org.testng.annotations.BeforeMethod;
|
||||||
import org.testng.annotations.BeforeTest;
|
import org.testng.annotations.BeforeTest;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
import org.testng.v6.Maps;
|
||||||
|
|
||||||
import com.google.appengine.tools.development.ApiProxyLocalImpl;
|
import com.google.appengine.tools.development.ApiProxyLocalImpl;
|
||||||
import com.google.apphosting.api.ApiProxy;
|
import com.google.apphosting.api.ApiProxy;
|
||||||
|
@ -93,11 +95,11 @@ public class GaeHttpCommandExecutorServiceIntegrationTest extends
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Test(invocationCount = 50, timeOut = 3000)
|
@Test(invocationCount = 50, timeOut = 3000, dataProvider = "gets")
|
||||||
public void testGetStringSynch() throws MalformedURLException, ExecutionException,
|
public void testGetStringSynch(String path) throws MalformedURLException, ExecutionException,
|
||||||
InterruptedException, TimeoutException {
|
InterruptedException, TimeoutException {
|
||||||
setupApiProxy();
|
setupApiProxy();
|
||||||
super.testGetStringSynch();
|
super.testGetStringSynch(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -214,6 +216,10 @@ public class GaeHttpCommandExecutorServiceIntegrationTest extends
|
||||||
public boolean isAdmin() {
|
public boolean isAdmin() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> getAttributes() {
|
||||||
|
return Maps.newHashMap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Module createClientModule() {
|
protected Module createClientModule() {
|
||||||
|
|
|
@ -34,7 +34,6 @@ import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URL;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -88,7 +87,7 @@ public class GaeHttpCommandExecutorServiceTest {
|
||||||
expect(gaeResponse.getHeaders()).andReturn(headers);
|
expect(gaeResponse.getHeaders()).andReturn(headers);
|
||||||
expect(gaeResponse.getContent()).andReturn(null).atLeastOnce();
|
expect(gaeResponse.getContent()).andReturn(null).atLeastOnce();
|
||||||
replay(gaeResponse);
|
replay(gaeResponse);
|
||||||
HttpResponse response = client.convert(new URL("file:///unused"), gaeResponse);
|
HttpResponse response = client.convert(URI.create("http://localhost"), gaeResponse);
|
||||||
assertEquals(response.getStatusCode(), 200);
|
assertEquals(response.getStatusCode(), 200);
|
||||||
assertEquals(response.getContent(), null);
|
assertEquals(response.getContent(), null);
|
||||||
assertEquals(response.getHeaders().size(), 1);
|
assertEquals(response.getHeaders().size(), 1);
|
||||||
|
@ -104,7 +103,7 @@ public class GaeHttpCommandExecutorServiceTest {
|
||||||
expect(gaeResponse.getHeaders()).andReturn(headers);
|
expect(gaeResponse.getHeaders()).andReturn(headers);
|
||||||
expect(gaeResponse.getContent()).andReturn("hello".getBytes()).atLeastOnce();
|
expect(gaeResponse.getContent()).andReturn("hello".getBytes()).atLeastOnce();
|
||||||
replay(gaeResponse);
|
replay(gaeResponse);
|
||||||
HttpResponse response = client.convert(new URL("file:///unused"), gaeResponse);
|
HttpResponse response = client.convert(URI.create("http://localhost"), gaeResponse);
|
||||||
assertEquals(response.getStatusCode(), 200);
|
assertEquals(response.getStatusCode(), 200);
|
||||||
assertEquals(IOUtils.toString(response.getContent()), "hello");
|
assertEquals(IOUtils.toString(response.getContent()), "hello");
|
||||||
assertEquals(response.getHeaders().size(), 1);
|
assertEquals(response.getHeaders().size(), 1);
|
||||||
|
|
|
@ -55,7 +55,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.httpcomponents</groupId>
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
<artifactId>httpcore-nio</artifactId>
|
<artifactId>httpcore-nio</artifactId>
|
||||||
<version>4.0.1</version>
|
<version>4.1-alpha1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -23,9 +23,13 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.http.httpnio.pool;
|
package org.jclouds.http.httpnio.pool;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.nio.charset.UnmappableCharacterException;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
|
@ -53,6 +57,7 @@ import org.jclouds.http.pool.HttpCommandConnectionHandle;
|
||||||
import org.jclouds.http.pool.HttpCommandConnectionPool;
|
import org.jclouds.http.pool.HttpCommandConnectionPool;
|
||||||
import org.jclouds.http.pool.PoolConstants;
|
import org.jclouds.http.pool.PoolConstants;
|
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.assistedinject.Assisted;
|
import com.google.inject.assistedinject.Assisted;
|
||||||
import com.google.inject.name.Named;
|
import com.google.inject.name.Named;
|
||||||
|
@ -84,12 +89,24 @@ public class NioHttpCommandConnectionPool extends HttpCommandConnectionPool<NHtt
|
||||||
@Named(PoolConstants.PROPERTY_POOL_MAX_SESSION_FAILURES) int maxSessionFailures,
|
@Named(PoolConstants.PROPERTY_POOL_MAX_SESSION_FAILURES) int maxSessionFailures,
|
||||||
@Assisted URI endPoint) throws Exception {
|
@Assisted URI endPoint) throws Exception {
|
||||||
super(executor, allConnections, commandQueue, maxConnectionReuse, available, endPoint);
|
super(executor, allConnections, commandQueue, maxConnectionReuse, available, endPoint);
|
||||||
|
String host = checkNotNull(checkNotNull(endPoint, "endPoint").getHost(), String.format(
|
||||||
|
"Host null for endpoint %s", endPoint));
|
||||||
|
int port = endPoint.getPort();
|
||||||
|
if (endPoint.getScheme().equals("https")) {
|
||||||
|
this.dispatch = provideSSLClientEventDispatch(clientHandler, params);
|
||||||
|
if (port == -1)
|
||||||
|
port = 443;
|
||||||
|
} else {
|
||||||
|
this.dispatch = provideClientEventDispatch(clientHandler, params);
|
||||||
|
if (port == -1)
|
||||||
|
port = 80;
|
||||||
|
}
|
||||||
|
checkArgument(port > 0, String.format("Port %d not in range for endpoint %s", endPoint
|
||||||
|
.getPort(), endPoint));
|
||||||
this.ioReactor = ioReactor;
|
this.ioReactor = ioReactor;
|
||||||
this.dispatch = endPoint.getScheme().equals("https") ? provideSSLClientEventDispatch(
|
|
||||||
clientHandler, params) : provideClientEventDispatch(clientHandler, params);
|
|
||||||
this.maxSessionFailures = maxSessionFailures;
|
this.maxSessionFailures = maxSessionFailures;
|
||||||
this.sessionCallback = new NHttpClientConnectionPoolSessionRequestCallback();
|
this.sessionCallback = new NHttpClientConnectionPoolSessionRequestCallback();
|
||||||
this.target = new InetSocketAddress(endPoint.getHost(), endPoint.getPort());
|
this.target = new InetSocketAddress(host, port);
|
||||||
clientHandler.setEventListener(this);
|
clientHandler.setEventListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,8 +188,8 @@ public class NioHttpCommandConnectionPool extends HttpCommandConnectionPool<NHtt
|
||||||
boolean acquired = allConnections.tryAcquire(1, TimeUnit.SECONDS);
|
boolean acquired = allConnections.tryAcquire(1, TimeUnit.SECONDS);
|
||||||
if (acquired) {
|
if (acquired) {
|
||||||
if (shouldDoWork()) {
|
if (shouldDoWork()) {
|
||||||
logger.debug("%1$s - opening new connection", target);
|
logger.debug("%1$s - opening new connection", getTarget());
|
||||||
ioReactor.connect(target, null, null, sessionCallback);
|
ioReactor.connect(getTarget(), null, null, sessionCallback);
|
||||||
} else {
|
} else {
|
||||||
allConnections.release();
|
allConnections.release();
|
||||||
}
|
}
|
||||||
|
@ -187,8 +204,8 @@ public class NioHttpCommandConnectionPool extends HttpCommandConnectionPool<NHtt
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected NioHttpCommandConnectionHandle getHandleFromConnection(NHttpConnection connection) {
|
protected NioHttpCommandConnectionHandle getHandleFromConnection(NHttpConnection connection) {
|
||||||
return (NioHttpCommandConnectionHandle) connection.getContext().getAttribute(
|
return (NioHttpCommandConnectionHandle) connection.getContext()
|
||||||
"command-handle");
|
.getAttribute("command-handle");
|
||||||
}
|
}
|
||||||
|
|
||||||
class NHttpClientConnectionPoolSessionRequestCallback implements SessionRequestCallback {
|
class NHttpClientConnectionPoolSessionRequestCallback implements SessionRequestCallback {
|
||||||
|
@ -234,7 +251,7 @@ public class NioHttpCommandConnectionPool extends HttpCommandConnectionPool<NHtt
|
||||||
logger.error(request.getException(),
|
logger.error(request.getException(),
|
||||||
"%1$s->%2$s[%3$s] - SessionRequest failures: %4$s, Disabling pool for %5$s",
|
"%1$s->%2$s[%3$s] - SessionRequest failures: %4$s, Disabling pool for %5$s",
|
||||||
request.getLocalAddress(), request.getRemoteAddress(), maxSessionFailures,
|
request.getLocalAddress(), request.getRemoteAddress(), maxSessionFailures,
|
||||||
target);
|
getTarget());
|
||||||
exception.set(request.getException());
|
exception.set(request.getException());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,12 +283,23 @@ public class NioHttpCommandConnectionPool extends HttpCommandConnectionPool<NHtt
|
||||||
}
|
}
|
||||||
|
|
||||||
public void fatalIOException(IOException ex, NHttpConnection conn) {
|
public void fatalIOException(IOException ex, NHttpConnection conn) {
|
||||||
logger.error(ex, "%3$s-%1$s{%2$d} - io error", conn, conn.hashCode(), target);
|
logger.error(ex, "%3$s-%1$s{%2$d} - io error", conn, conn.hashCode(), getTarget());
|
||||||
resubmitIfRequestIsReplayable(conn, ex);
|
HttpCommandRendezvous<?> rendezvous = getCommandFromConnection(conn);
|
||||||
|
if (rendezvous != null) {
|
||||||
|
/**
|
||||||
|
* these exceptions, while technically i/o are unresolvable. set the error on the command
|
||||||
|
* itself so that it doesn't replay.
|
||||||
|
*/
|
||||||
|
if (ex instanceof UnmappableCharacterException) {
|
||||||
|
setExceptionOnCommand(ex, rendezvous);
|
||||||
|
} else {
|
||||||
|
resubmitIfRequestIsReplayable(conn, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void fatalProtocolException(HttpException ex, NHttpConnection conn) {
|
public void fatalProtocolException(HttpException ex, NHttpConnection conn) {
|
||||||
logger.error(ex, "%3$s-%1$s{%2$d} - http error", conn, conn.hashCode(), target);
|
logger.error(ex, "%3$s-%1$s{%2$d} - http error", conn, conn.hashCode(), getTarget());
|
||||||
setExceptionOnCommand(conn, ex);
|
setExceptionOnCommand(conn, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,8 +307,8 @@ public class NioHttpCommandConnectionPool extends HttpCommandConnectionPool<NHtt
|
||||||
protected NioHttpCommandConnectionHandle createHandle(HttpCommandRendezvous<?> command,
|
protected NioHttpCommandConnectionHandle createHandle(HttpCommandRendezvous<?> command,
|
||||||
NHttpConnection conn) {
|
NHttpConnection conn) {
|
||||||
try {
|
try {
|
||||||
return new NioHttpCommandConnectionHandle(allConnections, available, endPoint,
|
return new NioHttpCommandConnectionHandle(allConnections, available, endPoint, command,
|
||||||
command, conn);
|
conn);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
throw new RuntimeException("Interrupted creating a handle to " + conn, e);
|
throw new RuntimeException("Interrupted creating a handle to " + conn, e);
|
||||||
}
|
}
|
||||||
|
@ -291,4 +319,9 @@ public class NioHttpCommandConnectionPool extends HttpCommandConnectionPool<NHtt
|
||||||
return rendezvous.getCommand().isReplayable();
|
return rendezvous.getCommand().isReplayable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
InetSocketAddress getTarget() {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -107,7 +107,7 @@ public class NioHttpCommandExecutionHandler implements NHttpRequestExecutionHand
|
||||||
HttpCommandRendezvous<?> rendezvous = handle.getCommandRendezvous();
|
HttpCommandRendezvous<?> rendezvous = handle.getCommandRendezvous();
|
||||||
HttpCommand command = rendezvous.getCommand();
|
HttpCommand command = rendezvous.getCommand();
|
||||||
org.jclouds.http.HttpResponse response = NioHttpUtils.convertToJavaCloudsResponse(
|
org.jclouds.http.HttpResponse response = NioHttpUtils.convertToJavaCloudsResponse(
|
||||||
command.getRequest().getEndpoint().toURL(), apacheResponse);
|
command.getRequest().getEndpoint(), apacheResponse);
|
||||||
int statusCode = response.getStatusCode();
|
int statusCode = response.getStatusCode();
|
||||||
// TODO determine how to get the original request here so we don't need to build each
|
// TODO determine how to get the original request here so we don't need to build each
|
||||||
// time
|
// time
|
||||||
|
|
|
@ -27,7 +27,7 @@ import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URL;
|
import java.net.URI;
|
||||||
|
|
||||||
import javax.ws.rs.core.HttpHeaders;
|
import javax.ws.rs.core.HttpHeaders;
|
||||||
|
|
||||||
|
@ -45,9 +45,11 @@ import org.jclouds.http.HttpResponse;
|
||||||
public class NioHttpUtils {
|
public class NioHttpUtils {
|
||||||
public static HttpEntityEnclosingRequest convertToApacheRequest(HttpRequest request) {
|
public static HttpEntityEnclosingRequest convertToApacheRequest(HttpRequest request) {
|
||||||
|
|
||||||
String path = request.getEndpoint().getPath() + request.getEndpoint().getQuery();
|
String path = request.getEndpoint().getRawPath();
|
||||||
|
if (request.getEndpoint().getQuery() != null)
|
||||||
|
path += "?" + request.getEndpoint().getQuery();
|
||||||
BasicHttpEntityEnclosingRequest apacheRequest = new BasicHttpEntityEnclosingRequest(request
|
BasicHttpEntityEnclosingRequest apacheRequest = new BasicHttpEntityEnclosingRequest(request
|
||||||
.getMethod().toString(), path, HttpVersion.HTTP_1_1);
|
.getMethod(), path, HttpVersion.HTTP_1_1);
|
||||||
|
|
||||||
Object content = request.getEntity();
|
Object content = request.getEntity();
|
||||||
|
|
||||||
|
@ -103,9 +105,9 @@ public class NioHttpUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static HttpResponse convertToJavaCloudsResponse(URL requestURL,
|
public static HttpResponse convertToJavaCloudsResponse(URI uri,
|
||||||
org.apache.http.HttpResponse apacheResponse) throws IOException {
|
org.apache.http.HttpResponse apacheResponse) throws IOException {
|
||||||
HttpResponse response = new HttpResponse(requestURL);
|
HttpResponse response = new HttpResponse(uri);
|
||||||
if (apacheResponse.getEntity() != null) {
|
if (apacheResponse.getEntity() != null) {
|
||||||
response.setContent(apacheResponse.getEntity().getContent());
|
response.setContent(apacheResponse.getEntity().getContent());
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
* ====================================================================
|
||||||
|
*/
|
||||||
|
package org.jclouds.http.httpnio.pool;
|
||||||
|
|
||||||
|
import static org.easymock.classextension.EasyMock.createNiceMock;
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import org.apache.http.nio.protocol.AsyncNHttpClientHandler;
|
||||||
|
import org.apache.http.params.HttpParams;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests parsing of nio
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Test(testName = "httpnio.NioHttpCommandConnectionPool")
|
||||||
|
public class NioHttpCommandConnectionPoolTest {
|
||||||
|
|
||||||
|
public void testConstructorGoodPort() throws Exception {
|
||||||
|
NioHttpCommandConnectionPool pool = new NioHttpCommandConnectionPool(null, null, null, null,
|
||||||
|
createNiceMock(AsyncNHttpClientHandler.class), null,
|
||||||
|
createNiceMock(HttpParams.class), 0, 0, URI.create("http://localhost:80"));
|
||||||
|
assertEquals(pool.getTarget(), new InetSocketAddress("localhost", 80));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testConstructorGoodSSLPort() throws Exception {
|
||||||
|
NioHttpCommandConnectionPool pool = new NioHttpCommandConnectionPool(null, null, null, null,
|
||||||
|
createNiceMock(AsyncNHttpClientHandler.class), null,
|
||||||
|
createNiceMock(HttpParams.class), 0, 0, URI.create("https://localhost:443"));
|
||||||
|
assertEquals(pool.getTarget(), new InetSocketAddress("localhost", 443));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testConstructorUnspecifiedPort() throws Exception {
|
||||||
|
NioHttpCommandConnectionPool pool = new NioHttpCommandConnectionPool(null, null, null, null,
|
||||||
|
createNiceMock(AsyncNHttpClientHandler.class), null,
|
||||||
|
createNiceMock(HttpParams.class), 0, 0, URI.create("http://localhost"));
|
||||||
|
assertEquals(pool.getTarget(), new InetSocketAddress("localhost", 80));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testConstructorUnspecifiedSSLPort() throws Exception {
|
||||||
|
NioHttpCommandConnectionPool pool = new NioHttpCommandConnectionPool(null, null, null, null,
|
||||||
|
createNiceMock(AsyncNHttpClientHandler.class), null,
|
||||||
|
createNiceMock(HttpParams.class), 0, 0, URI.create("https://localhost"));
|
||||||
|
assertEquals(pool.getTarget(), new InetSocketAddress("localhost", 443));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expectedExceptions = NullPointerException.class)
|
||||||
|
public void testConstructorNullURI() throws Exception {
|
||||||
|
new NioHttpCommandConnectionPool(null, null, null, null,
|
||||||
|
createNiceMock(AsyncNHttpClientHandler.class), null,
|
||||||
|
createNiceMock(HttpParams.class), 0, 0, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testConstructorWeirdName() throws Exception {
|
||||||
|
NioHttpCommandConnectionPool pool = new NioHttpCommandConnectionPool(null, null, null, null,
|
||||||
|
createNiceMock(AsyncNHttpClientHandler.class), null,
|
||||||
|
createNiceMock(HttpParams.class), 0, 0, URI
|
||||||
|
.create("http://adriancole.blobstore1138eu.s3-external-3.amazonaws.com"));
|
||||||
|
assertEquals(pool.getTarget(), new InetSocketAddress(
|
||||||
|
"adriancole.blobstore1138eu.s3-external-3.amazonaws.com", 80));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
* ====================================================================
|
||||||
|
*/
|
||||||
|
package org.jclouds.http.httpnio.util;
|
||||||
|
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import org.apache.http.HttpEntityEnclosingRequest;
|
||||||
|
import org.jclouds.http.HttpRequest;
|
||||||
|
import org.mortbay.jetty.HttpMethods;
|
||||||
|
import org.testng.annotations.DataProvider;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMultimap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests parsing of nio
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Test(testName = "httpnio.NioHttpUtilsTest")
|
||||||
|
public class NioHttpUtilsTest {
|
||||||
|
@DataProvider(name = "gets")
|
||||||
|
public Object[][] createData() {
|
||||||
|
return new Object[][] { { "object" }, { "/path" }, { "sp%20ace" }, { "unic¿de" },
|
||||||
|
{ "qu?stion" } };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(dataProvider = "gets")
|
||||||
|
public void testConvert(String uri) {
|
||||||
|
HttpEntityEnclosingRequest apacheRequest = NioHttpUtils
|
||||||
|
.convertToApacheRequest(new HttpRequest(HttpMethods.GET, URI
|
||||||
|
.create("https://s3.amazonaws.com:443/" + uri), ImmutableMultimap.of(
|
||||||
|
"Host", "s3.amazonaws.com")));
|
||||||
|
assertEquals(apacheRequest.getHeaders("Host")[0].getValue(), "s3.amazonaws.com");
|
||||||
|
assertEquals(apacheRequest.getRequestLine().getMethod(), "GET");
|
||||||
|
assertEquals(apacheRequest.getRequestLine().getUri(), "/" + uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testConvertWithQuery() {
|
||||||
|
HttpEntityEnclosingRequest apacheRequest = NioHttpUtils
|
||||||
|
.convertToApacheRequest(new HttpRequest(HttpMethods.GET, URI
|
||||||
|
.create("https://s3.amazonaws.com:443/?max-keys=0"), ImmutableMultimap.of(
|
||||||
|
"Host", "s3.amazonaws.com")));
|
||||||
|
assertEquals(apacheRequest.getHeaders("Host")[0].getValue(), "s3.amazonaws.com");
|
||||||
|
assertEquals(apacheRequest.getRequestLine().getMethod(), "GET");
|
||||||
|
assertEquals(apacheRequest.getRequestLine().getUri(), "/?max-keys=0");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue