<%@ page language="java" contentType="image/gif" import="java.io.ByteArrayOutputStream, java.io.IOException, java.io.OutputStream, java.io.UnsupportedEncodingException, java.math.BigInteger, java.net.HttpURLConnection, java.net.URLConnection, java.net.URL, java.net.URLEncoder, java.net.URLDecoder, java.security.MessageDigest, java.security.NoSuchAlgorithmException, javax.servlet.http.Cookie, java.util.regex.Pattern, java.util.regex.Matcher, java.util.UUID" %><%! /** Copyright 2009 Google Inc. All Rights Reserved. **/ // Tracker version. private static final String version = "4.4sj"; private static final String COOKIE_NAME = "__utmmobile"; // The path the cookie will be available to, edit this to use a different // cookie path. private static final String COOKIE_PATH = "/"; // Two years in seconds. private static final int COOKIE_USER_PERSISTENCE = 63072000; // 1x1 transparent GIF private static final byte[] GIF_DATA = new byte[] { (byte)0x47, (byte)0x49, (byte)0x46, (byte)0x38, (byte)0x39, (byte)0x61, (byte)0x01, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x80, (byte)0xff, (byte)0x00, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x2c, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x02, (byte)0x02, (byte)0x44, (byte)0x01, (byte)0x00, (byte)0x3b }; // A string is empty in our terms, if it is null, empty or a dash. private static boolean isEmpty(String in) { return in == null || "-".equals(in) || "".equals(in); } // The last octect of the IP address is removed to anonymize the user. private static String getIP(String remoteAddress) { if (isEmpty(remoteAddress)) { return ""; } // Capture the first three octects of the IP address and replace the forth // with 0, e.g. 124.455.3.123 becomes 124.455.3.0 String regex = "^([^.]+\\.[^.]+\\.[^.]+\\.).*"; Pattern getFirstBitOfIPAddress = Pattern.compile(regex); Matcher m = getFirstBitOfIPAddress.matcher(remoteAddress); if (m.matches()) { return m.group(1) + "0"; } else { return ""; } } // Generate a visitor id for this hit. // If there is a visitor id in the cookie, use that, otherwise // use the guid if we have one, otherwise use a random number. private static String getVisitorId( String guid, String account, String userAgent, Cookie cookie) throws NoSuchAlgorithmException, UnsupportedEncodingException { // If there is a value in the cookie, don't change it. if (cookie != null && cookie.getValue() != null) { return cookie.getValue(); } String message; if (!isEmpty(guid)) { // Create the visitor id using the guid. message = guid + account; } else { // otherwise this is a new user, create a new random id. message = userAgent + getRandomNumber() + UUID.randomUUID().toString(); } MessageDigest m = MessageDigest.getInstance("MD5"); m.update(message.getBytes("UTF-8"), 0, message.length()); byte[] sum = m.digest(); BigInteger messageAsNumber = new BigInteger(1, sum); String md5String = messageAsNumber.toString(16); // Pad to make sure id is 32 characters long. while (md5String.length() < 32) { md5String = "0" + md5String; } return "0x" + md5String.substring(0, 16); } // Get a random number string. private static String getRandomNumber() { return Integer.toString((int) (Math.random() * 0x7fffffff)); } // Writes the bytes of a 1x1 transparent gif into the response. private void writeGifData(HttpServletResponse response) throws IOException { response.addHeader( "Cache-Control", "private, no-cache, no-cache=Set-Cookie, proxy-revalidate"); response.addHeader("Pragma", "no-cache"); response.addHeader("Expires", "Wed, 17 Sep 1975 21:32:10 GMT"); ServletOutputStream output = response.getOutputStream(); output.write(GIF_DATA); output.flush(); } // Make a tracking request to Google Analytics from this server. // Copies the headers from the original request to the new one. // If request containg utmdebug parameter, exceptions encountered // communicating with Google Analytics are thown. private void sendRequestToGoogleAnalytics( String utmUrl, HttpServletRequest request) throws Exception { try { URL url = new URL(utmUrl); URLConnection connection = url.openConnection(); connection.setUseCaches(false); connection.addRequestProperty("User-Agent", request.getHeader("User-Agent")); connection.addRequestProperty("Accepts-Language", request.getHeader("Accepts-Language")); connection.getContent(); } catch (Exception e) { if (request.getParameter("utmdebug") != null) { throw new Exception(e); } } } // Track a page view, updates all the cookies and campaign tracker, // makes a server side request to Google Analytics and writes the transparent // gif byte data to the response. private void trackPageView( HttpServletRequest request, HttpServletResponse response) throws Exception { String timeStamp = Long.toString(System.currentTimeMillis() / 1000); String domainName = request.getServerName(); if (isEmpty(domainName)) { domainName = ""; } // Get the referrer from the utmr parameter, this is the referrer to the // page that contains the tracking pixel, not the referrer for tracking // pixel. String documentReferer = request.getParameter("utmr"); if (isEmpty(documentReferer)) { documentReferer = "-"; } else { documentReferer = URLDecoder.decode(documentReferer, "UTF-8"); } String documentPath = request.getParameter("utmp"); if (isEmpty(documentPath)) { documentPath = ""; } else { documentPath = URLDecoder.decode(documentPath, "UTF-8"); } String account = request.getParameter("utmac"); String userAgent = request.getHeader("User-Agent"); if (isEmpty(userAgent)) { userAgent = ""; } // Try and get visitor cookie from the request. Cookie[] cookies = request.getCookies(); Cookie cookie = null; if (cookies != null) { for(int i = 0; i < cookies.length; i++) { if (cookies[i].getName().equals(COOKIE_NAME)) { cookie = cookies[i]; } } } String visitorId = getVisitorId( request.getHeader("X-DCMGUID"), account, userAgent, cookie); // Always try and add the cookie to the response. Cookie newCookie = new Cookie(COOKIE_NAME, visitorId); newCookie.setMaxAge(COOKIE_USER_PERSISTENCE); newCookie.setPath(COOKIE_PATH); response.addCookie(newCookie); String utmGifLocation = "http://www.google-analytics.com/__utm.gif"; // Construct the gif hit url. String utmUrl = utmGifLocation + "?" + "utmwv=" + version + "&utmn=" + getRandomNumber() + "&utmhn=" + URLEncoder.encode(domainName, "UTF-8") + "&utmr=" + URLEncoder.encode(documentReferer, "UTF-8") + "&utmp=" + URLEncoder.encode(documentPath, "UTF-8") + "&utmac=" + account + "&utmcc=__utma%3D999.999.999.999.999.1%3B" + "&utmvid=" + visitorId + "&utmip=" + getIP(request.getRemoteAddr()); sendRequestToGoogleAnalytics(utmUrl, request); // If the debug parameter is on, add a header to the response that contains // the url that was used to contact Google Analytics. if (request.getParameter("utmdebug") != null) { response.setHeader("X-GA-MOBILE-URL", utmUrl); } // Finally write the gif data to the response. writeGifData(response); } %><% // Let exceptions bubble up to container, for better debugging. trackPageView(request, response); %>