/**
* Copyright 2014 ArcBees Inc.
*
* Licensed 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 com.arcbees.analytics.server;
import java.io.IOException;
import java.util.Random;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.arcbees.analytics.server.options.ServerOptionsCallback;
import com.arcbees.analytics.shared.GaAccount;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@Singleton
public class ServerOptionsCallbackProvider implements Filter, Provider<ServerOptionsCallback> {
private static final String[] ipForwardHeaders = {
"X-Forwarded-For",
"Proxy-Client-IP",
"WL-Proxy-Client-IP",
"HTTP_CLIENT_IP",
"HTTP_X_FORWARDED_FOR"};
private static final int ANALYTICS_VERSION = 1;
private static final String COOKIE_VALUE_KEY = "_uaCookie";
private final String userAccount;
private final Random random = new Random();
private final Provider<HttpServletRequest> requestProvider;
@Inject
ServerOptionsCallbackProvider(
@GaAccount String userAccount,
Provider<HttpServletRequest> requestProvider) {
this.userAccount = userAccount;
this.requestProvider = requestProvider;
}
@Override
public void destroy() {
// nothing to destoy
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
if ((request instanceof HttpServletRequest) && (response instanceof HttpServletResponse)) {
doHttpFilter((HttpServletRequest) request, (HttpServletResponse) response, chain);
} else {
chain.doFilter(request, response);
}
}
private void doHttpFilter(HttpServletRequest request, HttpServletResponse response,
FilterChain chain) throws IOException, ServletException {
String cookieValue = null;
final Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (final Cookie cookie : cookies) {
if (cookie.getName().equals("_ga")) {
cookieValue = cookie.getValue();
if (cookieValue.split("\\.").length != 4) {
cookieValue = null;
}
}
}
}
if (cookieValue == null) {
final int hostLevel = request.getServerName().split("\\.").length;
cookieValue = "GA" + ANALYTICS_VERSION + "." + hostLevel + "."
+ random.nextInt(Integer.MAX_VALUE) + "." + (System.currentTimeMillis() / 1000);
final Cookie cookie = new Cookie("_ga", cookieValue);
cookie.setPath("/");
cookie.setDomain("." + request.getServerName());
cookie.setMaxAge(63072000);
response.addCookie(cookie);
}
request.setAttribute(COOKIE_VALUE_KEY, cookieValue);
chain.doFilter(request, response);
}
@Override
public ServerOptionsCallback get() {
final ServerOptionsCallback result = new ServerOptionsCallback();
result.putText("v", ANALYTICS_VERSION + "");
result.putText("tid", userAccount);
result.putText("uip", getClientIpAddr(requestProvider.get()));
final String[] split = ((String) requestProvider.get().getAttribute(COOKIE_VALUE_KEY))
.split("\\.");
result.putText("cid", split[2] + "." + split[3]);
return result;
}
private static String getClientIpAddr(HttpServletRequest request) {
String ip = null;
for (String forwardHeader: ipForwardHeaders) {
ip = request.getHeader(forwardHeader);
if (ip != null && !ip.isEmpty() && !"unknown".equalsIgnoreCase(ip)) {
return ip;
}
}
return request.getRemoteAddr();
}
@Override
public void init(FilterConfig config) throws ServletException {
// nothing to init
}
}