tomcat 服务器下的cookie 实现 详解

cookie 的作用,就是当一个浏览器通过http 请求访问一个服务器时,这个服务器会返回key/value 键值对给客户端浏览器,在servlet 中可以这样增加cookie ,tomcat的 版本是7

public void addcookies(HttpServletResponse response,String key,String value){
		Cookie cookie = new Cookie(key,value);
		response.addCookie(cookie);
	}

生成cookie 对象,将对象增加到httpServletResponse 对象中,用于返回到客户端,在tomcat 服务器中,其实就是调用response 的门面方法。org.apache.catalina.connector.ResponseFacade 的addCookie 方法

  @Override
    public void addCookie(Cookie cookie) {
        //判断response 是否提交
        if (isCommitted()) {
            return;
        }

        response.addCookie(cookie);

    }

  将cookie 对象委托给被装饰的org.apache.catalina.connector.Response 类处理,ResponseFacade  是Responese 类的一个门面类,

 public void addCookie(final Cookie cookie) {

        if (included || isCommitted()) {
            return;
        }
       // 生成符合http 协议 cookie 格式的字符串
        final StringBuffer sb = generateCookieString(cookie);
        //将字符串放到响应头中
        addHeader("Set-Cookie", sb.toString());
    }

 具体的生成方式

扫描二维码关注公众号,回复: 301005 查看本文章
  public StringBuffer generateCookieString(final Cookie cookie) {
        final StringBuffer sb = new StringBuffer();
        //web application code can receive a IllegalArgumentException
        //from the appendCookieValue invocation
        if (SecurityUtil.isPackageProtectionEnabled()) {
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                @Override
                public Void run(){
                    ServerCookie.appendCookieValue
                        (sb, cookie.getVersion(), cookie.getName(),
                         cookie.getValue(), cookie.getPath(),
                         cookie.getDomain(), cookie.getComment(),
                         cookie.getMaxAge(), cookie.getSecure(),
                         cookie.isHttpOnly());
                    return null;
                }
            });
        } else {
            ServerCookie.appendCookieValue
                (sb, cookie.getVersion(), cookie.getName(), cookie.getValue(),
                     cookie.getPath(), cookie.getDomain(), cookie.getComment(),
                     cookie.getMaxAge(), cookie.getSecure(),
                     cookie.isHttpOnly());
        }
        return sb;
    }

 org.apache.tomcat.util.http.ServerCookie 类是处理生成cookie 的一个实体类,继承 Serializable 接口,可以序列化在网络上传输具体生成cookie 的处理逻辑

 public static void appendCookieValue( StringBuffer headerBuf,
                                          int version,
                                          String name,
                                          String value,
                                          String path,
                                          String domain,
                                          String comment,
                                          int maxAge,
                                          boolean isSecure,
                                          boolean isHttpOnly)
    {
        StringBuffer buf = new StringBuffer();
        // Servlet implementation checks name
        buf.append( name );
        buf.append("=");
        // Servlet implementation does not check anything else

        /*
         * The spec allows some latitude on when to send the version attribute
         * with a Set-Cookie header. To be nice to clients, we'll make sure the
         * version attribute is first. That means checking the various things
         * that can cause us to switch to a v1 cookie first.
         *
         * Note that by checking for tokens we will also throw an exception if a
         * control character is encountered.
         */
        // Start by using the version we were asked for
        int newVersion = version;

        // If it is v0, check if we need to switch
        if (newVersion == 0 &&
                (!CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 &&
                 CookieSupport.isHttpToken(value) ||
                 CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 &&
                 CookieSupport.isV0Token(value))) {
            // HTTP token in value - need to use v1
            newVersion = 1;
        }

        if (newVersion == 0 && comment != null) {
            // Using a comment makes it a v1 cookie
           newVersion = 1;
        }

        if (newVersion == 0 &&
                (!CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 &&
                 CookieSupport.isHttpToken(path) ||
                 CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 &&
                 CookieSupport.isV0Token(path))) {
            // HTTP token in path - need to use v1
            newVersion = 1;
        }

        if (newVersion == 0 &&
                (!CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 &&
                 CookieSupport.isHttpToken(domain) ||
                 CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 &&
                 CookieSupport.isV0Token(domain))) {
            // HTTP token in domain - need to use v1
            newVersion = 1;
        }

        // Now build the cookie header
        // Value
        maybeQuote(buf, value);
        // Add version 1 specific information
        if (newVersion == 1) {
            // Version=1 ... required
            buf.append ("; Version=1");

            // Comment=comment
            if ( comment!=null ) {
                buf.append ("; Comment=");
                maybeQuote(buf, comment);
            }
        }

        // Add domain information, if present
        if (domain!=null) {
            buf.append("; Domain=");
            maybeQuote(buf, domain);
        }

        // Max-Age=secs ... or use old "Expires" format
        if (maxAge >= 0) {
            if (newVersion > 0) {
                buf.append ("; Max-Age=");
                buf.append (maxAge);
            }
            // IE6, IE7 and possibly other browsers don't understand Max-Age.
            // They do understand Expires, even with V1 cookies!
            if (newVersion == 0 || CookieSupport.ALWAYS_ADD_EXPIRES) {
                // Wdy, DD-Mon-YY HH:MM:SS GMT ( Expires Netscape format )
                buf.append ("; Expires=");
                // To expire immediately we need to set the time in past
                if (maxAge == 0) {
                    buf.append( ancientDate );
                } else {
                    OLD_COOKIE_FORMAT.get().format(
                            new Date(System.currentTimeMillis() +
                                    maxAge*1000L),
                            buf, new FieldPosition(0));
                }
            }
        }

        // Path=path
        if (path!=null) {
            buf.append ("; Path=");
            maybeQuote(buf, path);
        }

        // Secure
        if (isSecure) {
          buf.append ("; Secure");
        }

        // HttpOnly
        if (isHttpOnly) {
            buf.append("; HttpOnly");
        }
        headerBuf.append(buf);
    }

 tomcat 最终构造响应头的方法在org.apache.coyote.http11.AbstractHttp11Processor 的prepareResponse中,具体片段 

  int size = headers.size();
        for (int i = 0; i < size; i++) {
            getOutputBuffer().sendHeader(headers.getName(i), headers.getValue(i));
        }

 

猜你喜欢

转载自lliang54.iteye.com/blog/2394701