Servlet规范系列 之 Cookie源码分析

欢迎大家关注本博,同时欢迎大家评论交流,可以给个赞哦!!!

  谈到Cookie,就得说到会话跟踪技术,在Web发展早期,Cookie是会话跟踪技术的不二选择,拥有统一的实现标准。在基于无状态的HTTP协议进行服务搭建时,如何保持更加安全、简便的保持会话,就成了首要问题,Cookie技术就应运而生了。

  Cookie是由一个键和一个值构成的,由服务器创建,随着服务器响应发送给客户端浏览器。客户端浏览器会把Cookie保存下来,下一次访问服务器时把服务器发送的Cookie再发送给服务器。单独来说Cookie的话,其实属于客户端应用,与之对应的Session属于服务器端应用,两者的交集就是保持会话的基础。

  对于Cookie的内容不做过多的分析,在Cookie源码注释中都进行了标注。

  Cookie

  对于Servlet中Cookie,HttpServletRequest的getCookies提供了Cookie读取的功能,HttpServletResponse的addCookie提供了Cookie写入的功能。

package javax.servlet.http;

import java.text.MessageFormat;
import java.util.ResourceBundle;

/**
 * 创建一个Cookie,Servlet发送到Web浏览器,由浏览器保存并稍后发送回服务器的少量信息.
 * Cookie的值可以唯一地标识客户端,因此Cookie通常用于会话管理.
 * Cookie有一个名称、一个值和可选属性(如注释、路径和域限定符、最长期限和版本号).
 * 一些Web浏览器在处理可选属性的方式上存在缺陷,因此要谨慎使用它们来提高servlet的互操作性.
 * Servlet使用HttpServletResponse.addCookie方法将Cookie发送到浏览器,该方法向HTTP响应头添加字段,以便一次发送一个cookie到浏览器.
 * 浏览器预计支持每个Web服务器20个cookie,总共300个cookie,并且每个cookie大小限制为4kb.随着客户端浏览器的发展,这一项现在的容量已经大大提供了.
 * 浏览器通过向HTTP请求头添加字段来将cookies返回给servlet.可以使用HttpServletRequest.getCookies方法从请求中检索Cookies.
 * 多个cookie可能具有相同的名称,但路径属性不同.
 * Cookie会影响使用它们的网页的缓存.HTTP1.0不缓存使用此类创建的Cookie的页面.此类不支持用HTTP1.1定义的缓存控件.
 * 此类同时支持版本0(Netscape的Cookie规范)和版本1(W3C的RFC2109规范)Cookie规范.默认情况下,Cookie是使用版本0创建的,以确保最佳互操作性.
 */
public class Cookie implements Cloneable {
    
    

    /**
     * 错误信息模板位置.
     */
    private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings";
    
    /**
     * 错误信息模板加载.
     */
    private static ResourceBundle lStrings = ResourceBundle.getBundle(LSTRING_FILE);

    /**
     * Cookie名称.
     */
    private String name; // NAME= ... "$Name" style is reserved
    
    /**
     * Cookie值.
     */
    private String value; // value of NAME

    /**
     * Cookie用处说明.
     */
    private String comment; // ;Comment=VALUE ... describes cookie's use
    
    /**
     * 可以访问该Cookie的域名.
     */
    private String domain; // ;Domain=VALUE ... domain that sees cookie
    
    /**
     * 该Cookie的失效时间.
     */
    private int maxAge = -1; // ;Max-Age=VALUE ... cookies auto-expire
    
    /**
     * 该Cookie的使用路径.
     */
    private String path; // ;Path=VALUE ... URLs that see the cookie
    
    /**
     * 该Cookie是否仅被使用安全协议传输.安全协议有HTTPS、SSL等.
     */
    private boolean secure; // ;Secure ... e.g. use SSL
    
    /**
     * 该Cookie使用的版本号.0表示遵循Netscape的Cookie规范、1表示遵循W3C的RFC2109规范.
     */
    private int version = 0; // ;Version=1 ... means RFC 2109++ style

