Skip to content

Commit

Permalink
Add User-Agent header to all outbound network requests
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesonwilliams committed Jan 21, 2020
1 parent 5981bdd commit 6f13bc0
Show file tree
Hide file tree
Showing 6 changed files with 224 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
import com.amplifyframework.analytics.AnalyticsException;
import com.amplifyframework.core.Amplify;
import com.amplifyframework.logging.Logger;
import com.amplifyframework.util.UserAgent;

import com.amazonaws.ClientConfiguration;
import com.amazonaws.mobile.client.AWSMobileClient;
import com.amazonaws.mobile.client.Callback;
import com.amazonaws.mobile.client.UserStateDetails;
Expand Down Expand Up @@ -76,14 +78,17 @@ public void onError(Exception exception) {
throw new RuntimeException("Failed to initialize mobile client: " + exception.getLocalizedMessage());
}

ClientConfiguration clientConfiguration = new ClientConfiguration();
clientConfiguration.setUserAgent(UserAgent.string());

// Construct configuration using information from the configure method
PinpointConfiguration pinpointConfiguration = new PinpointConfiguration(
context,
pinpointAnalyticsPluginConfiguration.getAppId(),
Regions.fromName(pinpointAnalyticsPluginConfiguration.getRegion()),
ChannelType.GCM,
AWSMobileClient.getInstance()
);
).withClientConfiguration(clientConfiguration);

pinpointManager = new PinpointManager(pinpointConfiguration);
return pinpointManager.getAnalyticsClient();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import com.amplifyframework.core.Consumer;
import com.amplifyframework.core.model.Model;
import com.amplifyframework.core.model.query.predicate.QueryPredicate;
import com.amplifyframework.util.UserAgent;

import org.json.JSONObject;

