View Javadoc
1   /* 
2    * Licensed under the Apache License, Version 2.0 (the "License");
3    * you may not use this file except in compliance with the License.
4    * You may obtain a copy of the License at
5    *
6    * http://www.apache.org/licenses/LICENSE-2.0
7    *
8    * Unless required by applicable law or agreed to in writing, software
9    * distributed under the License is distributed on an "AS IS" BASIS,
10   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11   * See the License for the specific language governing permissions and
12   * limitations under the License.
13   *
14   */
15  
16  package org.esigate.vars;
17  
18  import java.io.IOException;
19  import java.io.InputStream;
20  import java.net.URL;
21  import java.util.Properties;
22  import java.util.regex.Matcher;
23  import java.util.regex.Pattern;
24  
25  import org.apache.commons.lang3.StringUtils;
26  import org.apache.http.cookie.Cookie;
27  import org.esigate.ConfigurationException;
28  import org.esigate.Driver;
29  import org.esigate.DriverFactory;
30  import org.esigate.http.IncomingRequest;
31  import org.esigate.impl.DriverRequest;
32  import org.esigate.util.HttpRequestHelper;
33  import org.esigate.util.UriUtils;
34  import org.slf4j.Logger;
35  import org.slf4j.LoggerFactory;
36  
37  /**
38   * Manage variables replacement.
39   * 
40   * @author Alexis Thaveau
41   * @author Nicolas Richeton
42   */
43  public final class VariablesResolver {
44  
45      private static final Logger LOG = LoggerFactory.getLogger(VariablesResolver.class);
46      private static Pattern userAgentVersion = Pattern.compile("^[A-Za-z]+/([0-9]+\\.[0-9]+)");
47  
48      static {
49          // Load default settings
50          configure();
51      }
52      /**
53       * Properties file
54       */
55      private static Properties properties;
56  
57      private VariablesResolver() {
58      }
59  
60      /**
61       * Loads variables from properties.
62       * 
63       * @param props
64       *            properties
65       */
66      public static void configure(Properties props) {
67          properties = props;
68      }
69  
70      /**
71       * Loads variables according to default configuration file org/esigate/vars.properties.
72       */
73      public static void configure() {
74          InputStream inputStream = null;
75          try {
76              LOG.debug("Loading esigate-vars.properties file");
77              inputStream = Driver.class.getResourceAsStream("/esigate-vars.properties");
78              if (inputStream == null) {
79                  inputStream = Driver.class.getResourceAsStream("vars.properties");
80              }
81              if (inputStream != null) {
82                  properties = new Properties();
83                  properties.load(inputStream);
84              }
85          } catch (IOException e) {
86              throw new ConfigurationException(e);
87          } finally {
88              if (inputStream != null) {
89                  try {
90                      inputStream.close();
91                  } catch (IOException e) {
92                      // nothing to do
93                  }
94              }
95          }
96      }
97  
98      /**
99       * @return The URL of the variables file.
100      */
101     public static URL getVariablessUrl() {
102         URL varsUrl = Driver.class.getResource("/esigate-vars.properties");
103         if (varsUrl == null) {
104             varsUrl = Driver.class.getResource("vars.properties");
105         }
106         return varsUrl;
107     }
108 
109     /**
110      * Regexp to find variables
111      */
112     private static final Pattern VAR_PATTERN = Pattern.compile("\\$\\((.*?)\\)");
113 
114     /**
115      * 
116      * @param strVars
117      *            a String that may contain variables.
118      * @return true if contains variables
119      */
120     static boolean containsVariable(String strVars) {
121         return strVars.contains("$(") && strVars.contains(")");
122     }
123 
124     /**
125      * Replace all ESI variables found in strVars by their matching value in vars.properties.
126      * 
127      * @param strVars
128      *            a String containing variables.
129      * @return The resulting String
130      */
131     public static String replaceAllVariables(String strVars) {
132         return replaceAllVariables(strVars, null);
133     }
134 
135     /**
136      * Replace all ESI variables found in strVars by their matching value in vars.properties.
137      * 
138      * @param strVars
139      *            a String containing variables.
140      * @param request
141      * @return The resulting String
142      */
143     public static String replaceAllVariables(String strVars, DriverRequest request) {
144         String result = strVars;
145         if (VariablesResolver.containsVariable(strVars)) {
146             Matcher matcher = VAR_PATTERN.matcher(strVars);
147 
148             while (matcher.find()) {
149                 String group = matcher.group();
150                 String var = group.substring(2, group.length() - 1);
151                 String arg = null;
152 
153                 // try to find argument
154                 int argIndex = var.indexOf('{');
155                 if (argIndex != -1) {
156                     arg = VarUtils.removeSimpleQuotes(var.substring(argIndex + 1, var.indexOf('}')));
157                 }
158 
159                 // try to find default value
160                 // ESI 1.0 spec :
161                 // 4.2 Variable Default Values
162                 // Variables whose values are empty, nonexistent variables and
163                 // undefined substructures of variables will evaluate to an
164                 // empty string when they are accessed.
165                 String defaultValue = StringUtils.EMPTY;
166                 int defaultValueIndex = var.indexOf('|');
167                 if (defaultValueIndex != -1) {
168                     defaultValue = VarUtils.removeSimpleQuotes(var.substring(defaultValueIndex + 1));
169                 }
170 
171                 String value = getProperty(var, arg, request);
172 
173                 if (value == null) {
174                     value = defaultValue;
175                 }
176 
177                 result = result.replace(group, value);
178 
179             }
180 
181         }
182         return result;
183     }
184 
185     private static String getProperty(String var, String arg, DriverRequest request) {
186         String result = processVar(var, arg, request);
187         if (properties != null) {
188             result = properties.getProperty(var, result);
189         }
190         LOG.debug("Resolve property $({})={}", var, result);
191         return result;
192     }
193 
194     private static String processVar(String var, String arg, DriverRequest request) {
195         IncomingRequest incomingRequest = null;
196         if (request != null) {
197             incomingRequest = request.getOriginalRequest();
198         }
199         String res = null;
200         if (var.contains("QUERY_STRING")) {
201             if (arg == null) {
202                 res = UriUtils.getRawQuery(incomingRequest.getRequestLine().getUri());
203             } else {
204                 res = HttpRequestHelper.getParameter(request, arg);
205             }
206         } else if (var.contains("HTTP_ACCEPT_LANGUAGE")) {
207             String langs = HttpRequestHelper.getFirstHeader("Accept-Language", incomingRequest);
208             if (arg == null) {
209                 res = langs;
210             } else {
211                 res = String.valueOf(!(langs == null || !langs.contains(arg)));
212             }
213         } else if (var.contains("HTTP_HEADER")) {
214             res = HttpRequestHelper.getFirstHeader(arg, incomingRequest);
215         } else if (var.contains("HTTP_HOST")) {
216             res = HttpRequestHelper.getFirstHeader("Host", incomingRequest);
217         } else if (var.contains("HTTP_REFERER")) {
218             res = HttpRequestHelper.getFirstHeader("Referer", incomingRequest);
219         } else if (var.contains("HTTP_COOKIE")) {
220             if (arg == null) {
221                 // Add cookies
222                 // In request header
223                 String cookieHeaderValue = StringUtils.EMPTY;
224                 for (Cookie c : request.getOriginalRequest().getCookies()) {
225                     if (StringUtils.isNotBlank(cookieHeaderValue)) {
226                         cookieHeaderValue = cookieHeaderValue + "; ";
227                     }
228                     cookieHeaderValue = cookieHeaderValue + c.getName() + "=" + c.getValue();
229                 }
230                 if (StringUtils.isNotBlank(cookieHeaderValue)) {
231                     res = cookieHeaderValue;
232                 }
233             } else {
234                 Cookie[] cookies = request.getOriginalRequest().getCookies();
235                 for (Cookie c : cookies) {
236                     if (c.getName().equals(arg)) {
237                         res = c.getValue();
238                         break;
239                     }
240                 }
241             }
242         } else if (var.contains("HTTP_USER_AGENT")) {
243             if (arg == null) {
244                 res = HttpRequestHelper.getFirstHeader("User-agent", incomingRequest);
245             } else {
246                 String userAgent =
247                         StringUtils.defaultString(HttpRequestHelper.getFirstHeader("User-Agent", incomingRequest))
248                                 .toLowerCase();
249                 if (arg.equals("os")) {
250                     if (userAgent.contains("unix")) {
251                         res = "UNIX";
252                     } else if (userAgent.contains("mac")) {
253                         res = "MAC";
254                     } else if (userAgent.contains("windows")) {
255                         res = "WIN";
256                     } else {
257                         res = "OTHER";
258                     }
259                 } else if (arg.equals("browser")) {
260                     if (userAgent.contains("msie")) {
261                         res = "MSIE";
262                     } else {
263                         res = "MOZILLA";
264                     }
265                 } else if (arg.equals("version")) {
266                     Matcher m = userAgentVersion.matcher(userAgent);
267 
268                     if (m.find()) {
269                         res = m.group(1);
270                     }
271                 }
272             }
273         } else if (var.contains("PROVIDER")) {
274             String providerUrl = StringUtils.EMPTY;
275             try {
276                 Driver driver = DriverFactory.getInstance(arg);
277                 providerUrl =
278                         driver.getConfiguration().getBaseUrlRetrieveStrategy().getBaseURL(request.getOriginalRequest());
279             } catch (Exception e) {
280                 // No driver available for this id.
281             }
282 
283             return providerUrl;
284 
285         }
286         return res;
287     }
288 }