    /**
     * Constructs.初始参数包括name和value.
     * name:必须遵循RFC 2109规范,只能包含ASCII字母数字字符,不能包含逗号、分号、空格或以$字符开头.创建后无法更改cookie的名称.
     * value:可以是服务器选择发送的任何内容.
     * 默认情况下,cookies是根据Netscape cookie规范创建的。可以使用setVersion方法更改版本.
     * name不允许出现如下情况:
     *  非Java保留标记,不区分大小写情况下,不等于Commet、Discard、Domain、Expires、Max-Age、Path、Secure、Version,不以$开头.
     * @param name Cookie名.
     * @param value Cookie值.
     */
    public Cookie(String name, String value) {
    
    
        if (!isToken(name) || name.equalsIgnoreCase("Comment") // rfc2019
                || name.equalsIgnoreCase("Discard") // 2019++
                || name.equalsIgnoreCase("Domain") || name.equalsIgnoreCase("Expires") // (old cookies)
                || name.equalsIgnoreCase("Max-Age") // rfc2019
                || name.equalsIgnoreCase("Path") || name.equalsIgnoreCase("Secure") || name.equalsIgnoreCase("Version")
                || name.startsWith("$")) {
    
    
            String errMsg = lStrings.getString("err.cookie_name_is_token");
            Object[] errArgs = new Object[1];
            errArgs[0] = name;
            errMsg = MessageFormat.format(errMsg, errArgs);
            throw new IllegalArgumentException(errMsg);
        }

        this.name = name;
        this.value = value;
    }

    /**
     * 设置commet.
     */
    public void setComment(String purpose) {
    
    
        comment = purpose;
    }

    /**
     * 获取commet.
     */
    public String getComment() {
    
    
        return comment;
    }

    /**
     * 设置domain.
     */
    public void setDomain(String pattern) {
    
    
        domain = pattern.toLowerCase(); // IE allegedly needs this
    }

    /**
     * 获取domain.
     */
    public String getDomain() {
    
    
        return domain;
    }

    /**
     * 设置maxAge.
     */
    public void setMaxAge(int expiry) {
    
    
        maxAge = expiry;
    }

    /**
     * 获取maxAge.
     */
    public int getMaxAge() {
    
    
        return maxAge;
    }

    /**
     * 设置path.
     */
    public void setPath(String uri) {
    
    
        path = uri;
    }

    /**
     * 获取path.
     */
    public String getPath() {
    
    
        return path;
    }

    /**
     * 设置seure.
     */
    public void setSecure(boolean flag) {
    
    
        secure = flag;
    }

    /**
     * 获取secure.
     */
    public boolean getSecure() {
    
    
        return secure;
    }

    /**
     * 获取name.
     */
    public String getName() {
    
    
        return name;
    }

    /**
     * 设置value.
     */
    public void setValue(String newValue) {
    
    
        value = newValue;
    }

    /**
     * 获取value.
     */
    public String getValue() {
    
    
        return value;
    }

    /**
     * 获取version.
     */
    public int getVersion() {
    
    
        return version;
    }

    /**
     * 设置version.
     */
    public void setVersion(int v) {
    
    
        version = v;
    }

    private static final String tspecials = ",; ";

    /**
     * 测试字符串,如果该字符串在Java语言中算作保留标记,则返回true.
     */
    private boolean isToken(String value) {
    
    
        int len = value.length();

        for (int i = 0; i < len; i++) {
    
    
            char c = value.charAt(i);

            if (c < 0x20 || c >= 0x7f || tspecials.indexOf(c) != -1)
                return false;
        }
        return true;
    }

    /**
     * 重写clone.
     */
    public Object clone() {
    
    
        try {
    
    
            return super.clone();
        } catch (CloneNotSupportedException e) {
    
    
            throw new RuntimeException(e.getMessage());
        }
    }
    
}

  若文中存在错误和不足,欢迎指正!

本博微信公众号“超哥说码”,欢迎大家订阅,公众号正在完善中,会及时将更优质的博文推送于您!
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/securitit/article/details/108046228
今日推荐