jetty接受到链接请求,首先要解析请求;jetty中定义了一个HttpParser类来解析http。类中的部分定义如下
// 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里;
再来看具体的parse方法:
/** * 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方法中的,由于这个方法实在太大,就不贴出来了;
也就是解析完http头再解析http体;初始化各种如下:
/* ------------------------------------------------------------ */ 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类中,部分代码如下
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了;
剩下还有一个我们关心的session;jetty的Request中有两个属性与session相关,一个是_session,另一个是_sessionManager;
其中setSession()方法只在两个地方调用了,两个调用的地方都在SessionHandler里;
1、检查requst cookies中的值,或者uri中的参数
/** * Look for a requested session ID in cookies and URI parameters * * @param baseRequest * @param request */ protected void checkRequestedSessionId(Request baseRequest, HttpServletRequest request)
2、再一个
@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;