Expand Down Expand Up @@ -113,6 +114,7 @@ public void configure(@NonNull JSONObject pluginConfigurationJson, @Nullable Con
final ApiConfiguration apiConfiguration = entry.getValue();
final EndpointType endpointType = apiConfiguration.getEndpointType();
final OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.addNetworkInterceptor(UserAgentInterceptor.using(UserAgent::string));
if (apiConfiguration.getAuthorizationType() != AuthorizationType.NONE) {
builder.addInterceptor(interceptorFactory.create(apiConfiguration));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.amplifyframework.api.graphql.GraphQLResponse;
import com.amplifyframework.core.Action;
import com.amplifyframework.core.Consumer;
import com.amplifyframework.util.UserAgent;

import org.json.JSONException;
import org.json.JSONObject;
Expand Down Expand Up @@ -157,6 +158,7 @@ private WebSocket createWebSocket() throws ApiException {
.build();

return new OkHttpClient.Builder()
.addNetworkInterceptor(UserAgentInterceptor.using(UserAgent::string))
.retryOnConnectionFailure(true)
.build()
.newWebSocket(request, new WebSocketListener() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file 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 com.amplifyframework.api.aws;

import androidx.annotation.NonNull;

import java.io.IOException;

import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;

/**
* An OkHttp3 interceptor which applies a User-Agent header to an outgoing request.
*/
final class UserAgentInterceptor implements Interceptor {
private final UserAgentProvider userAgentProvider;

/**
* Constructs a UserAgentInterceptor.
* @param userAgentProvider A Provider of a user-agent string
*/
private UserAgentInterceptor(final UserAgentProvider userAgentProvider) {
this.userAgentProvider = userAgentProvider;
}

/**
* Creates a user agent interceptor using a user-agent string provider.
* @param userAgentProvider Provider of user-agent string
* @return A UserAgentInterceptor
*/
static UserAgentInterceptor using(UserAgentProvider userAgentProvider) {
return new UserAgentInterceptor(userAgentProvider);
}

@NonNull
@Override
public Response intercept(@NonNull Chain chain) throws IOException {
Request originalRequest = chain.request();
Request requestWithUserAgent = originalRequest.newBuilder()
.header("User-Agent", userAgentProvider.getUserAgent())
.build();
return chain.proceed(requestWithUserAgent);
}

/**
* A provider of a user-agent string.
*/
interface UserAgentProvider {
/**
* Gets the User-Agent string.
* @return User-Agent string
*/
String getUserAgent();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@
import android.content.Intent;

import com.amplifyframework.storage.result.StorageListResult;
import com.amplifyframework.util.UserAgent;

import com.amazonaws.ClientConfiguration;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.mobile.client.AWSMobileClient;
import com.amazonaws.mobileconnectors.s3.transferutility.TransferObserver;
import com.amazonaws.mobileconnectors.s3.transferutility.TransferService;
Expand Down Expand Up @@ -59,7 +62,7 @@ public final class AWSS3StorageService {
public AWSS3StorageService(Region region, Context context, String bucket, boolean transferAcceleration) {
this.context = context;
this.bucket = bucket;
this.client = new AmazonS3Client(AWSMobileClient.getInstance(), region);
this.client = createS3Client(region);

if (transferAcceleration) {
client.setS3ClientOptions(S3ClientOptions.builder().setAccelerateModeEnabled(true).build());
Expand All @@ -71,6 +74,13 @@ public AWSS3StorageService(Region region, Context context, String bucket, boolea
.build();
}

private AmazonS3Client createS3Client(Region region) {
AWSCredentialsProvider credentialsProvider = AWSMobileClient.getInstance();
ClientConfiguration configuration = new ClientConfiguration();
configuration.setUserAgent(UserAgent.string());
return new AmazonS3Client(credentialsProvider, region, configuration);
}

/**
* Begin downloading a file.
* @param serviceKey S3 service key
Expand Down
134 changes: 134 additions & 0 deletions core/src/main/java/com/amplifyframework/util/UserAgent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*
* Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file 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 com.amplifyframework.util;

import android.annotation.SuppressLint;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.amazonaws.amplify.core.BuildConfig;

/**
* A utility to construct a User-Agent header, to be sent with all network operations.
*/
public final class UserAgent {
private static String instance = null;

@SuppressWarnings("checkstyle:all") private UserAgent() {}

/**
* Gets a String to use as the value of a User-Agent header.
* @return A value for a User-Agent header.
*/
@SuppressLint("SyntheticAccessor")
@NonNull
public static String string() {
if (instance == null) {
instance = new UserAgent.Builder()
.libraryName("amplify-android")
.libraryVersion(BuildConfig.VERSION_NAME)
.systemName(System.getProperty("os.name"))
.systemVersion(System.getProperty("os.version"))
.javaVmName(System.getProperty("java.vm.name"))
.javaVmVersion(System.getProperty("java.vm.version"))
.javaVersion(System.getProperty("java.version"))
.userLanguage(System.getProperty("user.language"))
.userRegion(System.getProperty("user.region"))
.toString();
}

return instance;
}

@SuppressWarnings("SameParameterValue")
private static final class Builder {
private String libraryName;
private String libraryVersion;
private String systemName;
private String systemVersion;
private String javaVmName;
private String javaVmVersion;
private String javaVersion;
private String userLanguage;
private String userRegion;

Builder libraryName(String libraryName) {
this.libraryName = sanitize(libraryName);
return this;
}

Builder libraryVersion(String libraryVersion) {
this.libraryVersion = sanitize(libraryVersion);
return this;
}

Builder systemName(String systemName) {
this.systemName = sanitize(systemName);
return this;
}

Builder systemVersion(String systemVersion) {
this.systemVersion = sanitize(systemVersion);
return this;
}

Builder javaVmName(String javaVmName) {
this.javaVmName = sanitize(javaVmName);
return this;
}

Builder javaVmVersion(String javaVmVersion) {
this.javaVmVersion = sanitize(javaVmVersion);
return this;
}

Builder javaVersion(String javaVersion) {
this.javaVersion = sanitize(javaVersion);
return this;
}

Builder userLanguage(String userLanguage) {
this.userLanguage = sanitize(userLanguage);
return this;
}

Builder userRegion(String userRegion) {
this.userRegion = sanitize(userRegion);
return this;
}

@NonNull
@Override
public String toString() {
return String.format(
"%s/%s %s/%s %s/%s/%s %s_%s",
libraryName, libraryVersion,
systemName, systemVersion,
javaVmName, javaVmVersion, javaVersion,
userLanguage, userRegion
);
}

@NonNull
private static String sanitize(@Nullable String string) {
if (string == null) {
return "UNKNOWN";
}

return string.replace(' ', '_');
}
}
}

0 comments on commit 6f13bc0

Please sign in to comment.