init顺序
1 | Bootstrap |
start顺序
1 | Bootstrap |
请求处理
NioEndpoint.bind()
1
2
3- 创建ServerSocketChannel,绑定地址、端口,设置成阻塞模式
- 初始化SSL
- 开启NioSelectorPoolNioEndpoint.startInternal()
1
2
3
4- 创建processorCache、eventCache、nioChannels栈
- 创建worker线程池,默认大小200
- 创建Poller线程池并启动,大小为2和cpu最大核心数的最小值
- 创建Acceptor线程池并启动,默认大小1NioEndpoint.Acceptor.run()
1
2
3
4
5
6
7
8- countUpOrAwaitConnection()连接数减一
- Acceptor线程阻塞处理ServerSocketChannel.accept()返回SocketChannel
- countDownConnection()出异常加回去
- setSocketOptions从SocketChannel取出Socket包装到NioChannel,并设置成非阻塞模式
- 使用Poller线程register NioChannel
- eventCache取出PollerEvent修改为OP_REGISTER然后添加回去
- 唤醒Poller线程的Selector
- wakeupCounter加一NioEndpoint.Poller.run()
1
2
3
4
5- 调用events()处理PollerEvent
- 执行读取到的PollerEvent.run()
- PollerEvent.run()判断PollerEvent若是OP_REGISTER,则往NioChannel注册读事件,使用Poller线程的Selector
- select到SelectionKey,调用processKey处理
- 执行processKey处理读写事件AbstractEndpoint.processSocket()
1
2
3
4
5
6- processorCache.pop()缓存复用
- 没缓存则调用createSocketProcessor()创建SocketProcessor
- 使用worker线程池处理
- SocketProcessor.run()->doRun()
- getHandler().process()处理请求(AbstractProtocol.ConnectionHandler.process)
- SocketProcessor把自己push到processorCache缓存复用AbstractHttp11Protocol.AbstractHttp11Protocol()
创建应用协议层1
2- 构造方法传入endpoint
- 创建ConnectionHandler并设置给endpoint
AbstractProtocol.ConnectionHandler.process()
1
2
3- 从connections缓存复用Processor
- 不存在缓存则调用相应协议的getProtocol().createProcessor()
- 缓存至connections复用AbstractHttp11Protocol.createProcessor()
1
2
3
4
5
6- 创建Http11Processor
- Http11Processor构造方法创建Request、Response
- 创建HttpParser用于解析http数据
- 创建Http11InputBuffer、Http11OutputBuffer分别设置给Request、Response
- 给Http11InputBuffer添加一系列的InputFilter
- 给Http11OutputBuffer添加一系列的OutputFilterAbstractProcessorLight.process() -> Http11Processor
1
2
3
4- Http11Processor.service()
- inputBuffer.parseRequestLine()解析请求行
- inputBuffer.parseHeaders解析请求头
- Http11Processor.prepareRequest()准备请求CoyoteAdapter.service() - 处理请求
1
2
3- 创建org.apache.catalina.connector.Request存储老的org.apache.coyote.Request
- 创建org.apache.catalina.connector.Response存储老的org.apache.coyote.Response
- 从connector.getURICharset()读取URI字符集类型,设置到org.apache.coyote.Request的parametersCoyoteAdapter.postParseRequest()
1
2
3
4
5
6
7- 若是OPTIONS *,则直接打印访问日志并返回(添加Allow头GET, HEAD, POST, PUT, DELETE, OPTIONS)
- parsePathParameters解析路径参数
- 解码URI(% +)
- URI处理,反斜杠\转斜杆/,穿越/../ /./处理
- B2CConverter转换URI
- 检测前面对于穿越有没有处理干净
- 从URL或者Cookie中读取SessionIdorg.apache.catalina.mapper -> internalMap -> internalMapWrapper
1
2
3- host+uri匹配
- 读取servletPath
- 把匹配到的数据放到传入的MappingData参数中返回pipeline处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18- org.apache.catalina.core.StandardEngineValve#invoke
- org.apache.catalina.valves.AbstractAccessLogValve#invoke
- org.apache.catalina.valves.ErrorReportValve#invoke
- org.apache.catalina.core.StandardHostValve#invoke
- org.apache.catalina.authenticator.AuthenticatorBase#invoke
- org.apache.catalina.core.StandardContextValve#invoke
- org.apache.catalina.core.StandardWrapperValve#invoke
- org.apache.catalina.core.ApplicationFilterChain#doFilter
- org.apache.catalina.core.ApplicationFilterChain#internalDoFilter
- javax.servlet.http.HttpServlet#service
jsp:
- org.apache.jasper.servlet.JspServlet#service
- org.apache.jasper.servlet.JspServlet#serviceJspFile
- org.apache.jasper.servlet.JspServletWrapper#service
servlet:
- org.apache.catalina.servlets.DefaultServlet#service
- javax.servlet.http.HttpServlet#service
- org.apache.catalina.servlets.DefaultServlet#doGet
请求头解析
inputBuffer.parseRequestLine解析请求行
1
2
3
4
51. 跳过CR LF空行
2. 解析method,读取到第一个空格或\t结束
3. 跳过一些空格和\t
4. 解析URI,判断URI字符是否合规,CR后不能接LF
5. 判断协议字符是否合规inputBuffer.parseHeaders解析请求头
1
21. 不断读取请求头,以:分隔name和value
2. 大写的name会转小写Http11Processor.prepareRequest()准备请求
1
2
3
4
5
6
7
81. 读取头Connection判断是close还是keep-alive
2. 读取头expect判断是否100-continue
3. 读取头host判断是否为空
4. 如果URI是"http://"、"https://"开头的,需要去除
5. 如果URI带有host,并且与host头不一致,将使用URI的host作为新的host头
6. 如果是HTTP/1.1,则读取transfer-encoding,遍历值,选择解码filter添加
7. 读取头content-length
8. 解析host,得到serverPort和serverNameMB
- 连接数:默认10000
- ServerSocket accept积压数:默认100
- accept线程数:默认1
- poller线程数:2和cpu最大核心数的最小值