Tomcat

Tomcat之Http11Processor源码分析

2020-05-13  本文已影响0人  loveFXX

Http11Processor继承关系


image.png

java.nio.ByteBuffer


image.png
ByteBuffer有三个属性值:position、limit、capacity
初始化时,position=0,limit=capacity=最大容量10,下标是10的位置不可以写入数据

如果position<limit,是可写模式。如果这中间(position到limit)有数据,将会被覆盖。
调用flip()方法,由写模式变为可读模式,此时limit=position=2,position=0。
position到limit是在写入模式写入的数据,此时可以读取出来。读取一个数据position位置加1

解析调用入口

在SocketProcessor任务类中调用doRun会调用到ConnectionHandler#process
1、doRun
org.apache.tomcat.util.net.NioEndpoint.SocketProcessor#doRun


process.png

2、process
org.apache.coyote.AbstractProtocol.ConnectionHandler#process


process.png
3、process
org.apache.coyote.AbstractProcessorLight#process
process.png

解析处理方法service

org.apache.coyote.http11.Http11Processor#service


service.png

0、setSocketWrapper
org.apache.coyote.http11.Http11Processor#setSocketWrapper
Http11InputBuffer inputBuffer和outputBuffer的初始化,此时activeFilters 是null


image.png
设置keepAlive、openSocket、readComplete的值。
keepAlive表示客户端与服务端连接是长连接Keep-alive,就是说客户端socket连接到服务端之后,告诉服务端这个socket你别给我关了,要一直保持连接。

1、解析请求行

image.png
1.1、parsingRequestLinePhase < 2

跳过空白行,并读取socket数据到缓冲区
①、parseRequestLine
org.apache.coyote.http11.Http11InputBuffer#parseRequestLine


parseRequestLine.png

此时byteBuffer的position和limit都是0,将会通过fill方法从操作系统的输入缓冲区读取数据
②、fill
是个非阻塞方法,如果从输入缓冲区没有读取到数据会立即返回。并不会像Tomcat7使用BIO读取,如果没数据一直会等待。
org.apache.coyote.http11.Http11InputBuffer#fill


fill.png
byteBuffer设置标记为mark=position=0
设置lim位置是最大位置cap大小。java.nio.HeapByteBuffer[pos=0 lim=16384 cap=16384]
③、read
从socketWrapper通道中读取数据到byteBuffer,以非阻塞方式

org.apache.tomcat.util.net.NioEndpoint.NioSocketWrapper#read(boolean, java.nio.ByteBuffer)


read.png
populateReadBuffer从to缓存区读取,如果没读取到说明此时ByteBuffer缓冲区中没有数据继续往下走
read.png
④、populateReadBuffer
从读缓冲区readBuffer数据读取到字节数组to
org.apache.tomcat.util.net.SocketWrapperBase#populateReadBuffer(java.nio.ByteBuffer)
image.png
⑤、setReadBufferConfiguredForWrite
如果readBuffer缓冲区处于正确状态,就可以反转flip读取
org.apache.tomcat.util.net.SocketBufferHandler#setReadBufferConfiguredForWrite
readBuffer切换到读java.nio.HeapByteBuffer[pos=0 lim=0 cap=8192]的lim=0
image.png
⑥、read
与③相同方法内
image.png

⑦、fillReadBuffer
org.apache.tomcat.util.net.NioEndpoint.NioSocketWrapper#fillReadBuffer(boolean, java.nio.ByteBuffer)


fillReadBuffer.png
if方法block=false && nRead == 0 如果读取nRead 为0,由于是非阻塞所以会立即返回
image.png
⑧、parseRequestLine
返回到①方法,socket数据读取到缓冲区。遇到“\r”或\n结束parsingRequestLinePhase<2循环
java.nio.HeapByteBuffer[pos=0 lim=510 cap=16384] 设置lim=510
image.png
1.2、parsingRequestLinePhase = 2

读取方法名,并在byteBuffer中标记


image.png
image.png

java.nio.HeapByteBuffer[pos=4 lim=510 cap=16384]

1.3、parsingRequestLinePhase = 3

空格和\t处理
parsingRequestLinePhase=3跳过方法后的Constants.SP(' ' )和Constants.HT('\t')


image.png
1.4、parsingRequestLinePhase = 4

解析uri,并标记位置


requestURI.png
1.5、parsingRequestLinePhase = 5

空格和\t处理
parsingRequestLinePhase=5跳过方法后的Constants.SP(' ' )和Constants.HT('\t')


image.png
1.6、parsingRequestLinePhase = 6

parsingRequestLinePhase == 6解析协议


protocol.png

如果缓冲区没数据,任意一步也会调用fill方法读取

MessageBytes

MessageBytes是请求数据存储类型
1、请求数据存储


image.png

2、Request属性
org.apache.coyote.Request类中的请求属性值都是MessageBytes类型


Request.png
3、MessageBytes属性
MessageBytes有两个byteC、charC属性,数据块
private final ByteChunk byteC=new ByteChunk();

