![479bea63fa2fbce59745b723275d0a28.png](https://img-blog.csdnimg.cn/img_convert/479bea63fa2fbce59745b723275d0a28.png)
No.1
源码下载
http://apache.communilink.net/tomcat/tomcat-9/v9.0.31/src/apache-tomcat-9.0.31-src.zip
No.2
寻找tomcat代码入口
本次分析的源码为tomcat9.0.31
首先寻找代码的入口点
我们在win上一般启动tomcat,都是使用bin目录下的startup.bat
![42a337dff192c4e30bd6551801d7c884.png](https://img-blog.csdnimg.cn/img_convert/42a337dff192c4e30bd6551801d7c884.png)
这里调用了catelina.bat
Catelina第259行设置了mainclass
![b4a9c47f6b1962276cadd9d8dfcb20f0.png](https://img-blog.csdnimg.cn/img_convert/b4a9c47f6b1962276cadd9d8dfcb20f0.png)
![9ff6672bbbcee1d613129dbb037d96b8.png](https://img-blog.csdnimg.cn/img_convert/9ff6672bbbcee1d613129dbb037d96b8.png)
并在361行做了调用
我们通过catelina.bat的mainclass值就能找到入口点
org.apache.catalina.startup.Bootstrap
使用idea打开tomcat源码,找到
![5d14e221211f74c1176f469b8221dc9c.png](https://img-blog.csdnimg.cn/img_convert/5d14e221211f74c1176f469b8221dc9c.png)
这里就是tomcat的入口点了。
No.3
Tomcat启动分析
tomcat启动时会先进行一些初始化
网上有张图很详细地描绘了tomcat的启动流程
![a9d36cd3e4fb39ebc9e8fa5f7c7a977f.png](https://img-blog.csdnimg.cn/img_convert/a9d36cd3e4fb39ebc9e8fa5f7c7a977f.png)
我们先看第一部分
![64ea933debe7141b54661160eb9178f9.png](https://img-blog.csdnimg.cn/img_convert/64ea933debe7141b54661160eb9178f9.png)
先从main方法进入,调用init,然后再执行load方法,从load方法中调用catalina的init方法,我们从代码上跟一下
![acd4daf1098ad2fe92011d8fd49e39da.png](https://img-blog.csdnimg.cn/img_convert/acd4daf1098ad2fe92011d8fd49e39da.png)
![da18bda701976820c7cf3cf16118f281.png](https://img-blog.csdnimg.cn/img_convert/da18bda701976820c7cf3cf16118f281.png)
使用java的反射调用org.apache.catalina.startup.Catalina
之后赋值给catalinaDaemon
返回main方法,跟踪到466行,进入load方法
![1f4e057b82f8d2c0af46add8dd55cc5a.png](https://img-blog.csdnimg.cn/img_convert/1f4e057b82f8d2c0af46add8dd55cc5a.png)
![4607c1cdeb65fc6c7428521e258d4da8.png](https://img-blog.csdnimg.cn/img_convert/4607c1cdeb65fc6c7428521e258d4da8.png)
最后发现反射调用了org.apache.catalina.startup.Catalina.load
559行是处理server.xml配置信息的功能
![da38e3a37ab0d129d7cffbf257ef065e.png](https://img-blog.csdnimg.cn/img_convert/da38e3a37ab0d129d7cffbf257ef065e.png)
584行调用了server的init方法
![932ddae10d768ab7f20cf7e231946e3c.png](https://img-blog.csdnimg.cn/img_convert/932ddae10d768ab7f20cf7e231946e3c.png)
也就是流程图的这里
![1c3720e481b9f29acaa5aed8531be599.png](https://img-blog.csdnimg.cn/img_convert/1c3720e481b9f29acaa5aed8531be599.png)
进入之后发现是个接口
![070e0af076dae16e4c6b78604e3db630.png](https://img-blog.csdnimg.cn/img_convert/070e0af076dae16e4c6b78604e3db630.png)
这是设计模式里面的模板模式,点击I标志进入实现方法进入lifecyclebase
点击initInternal()
![de150d181c7e51a7933892925ca4a131.png](https://img-blog.csdnimg.cn/img_convert/de150d181c7e51a7933892925ca4a131.png)
![e27c3d699ca3ce8746b7075c2e7c2a02.png](https://img-blog.csdnimg.cn/img_convert/e27c3d699ca3ce8746b7075c2e7c2a02.png)
找到standardServer
![8363697ab60789083107046136623c53.png](https://img-blog.csdnimg.cn/img_convert/8363697ab60789083107046136623c53.png)
发现for循环调用services[i].init();
是因为tomcat不止启动了一个service,然后继续跟进
![5aef6b054ab502463c09b2d139e38956.png](https://img-blog.csdnimg.cn/img_convert/5aef6b054ab502463c09b2d139e38956.png)
![aa86650e47e03008c3421ebf8e80818c.png](https://img-blog.csdnimg.cn/img_convert/aa86650e47e03008c3421ebf8e80818c.png)
发现和流程图一样 init了三个方法,之后的流程和之前类似就不再分析,
No.4
Tomcat包解析
Tomcat解析http协议是在
最后一步的Protocol Handler里面
生成UML图
![af68878acb2b9b1a185639e528c22aec.png](https://img-blog.csdnimg.cn/img_convert/af68878acb2b9b1a185639e528c22aec.png)
发现tomcat一共支持三种协议,http1.1 http2 和ajp
Ajp就前几天还出了个文件读取及RCE
今天我们分析http11
![00feaf849cf0ed65b44313d630e00d45.png](https://img-blog.csdnimg.cn/img_convert/00feaf849cf0ed65b44313d630e00d45.png)
查看构造方法我们知道tomcat解析http协议是使用filter的方式进行解析的,在service方法中我们找到了解析请求行的代码
![0ea861b9d4acc71e97a088f18f0883f6.png](https://img-blog.csdnimg.cn/img_convert/0ea861b9d4acc71e97a088f18f0883f6.png)
跟进方法
![1fc22dcac09ac611ca97ac4946bfcc07.png](https://img-blog.csdnimg.cn/img_convert/1fc22dcac09ac611ca97ac4946bfcc07.png)
parsingRequestLinePhase == 2时,开始解析http方法,这里我们可以看见用了一个while循环来查找 sp和ht,当找到sp和ht就代表http方法读取完毕了。
sp是space ht是 tab
![04744d929834ed46f928994916712490.png](https://img-blog.csdnimg.cn/img_convert/04744d929834ed46f928994916712490.png)
解析完http方法之后,会将parsingRequestLinePhase改为3
![1cc749a563ad95f17e0d48b2f98cd575.png](https://img-blog.csdnimg.cn/img_convert/1cc749a563ad95f17e0d48b2f98cd575.png)
这里又是一个while循环,因为之前是读取http方法,
当读到空格即为结束,
所以当parsingRequestLinePhase为3时候必然后面是空格,所以这里是当space和tab读取和结束的时候就退出,用于忽略tab和空格
用bp发包发现确实会忽略
![abd4345464eca18f6d18ef1522216ab8.png](https://img-blog.csdnimg.cn/img_convert/abd4345464eca18f6d18ef1522216ab8.png)
![df2ba4e07e3c4fbcf99a36a4e83dcd5d.png](https://img-blog.csdnimg.cn/img_convert/df2ba4e07e3c4fbcf99a36a4e83dcd5d.png)
后面的逻辑类似,就讲一下比较有意思的点
parsingRequestLinePhase == 4
![1f9f92341a48cd3a21e2b1efb7fa5ef5.png](https://img-blog.csdnimg.cn/img_convert/1f9f92341a48cd3a21e2b1efb7fa5ef5.png)
为了兼容http0.9的风格,这里还会以回车作为终点
![0baa0246269dceacfae1ed0282bbfa0f.png](https://img-blog.csdnimg.cn/img_convert/0baa0246269dceacfae1ed0282bbfa0f.png)
回到http11Processor,
查看inputBuffer. parseHeaders()
![9970efb95378359fc1bca7c6667b5428.png](https://img-blog.csdnimg.cn/img_convert/9970efb95378359fc1bca7c6667b5428.png)
里面是do循环
![4bf83396e1a3b4a47f198d94ecc48afd.png](https://img-blog.csdnimg.cn/img_convert/4bf83396e1a3b4a47f198d94ecc48afd.png)
注意在564行开始解析headername
![e0047202e66fee79d81f18e39cb067ed.png](https://img-blog.csdnimg.cn/img_convert/e0047202e66fee79d81f18e39cb067ed.png)
COLON是冒号,匹配到冒号就将值加入到headerValue
![5612881b6dc8e4ba7aa7f5b4dabf6f7d.png](https://img-blog.csdnimg.cn/img_convert/5612881b6dc8e4ba7aa7f5b4dabf6f7d.png)
在框红线的地方,他将坐标改成了HEADER_VALUE_START
所以我们寻找到这里
![02362f7e090215f50a5530b1581e028a.png](https://img-blog.csdnimg.cn/img_convert/02362f7e090215f50a5530b1581e028a.png)
当值没有sp和ht的时候,开始解析header_value
查看header_value方法
![a705541d35b3cefea43de70ef0027ee7.png](https://img-blog.csdnimg.cn/img_convert/a705541d35b3cefea43de70ef0027ee7.png)
![e60e93e7b2c22ae61aa314550c50d067.png](https://img-blog.csdnimg.cn/img_convert/e60e93e7b2c22ae61aa314550c50d067.png)
No.5
总结
总结到之前的那些点,删除没用的行 就能构造出这种有意思的包
![34f53329614e0d5211babbf5696af7ed.png](https://img-blog.csdnimg.cn/img_convert/34f53329614e0d5211babbf5696af7ed.png)
主要达成这种效果还是因为对RFC标准的容错