diff --git a/core/src/main/java/org/jclouds/Constants.java b/core/src/main/java/org/jclouds/Constants.java index f9d89f8361..388cc25700 100644 --- a/core/src/main/java/org/jclouds/Constants.java +++ b/core/src/main/java/org/jclouds/Constants.java @@ -339,6 +339,13 @@ public final class Constants { */ public static final String PROPERTY_STRIP_EXPECT_HEADER = "jclouds.strip-expect-header"; + /** + * String property. + *

+ * This will override the user agent header in http request. + */ + public static final String PROPERTY_USER_AGENT = "jclouds.user-agent"; + /** * When true, add the Connection: close header. Useful when interacting with * providers that don't properly support persistent connections. Defaults to false. diff --git a/core/src/main/java/org/jclouds/apis/internal/BaseApiMetadata.java b/core/src/main/java/org/jclouds/apis/internal/BaseApiMetadata.java index e516e2361d..e074a6c125 100644 --- a/core/src/main/java/org/jclouds/apis/internal/BaseApiMetadata.java +++ b/core/src/main/java/org/jclouds/apis/internal/BaseApiMetadata.java @@ -33,6 +33,7 @@ import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL; import static org.jclouds.Constants.PROPERTY_SO_TIMEOUT; import static org.jclouds.Constants.PROPERTY_STRIP_EXPECT_HEADER; import static org.jclouds.Constants.PROPERTY_USER_THREADS; +import static org.jclouds.Constants.PROPERTY_USER_AGENT; import static org.jclouds.reflect.Reflection2.typeToken; import java.net.URI; @@ -40,6 +41,7 @@ import java.util.Properties; import java.util.Set; import org.jclouds.Context; +import org.jclouds.JcloudsVersion; import org.jclouds.View; import org.jclouds.apis.ApiMetadata; @@ -75,6 +77,10 @@ public abstract class BaseApiMetadata implements ApiMetadata { props.setProperty(PROPERTY_SESSION_INTERVAL, 60 + ""); props.setProperty(PROPERTY_PRETTY_PRINT_PAYLOADS, "true"); props.setProperty(PROPERTY_STRIP_EXPECT_HEADER, "false"); + props.setProperty(PROPERTY_USER_AGENT, + String.format("jclouds/%s java/%s", + JcloudsVersion.get(), + System.getProperty("java.version"))); props.setProperty(PROPERTY_CONNECTION_CLOSE_HEADER, "false"); // By default, we allow maximum parallel deletes to be equal to the number diff --git a/core/src/main/java/org/jclouds/http/internal/JavaUrlHttpCommandExecutorService.java b/core/src/main/java/org/jclouds/http/internal/JavaUrlHttpCommandExecutorService.java index 468f500db7..f64f4a797e 100644 --- a/core/src/main/java/org/jclouds/http/internal/JavaUrlHttpCommandExecutorService.java +++ b/core/src/main/java/org/jclouds/http/internal/JavaUrlHttpCommandExecutorService.java @@ -22,6 +22,7 @@ import static com.google.common.net.HttpHeaders.CONTENT_LENGTH; import static com.google.common.net.HttpHeaders.HOST; import static com.google.common.net.HttpHeaders.USER_AGENT; import static org.jclouds.Constants.PROPERTY_IDEMPOTENT_METHODS; +import static org.jclouds.Constants.PROPERTY_USER_AGENT; import static org.jclouds.http.HttpUtils.filterOutContentHeaders; import static org.jclouds.io.Payloads.newInputStreamPayload; import static org.jclouds.util.Closeables2.closeQuietly; @@ -43,7 +44,6 @@ import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; -import org.jclouds.JcloudsVersion; import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpUtils; @@ -64,22 +64,20 @@ import com.google.inject.Inject; @Singleton public class JavaUrlHttpCommandExecutorService extends BaseHttpCommandExecutorService { - - public static final String DEFAULT_USER_AGENT = String.format("jclouds/%s java/%s", JcloudsVersion.get(), - System.getProperty("java.version")); - protected final Supplier untrustedSSLContextProvider; protected final Function proxyForURI; protected final HostnameVerifier verifier; @Inject(optional = true) protected Supplier sslContextSupplier; + protected final String userAgent; @Inject public JavaUrlHttpCommandExecutorService(HttpUtils utils, ContentMetadataCodec contentMetadataCodec, DelegatingRetryHandler retryHandler, IOExceptionRetryHandler ioRetryHandler, DelegatingErrorHandler errorHandler, HttpWire wire, @Named("untrusted") HostnameVerifier verifier, @Named("untrusted") Supplier untrustedSSLContextProvider, Function proxyForURI, - @Named(PROPERTY_IDEMPOTENT_METHODS) String idempotentMethods) { + @Named(PROPERTY_IDEMPOTENT_METHODS) String idempotentMethods, + @Named(PROPERTY_USER_AGENT) String userAgent) { super(utils, contentMetadataCodec, retryHandler, ioRetryHandler, errorHandler, wire, idempotentMethods); if (utils.getMaxConnections() > 0) { System.setProperty("http.maxConnections", String.valueOf(checkNotNull(utils, "utils").getMaxConnections())); @@ -87,6 +85,7 @@ public class JavaUrlHttpCommandExecutorService extends BaseHttpCommandExecutorSe this.untrustedSSLContextProvider = checkNotNull(untrustedSSLContextProvider, "untrustedSSLContextProvider"); this.verifier = checkNotNull(verifier, "verifier"); this.proxyForURI = checkNotNull(proxyForURI, "proxyForURI"); + this.userAgent = userAgent; } @Override @@ -149,7 +148,7 @@ public class JavaUrlHttpCommandExecutorService extends BaseHttpCommandExecutorSe } connection.setRequestProperty(HOST, host); if (connection.getRequestProperty(USER_AGENT) == null) { - connection.setRequestProperty(USER_AGENT, DEFAULT_USER_AGENT); + connection.setRequestProperty(USER_AGENT, userAgent); } Payload payload = request.getPayload(); if (payload != null) { diff --git a/core/src/test/java/org/jclouds/http/internal/TrackingJavaUrlHttpCommandExecutorService.java b/core/src/test/java/org/jclouds/http/internal/TrackingJavaUrlHttpCommandExecutorService.java index 65cd854554..35fe0ef67f 100644 --- a/core/src/test/java/org/jclouds/http/internal/TrackingJavaUrlHttpCommandExecutorService.java +++ b/core/src/test/java/org/jclouds/http/internal/TrackingJavaUrlHttpCommandExecutorService.java @@ -17,6 +17,7 @@ package org.jclouds.http.internal; import static org.jclouds.Constants.PROPERTY_IDEMPOTENT_METHODS; +import static org.jclouds.Constants.PROPERTY_USER_AGENT; import java.net.Proxy; import java.net.URI; @@ -90,10 +91,11 @@ public class TrackingJavaUrlHttpCommandExecutorService extends JavaUrlHttpComman DelegatingErrorHandler errorHandler, HttpWire wire, @Named("untrusted") HostnameVerifier verifier, @Named("untrusted") Supplier untrustedSSLContextProvider, Function proxyForURI, List commandsInvoked, - @Named(PROPERTY_IDEMPOTENT_METHODS) String idempotentMethods) + @Named(PROPERTY_IDEMPOTENT_METHODS) String idempotentMethods, + @Named(PROPERTY_USER_AGENT) String userAgent) throws SecurityException, NoSuchFieldException { super(utils, contentMetadataCodec, retryHandler, ioRetryHandler, errorHandler, wire, verifier, - untrustedSSLContextProvider, proxyForURI, idempotentMethods); + untrustedSSLContextProvider, proxyForURI, idempotentMethods, userAgent); this.commandsInvoked = commandsInvoked; } diff --git a/drivers/apachehc/src/main/java/org/jclouds/http/apachehc/ApacheHCHttpCommandExecutorService.java b/drivers/apachehc/src/main/java/org/jclouds/http/apachehc/ApacheHCHttpCommandExecutorService.java index cfca7ca7ef..3ef7af99c5 100644 --- a/drivers/apachehc/src/main/java/org/jclouds/http/apachehc/ApacheHCHttpCommandExecutorService.java +++ b/drivers/apachehc/src/main/java/org/jclouds/http/apachehc/ApacheHCHttpCommandExecutorService.java @@ -19,6 +19,7 @@ package org.jclouds.http.apachehc; import static com.google.common.hash.Hashing.md5; import static com.google.common.io.BaseEncoding.base64; import static org.jclouds.Constants.PROPERTY_IDEMPOTENT_METHODS; +import static org.jclouds.Constants.PROPERTY_USER_AGENT; import static org.jclouds.http.HttpUtils.filterOutContentHeaders; import java.io.IOException; @@ -28,6 +29,7 @@ import javax.inject.Inject; import javax.inject.Named; import org.apache.http.Header; +import org.apache.http.HttpHeaders; import org.apache.http.HttpHost; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; @@ -54,15 +56,18 @@ import com.google.common.collect.Multimap; public class ApacheHCHttpCommandExecutorService extends BaseHttpCommandExecutorService { private final HttpClient client; private final ApacheHCUtils apacheHCUtils; + private final String userAgent; @Inject ApacheHCHttpCommandExecutorService(HttpUtils utils, ContentMetadataCodec contentMetadataCodec, DelegatingRetryHandler retryHandler, IOExceptionRetryHandler ioRetryHandler, DelegatingErrorHandler errorHandler, HttpWire wire, HttpClient client, - @Named(PROPERTY_IDEMPOTENT_METHODS) String idempotentMethods) { + @Named(PROPERTY_IDEMPOTENT_METHODS) String idempotentMethods, + @Named(PROPERTY_USER_AGENT) String userAgent) { super(utils, contentMetadataCodec, retryHandler, ioRetryHandler, errorHandler, wire, idempotentMethods); this.client = client; this.apacheHCUtils = new ApacheHCUtils(contentMetadataCodec); + this.userAgent = userAgent; } @Override @@ -73,6 +78,10 @@ public class ApacheHCHttpCommandExecutorService extends BaseHttpCommandExecutorS returnVal.addHeader("Content-MD5", md5); } + if (!returnVal.containsHeader(HttpHeaders.USER_AGENT)) { + returnVal.addHeader(HttpHeaders.USER_AGENT, userAgent); + } + return returnVal; } diff --git a/drivers/okhttp/src/main/java/org/jclouds/http/okhttp/OkHttpCommandExecutorService.java b/drivers/okhttp/src/main/java/org/jclouds/http/okhttp/OkHttpCommandExecutorService.java index f3e4ed07da..ddf62c1451 100644 --- a/drivers/okhttp/src/main/java/org/jclouds/http/okhttp/OkHttpCommandExecutorService.java +++ b/drivers/okhttp/src/main/java/org/jclouds/http/okhttp/OkHttpCommandExecutorService.java @@ -20,6 +20,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.net.HttpHeaders.ACCEPT; import static com.google.common.net.HttpHeaders.USER_AGENT; import static org.jclouds.Constants.PROPERTY_IDEMPOTENT_METHODS; +import static org.jclouds.Constants.PROPERTY_USER_AGENT; import static org.jclouds.http.HttpUtils.filterOutContentHeaders; import static org.jclouds.io.Payloads.newInputStreamPayload; @@ -34,7 +35,6 @@ import okio.BufferedSink; import okio.Okio; import okio.Source; -import org.jclouds.JcloudsVersion; import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpUtils; @@ -59,21 +59,20 @@ import com.squareup.okhttp.RequestBody; import com.squareup.okhttp.Response; public final class OkHttpCommandExecutorService extends BaseHttpCommandExecutorService { - - private static final String DEFAULT_USER_AGENT = String.format("jclouds-okhttp/%s java/%s", JcloudsVersion.get(), - System.getProperty("java.version")); - private final Function proxyForURI; private final OkHttpClient globalClient; + private final String userAgent; @Inject OkHttpCommandExecutorService(HttpUtils utils, ContentMetadataCodec contentMetadataCodec, DelegatingRetryHandler retryHandler, IOExceptionRetryHandler ioRetryHandler, DelegatingErrorHandler errorHandler, HttpWire wire, Function proxyForURI, OkHttpClient okHttpClient, - @Named(PROPERTY_IDEMPOTENT_METHODS) String idempotentMethods) { + @Named(PROPERTY_IDEMPOTENT_METHODS) String idempotentMethods, + @Named(PROPERTY_USER_AGENT) String userAgent) { super(utils, contentMetadataCodec, retryHandler, ioRetryHandler, errorHandler, wire, idempotentMethods); this.proxyForURI = proxyForURI; this.globalClient = okHttpClient; + this.userAgent = userAgent; } @Override @@ -105,7 +104,7 @@ public final class OkHttpCommandExecutorService extends BaseHttpCommandExecutorS builder.addHeader(ACCEPT, "*/*"); } if (request.getFirstHeaderOrNull(USER_AGENT) == null) { - builder.addHeader(USER_AGENT, DEFAULT_USER_AGENT); + builder.addHeader(USER_AGENT, userAgent); } for (Map.Entry entry : request.getHeaders().entries()) { builder.addHeader(entry.getKey(), entry.getValue()); diff --git a/providers/dynect/src/main/java/org/jclouds/dynect/v3/config/DynECTHttpApiModule.java b/providers/dynect/src/main/java/org/jclouds/dynect/v3/config/DynECTHttpApiModule.java index bfc12a71c4..a4ca1944c3 100644 --- a/providers/dynect/src/main/java/org/jclouds/dynect/v3/config/DynECTHttpApiModule.java +++ b/providers/dynect/src/main/java/org/jclouds/dynect/v3/config/DynECTHttpApiModule.java @@ -17,6 +17,7 @@ package org.jclouds.dynect.v3.config; import static org.jclouds.Constants.PROPERTY_IDEMPOTENT_METHODS; +import static org.jclouds.Constants.PROPERTY_USER_AGENT; import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream; import static org.jclouds.rest.config.BinderUtils.bindHttpApi; @@ -104,10 +105,11 @@ public class DynECTHttpApiModule extends HttpApiModule { DelegatingRetryHandler retryHandler, IOExceptionRetryHandler ioRetryHandler, DelegatingErrorHandler errorHandler, HttpWire wire, @Named("untrusted") HostnameVerifier verifier, @Named("untrusted") Supplier untrustedSSLContextProvider, Function proxyForURI, - @Named(PROPERTY_IDEMPOTENT_METHODS) String idempotentMethods) + @Named(PROPERTY_IDEMPOTENT_METHODS) String idempotentMethods, + @Named(PROPERTY_USER_AGENT) String userAgent) throws SecurityException, NoSuchFieldException { super(utils, contentMetadataCodec, retryHandler, ioRetryHandler, errorHandler, wire, verifier, - untrustedSSLContextProvider, proxyForURI, idempotentMethods); + untrustedSSLContextProvider, proxyForURI, idempotentMethods, userAgent); } /** diff --git a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/ResponseStatusFromPayloadHttpCommandExecutorService.java b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/ResponseStatusFromPayloadHttpCommandExecutorService.java index 4887c134b0..8b0f47d83d 100644 --- a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/ResponseStatusFromPayloadHttpCommandExecutorService.java +++ b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/ResponseStatusFromPayloadHttpCommandExecutorService.java @@ -17,6 +17,7 @@ package org.jclouds.profitbricks.http; import static org.jclouds.Constants.PROPERTY_IDEMPOTENT_METHODS; +import static org.jclouds.Constants.PROPERTY_USER_AGENT; import static org.jclouds.util.Closeables2.closeQuietly; import java.io.ByteArrayInputStream; @@ -69,8 +70,10 @@ public class ResponseStatusFromPayloadHttpCommandExecutorService extends JavaUrl DelegatingErrorHandler errorHandler, HttpWire wire, @Named("untrusted") HostnameVerifier verifier, @Named("untrusted") Supplier untrustedSSLContextProvider, Function proxyForURI, ParseSax faultHandler, - @Named(PROPERTY_IDEMPOTENT_METHODS) String idempotentMethods) { - super(utils, contentMetadataCodec, retryHandler, ioRetryHandler, errorHandler, wire, verifier, untrustedSSLContextProvider, proxyForURI, idempotentMethods); + @Named(PROPERTY_IDEMPOTENT_METHODS) String idempotentMethods, + @Named(PROPERTY_USER_AGENT) String userAgent) { + super(utils, contentMetadataCodec, retryHandler, ioRetryHandler, errorHandler, wire, verifier, untrustedSSLContextProvider, proxyForURI, + idempotentMethods, userAgent); this.faultHandler = faultHandler; }