1 /*
2  * Copyright 2010-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License").
5  * You may not use this file except in compliance with the License.
6  * A copy of the License is located at
7  *
8  *  http://aws.amazon.com/apache2.0
9  *
10  * or in the "license" file accompanying this file. This file is distributed
11  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12  * express or implied. See the License for the specific language governing
13  * permissions and limitations under the License.
14  */

15 package com.amazonaws.services.s3.internal;
16
17 import com.amazonaws.SdkClientException;
18 import com.amazonaws.annotation.SdkInternalApi;
19 import com.amazonaws.annotation.ThreadSafe;
20 import com.amazonaws.auth.profile.ProfilesConfigFile;
21 import com.amazonaws.auth.profile.internal.AwsProfileNameLoader;
22 import com.amazonaws.auth.profile.internal.BasicProfile;
23 import com.amazonaws.profile.path.AwsProfileFileLocationProvider;
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26
27 import java.io.File;
28
29 /**
30  * Resolves the regional endpoints option for S3.
31  */

32 @ThreadSafe
33 @SdkInternalApi
34 public final class RegionalEndpointsOptionResolver {
35     private enum Option {
36         LEGACY,
37         REGIONAL
38     }
39     private static final Log log = LogFactory.getLog(RegionalEndpointsOptionResolver.class);
40     private static final String ENV_VAR = "AWS_S3_US_EAST_1_REGIONAL_ENDPOINT";
41     private static final String PROFILE_PROPERTY = "s3_us_east_1_regional_endpoint";
42
43     private final AwsProfileFileLocationProvider configFileLocationProvider;
44
45     private volatile String profileName;
46     private volatile ProfilesConfigFile configFile;
47     private volatile boolean profileLoadAttempted;
48
49     public RegionalEndpointsOptionResolver() {
50         configFileLocationProvider = AwsProfileFileLocationProvider.DEFAULT_CONFIG_LOCATION_PROVIDER;
51     }
52
53     public RegionalEndpointsOptionResolver(AwsProfileFileLocationProvider configFileLocationProvider) {
54         this.configFileLocationProvider = configFileLocationProvider;
55     }
56
57     public boolean useRegionalMode() {
58         Option option = envVarOption();
59         if (option == null) {
60             option = profileOption();
61         }
62         return option == Option.REGIONAL;
63     }
64
65     private Option envVarOption() {
66         String val = System.getenv(ENV_VAR);
67         return resolveOption(val, String.format("Unexpected value set for %s environment variable: '%s'", ENV_VAR,
68                              val));
69     }
70
71     private synchronized Option profileOption() {
72         String profileName = getProfileName();
73         BasicProfile profile = getProfile(profileName);
74         if (profile == null) {
75             return null;
76         }
77         String val = profile.getPropertyValue(PROFILE_PROPERTY);
78         return resolveOption(val, String.format("Unexpected option for '%s' property in profile '%s': %s",
79                              PROFILE_PROPERTY, profileName, val));
80     }
81
82     private Option resolveOption(String value, String errMsg) {
83         if (value == null) {
84             return null;
85         }
86
87         if ("legacy".equalsIgnoreCase(value)) {
88             return Option.LEGACY;
89         }
90
91         if ("regional".equalsIgnoreCase(value)) {
92             return Option.REGIONAL;
93         }
94
95         throw new SdkClientException(errMsg);
96     }
97
98     private String getProfileName() {
99         if (profileName == null) {
100             synchronized (this) {
101                 if (profileName == null) {
102                     profileName = AwsProfileNameLoader.INSTANCE.loadProfileName();
103                 }
104             }
105         }
106         return profileName;
107     }
108
109     private synchronized BasicProfile getProfile(String profileName) {
110         ProfilesConfigFile profilesConfigFile = getProfilesConfigFile();
111         if (profilesConfigFile != null) {
112             return profilesConfigFile.getAllBasicProfiles().get(profileName);
113         }
114         return null;
115     }
116
117     // ProfilesConfigFile immediately loads the profiles at construction time
118     private ProfilesConfigFile getProfilesConfigFile() {
119         if (!profileLoadAttempted) {
120             synchronized (this) {
121                 if (!profileLoadAttempted) {
122                     File location = null;
123                     try {
124                         location = configFileLocationProvider.getLocation();
125                         if (location != null) {
126                             configFile = new ProfilesConfigFile(location);
127                         }
128                     } catch (Exception e) {
129                         if (log.isWarnEnabled()) {
130                             log.warn("Unable to load config file " + location, e);
131                         }
132                     } finally {
133                         profileLoadAttempted = true;
134                     }
135                 }
136             }
137         }
138         return configFile;
139     }
140 }
141