jetty http解析 session存储

jetty接受到连接请求,首先要解析请求;jetty中定义了一个HttpParser类来解析http。类中的部分定义以下java

// States
    public static final int STATE_START=-14;
    public static final int STATE_FIELD0=-13;
    public static final int STATE_SPACE1=-12;
    public static final int STATE_STATUS=-11;
    public static final int STATE_URI=-10;
    public static final int STATE_SPACE2=-9;
    public static final int STATE_END0=-8;
    public static final int STATE_END1=-7;
    public static final int STATE_FIELD2=-6;
    public static final int STATE_HEADER=-5;
    public static final int STATE_HEADER_NAME=-4;
    public static final int STATE_HEADER_IN_NAME=-3;
    public static final int STATE_HEADER_VALUE=-2;
    public static final int STATE_HEADER_IN_VALUE=-1;
    public static final int STATE_END=0;
    public static final int STATE_EOF_CONTENT=1;
    public static final int STATE_CONTENT=2;
    public static final int STATE_CHUNKED_CONTENT=3;
    public static final int STATE_CHUNK_SIZE=4;
    public static final int STATE_CHUNK_PARAMS=5;
    public static final int STATE_CHUNK=6;
    public static final int STATE_SEEKING_EOF=7;

    private final EventHandler _handler;
    private final Buffers _buffers; // source of buffers
    private final EndPoint _endp;
    private Buffer _header; // Buffer for header data (and small _content)
    private Buffer _body; // Buffer for large content
    private Buffer _buffer; // The current buffer in use (either _header or _content)

从这定义的状态来看,http解析是顺序执行的,从请求头到content,并把解析出来的http头和内容保存在自定义的Buffer里;redis

再来看具体的parse方法:cookie

/**
     * Parse until {@link #STATE_END END} state.
     * If the parser is already in the END state, then it is {@link #reset reset} and re-parsed.
     * @throws IllegalStateException If the buffers have already been partially parsed.
     */
    public void parse() throws IOException
    {
        if (_state==STATE_END)
            reset();
        if (_state!=STATE_START)
            throw new IllegalStateException("!START");

        // continue parsing
        while (_state != STATE_END)
            if (parseNext()<0)
                return;
    }

没错,关键的解析是在parseNext方法中的,因为这个方法实在太大,就不贴出来了;session

也就是解析完http头再解析http体;初始化各类以下:
app

/* ------------------------------------------------------------ */
    public AbstractHttpConnection(Connector connector, EndPoint endpoint, Server server)
    {
        super(endpoint);
        _uri = StringUtil.__UTF8.equals(URIUtil.__CHARSET)?new HttpURI():new EncodedHttpURI(URIUtil.__CHARSET);
        _connector = connector;
        HttpBuffers ab = (HttpBuffers)_connector;
        _parser = newHttpParser(ab.getRequestBuffers(), endpoint, new RequestHandler());
        _requestFields = new HttpFields();
        _responseFields = new HttpFields();
        _request = new Request(this);
        _response = new Response(this);
        _generator = newHttpGenerator(ab.getResponseBuffers(), endpoint);
        _generator.setSendServerVersion(server.getSendServerVersion());
        _server = server;
    }


我关心的是request的信息何时被设置;方法就在AbstractHttpConnection类中,部分代码以下async

protected void handleRequest() throws IOException
    {
        boolean error = false;

        String threadName=null;
        Throwable async_exception=null;
        try
        {
            if (LOG.isDebugEnabled())
            {
                threadName=Thread.currentThread().getName();
                Thread.currentThread().setName(threadName+" - "+_uri);
            }


            // Loop here to handle async request redispatches.
            // The loop is controlled by the call to async.unhandle in the
            // finally block below.  If call is from a non-blocking connector,
            // then the unhandle will return false only if an async dispatch has
            // already happened when unhandle is called.   For a blocking connector,
            // the wait for the asynchronous dispatch or timeout actually happens
            // within the call to unhandle().

解析完就是一个jetty的httpRequest了;
ide

剩下还有一个咱们关心的session;jetty的Request中有两个属性与session相关,一个是_session,另外一个是_sessionManager;函数

其中setSession()方法只在两个地方调用了,两个调用的地方都在SessionHandler里;oop

一、检查requst cookies中的值,或者uri中的参数this

/**
     * Look for a requested session ID in cookies and URI parameters
     *
     * @param baseRequest
     * @param request
     */
    protected void checkRequestedSessionId(Request baseRequest, HttpServletRequest request)

二、再一个

@Override
    public void doScope(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
    {
        SessionManager old_session_manager = null;
        HttpSession old_session = null;
        HttpSession access = null;
        try
        {
            old_session_manager = baseRequest.getSessionManager();
            old_session = baseRequest.getSession(false);

            if (old_session_manager != _sessionManager)
            {
                // new session context
                baseRequest.setSessionManager(_sessionManager);
                baseRequest.setSession(null);
                checkRequestedSessionId(baseRequest,request);//即1中指的那个方法
            }

比较这两个地方发现,只有在SessionHandler的doScope方法中设置session;

其中_sessionManager是存储和维护session的地方;默认是HashSessionManager存储在内存中,重启即失效;

在看看Request中的_seesionManager的set方法,也只有SessionHander的doScope调用了;也就是说整个过程只有在这里给设置_sessionManager。那么每一次请求过来,Request中的_sessionManager必然是null的;

而后reqest的SessionManager别设置为SessionHandler的_sessionManager;而这个_sessionManager只有在SessionHander的构造函数中调用setSessionManager方法;全部要找到SessionHander在何时初始化的;

- -! 因为找了很久仍是不知道怎么初始化的,大概是执行链中获取的;ScopedHandler中的_nextScope被设置为SessionHandler;  乏力。。。

-----------------

那么就无论怎么初始化SessionHandler中的_sessionMananger的了,只知道最后request中的_sessionManager回等于该_sesionManager;

仍是来看看requet的getSesion方法吧:

/*
     * @see javax.servlet.http.HttpServletRequest#getSession()
     */
    public HttpSession getSession()
    {
        return getSession(true);
    }

以及

public HttpSession getSession(boolean create)
    {
        if (_session != null)
        {
            if (_sessionManager != null && !_sessionManager.isValid(_session))
                _session = null;
            else
                return _session;
        }

        if (!create)
            return null;

        if (_sessionManager == null)
            throw new IllegalStateException("No SessionManager");

        _session = _sessionManager.newHttpSession(this);
        HttpCookie cookie = _sessionManager.getSessionCookie(_session,getContextPath(),isSecure());
        if (cookie != null)
            _connection.getResponse().addCookie(cookie);

        return _session;
    }

得知调用getSession方法会在sessionManager中建立一个session实例并保存起来;也同时向response中写入cookie;

若是当前requet已经有sesion直接返回该session;