private final CharChunk charC=new CharChunk();
4、当设置请求数据时,便是调用setBytes
org.apache.tomcat.util.buf.MessageBytes#setBytes


setBytes.png
org.apache.tomcat.util.buf.ByteChunk#setBytes
setBytes.png
ByteBuff数据解析请求行数据块标记

以localhost:8080/,methodMB、uriMB和protoMB(不是解析请求行设置的)的标记为例。这里只是说明数据块标记效果


ByteBuff.png

2、解析请求头

image.png

解析过程与解析请求行类似,就是读取缓存的数据进行解析。如果缓冲区数据不足,则会继续读取操作系统输出缓冲区数据
1、parseHeaders
org.apache.coyote.http11.Http11InputBuffer#parseHeaders


image.png

2、setBytes


headerValue.png
keep-alive
image.png
3、请求头数据request headers
image.png
java.nio.HeapByteBuffer[pos=581 lim=581 cap=16384]

4、缓冲区数据块headers
请求头数据也会在缓冲区HeapByteBuffer类中标记,在Request类的MimeHeaders headers属性

3、prepareRequest

在处理请求头之前,设置一些过滤器


image.png

org.apache.coyote.http11.Http11Processor#prepareRequest
1、设置协议protocolMB


prepareRequest.png
2、检查keepAlive
image.png

3、检查expect和user-agent


image.png
image.png
4、检查host
image.png
5、检查uri是否以http开头
image.png
6、检查uri字符
image.png
image.png

7、创建InputFilter数组


image.png
InputFilter[4]
{BufferedInputFilter、VoidInputFilter、ChunkedInputFilter、IdentityInputFilter}
8、解析transfer-encoding header
image.png
9、获取contentLength
image.png
如果contentLength大于0,inputBuffer是IdentityInputFilter
inputFilters[Constants.IDENTITY_FILTER]=inputFilters[0]
image.png
image.png
10、检验hostname和port
image.png
如果contentLength大于0则contentDelimitation=true。inputBuffer是inputFilters[0]
如果不成立,则inputFilters[Constants.VOID_FILTER]=2是VoidInputFilter类型
11、检查maxKeepAliveRequests
如果maxKeepAliveRequests=1或keepAliveLeft小于等于0,会把是否保持连接设置为keepAlive=false,则当前socket处理将会被关闭
image.png
处理请求getAdapter().service
image.png

4、解析请求体

InputFilter实现类用来处理请求数据的请求体,相对应的OutputFilter用于处理Servlet服务响应给客户端的数据。
BufferedInputFilter
VoidInputFilter(contentLength=0)
ChunkedInputFilter(被标记为Chunked)
IdentityInputFilter(contentLength>0)

5、结束请求

image.png

1、endRequest
org.apache.coyote.http11.Http11Processor#endRequest


image.png

2、endRequest
org.apache.coyote.http11.Http11InputBuffer#endRequest
调用activeFilters的end方法,用来处理请求体。得到返回的结果extraBytes,并设置正确的position位置


endRequest.png
3、end
org.apache.coyote.http11.filters.VoidInputFilter#end
①、VoidInputFilter说明没有请求体需要处理
image.png

②、IdentityInputFilter请求体的处理方法
org.apache.coyote.http11.filters.IdentityInputFilter#end


image.png
IdentityInputFilter根据还有剩余的数据需要处理,如果是负值说明请求读取了下一个的请求数据,所以需要修复。如果remaining大于0说明,还有这些数据没有读取到,则会继续读取。
缓冲区读取请求是按照请求行请求头请求体以此读取,然后是下一个请求行请求头请求体
image.png
如果此时请求体数据是123,此时只读取到了123后,又读取了下一个的get方法,remaining小于0需要往回退移动指针到正确位置。
如果此时请求体数据是123456789,此时只读取到了123,remaining大于0需要读取剩余的,需要往后移动指针到正确位置。
③、ChunkedInputFilter请求体的处理方法
org.apache.coyote.http11.filters.ChunkedInputFilter#end
image.png
4、action
返回到1的处理
org.apache.coyote.AbstractProcessor#action
image.png
5、prepareResponse

用来响应数据,并验证响应头和构建输出过滤器outputFilters
org.apache.coyote.http11.Http11Processor#prepareResponse
6、nextRequest
处理下个请求


nextRequest.png
①、Request类重置
org.apache.coyote.Request request属性重置
image.png
②、Http11InputBuffer 类重置
byteBuffer指针重置、activeFilters及其他属性值重置
image.png

总结:

Http11Processor类是客户端请求时用来处理Http协议和向客户端响应数据时构建Http协议的核心代码。
请求处理过程主要包括:
解析请求行、解析请求头、解析请求体、Servlet服务调用、重置基本类属性用来处理下次请求等过程。
其中InputFilter和OutputFilter涉及请求体的读写数据及其他处理。
Servlet服务调用是通过getAdapter().service方法进行调用

上一篇下一篇

猜你喜欢

热点阅读