1   package com.atlassian.seraph.cookie;
2   
3   import org.apache.commons.lang.StringUtils;
4   
5   import java.text.SimpleDateFormat;
6   import java.util.Date;
7   import javax.servlet.http.Cookie;
8   import javax.servlet.http.HttpServletResponse;
9   
10  /**
11   * Until we get to Servlet Spec 3.0, we have to roll our own HTTP only support.
12   */
13  public class HttpOnlyCookieKit
14  {
15      private static final String COOKIE_EXPIRE_DF = "EEE, d MMM yyyy HH:mm:ss 'GMT'";
16  
17      /**
18       * See http://tools.ietf.org/html/rfc2965 and http://www.ietf.org/rfc/rfc2109.txt and
19       * http://en.wikipedia.org/wiki/HTTP_cookie for more info
20       * <p/>
21       * I built the code here by reading the spec and then onbserving how Tomcat 5.5 re-acts when you set the versions
22       * and so on.
23       *
24       * @param httpServletResponse the response in play
25       * @param cookie              containing the raw values we want
26       */
27      public static void setCookie(HttpServletResponse httpServletResponse, Cookie cookie)
28      {
29          boolean greaterThanV0 = cookie.getVersion() > 0;
30  
31          StringBuilder sb = new StringBuilder();
32  
33          sb.append(cookie.getName()).append("=").append(esc(cookie.getValue()));
34          if (greaterThanV0)
35          {
36              sb.append("; Version=").append(cookie.getVersion());
37          }
38          if (greaterThanV0 && StringUtils.isNotBlank(cookie.getComment()))
39          {
40              sb.append("; Comment=").append(esc(cookie.getComment()));
41          }
42          if (StringUtils.isNotBlank(cookie.getDomain()))
43          {
44              sb.append("; Domain=").append(esc(cookie.getDomain()));
45          }
46          if (cookie.getMaxAge() >= 0)
47          {
48              if (greaterThanV0)
49              {
50                  sb.append("; Max-Age=").append(cookie.getMaxAge());
51              }
52              else
53              {
54                  sb.append("; Expires=").append(expires(cookie));
55              }
56          }
57          if (StringUtils.isNotBlank(cookie.getPath()))
58          {
59              sb.append("; Path=").append(esc(cookie.getPath()));
60          }
61          if (cookie.getSecure())
62          {
63              sb.append("; Secure");
64          }
65          sb.append("; HttpOnly");
66          httpServletResponse.addHeader("Set-Cookie", sb.toString());
67      }
68  
69      private static String esc(final String value)
70      {
71          if (isToken(value))
72          {
73              return value;
74          }
75          return "\"" + value + "\"";
76      }
77  
78      private static String expires(final Cookie cookie)
79      {
80          final int msMaxAge = cookie.getMaxAge() * 1000;
81          SimpleDateFormat df = new SimpleDateFormat(COOKIE_EXPIRE_DF);
82          return df.format(new Date(System.currentTimeMillis() + msMaxAge));
83      }
84      // Note -- disabled for now to allow full Netscape compatibility
85      // from RFC 2068, token special case characters
86      //
87      // private static final String tspecials = "()<>@,;:\\\"/[]?={} \t";
88  
89      private static final String tspecials = ",;";
90  
91      private static boolean isToken(String value)
92      {
93          int len = value.length();
94  
95          for (int i = 0; i < len; i++)
96          {
97              char c = value.charAt(i);
98  
99              if (c < 0x20 || c >= 0x7f || tspecials.indexOf(c) != -1)
100             {
101                 return false;
102             }
103         }
104         return true;
105     }
106 
107 }