在看AJP协议数据包处理之前,先来了解一下Tomcat处理一个请求的过程。大致如下流程:
    3. AJP协议数据包处理 - 图1
    一次请求的处理可以划分为Connector及Container进行处理,经历的过程大致如下:

    • 一个TCP/IP数据包发送到目标服务器,被监听此端口的Tomcat获取到。
    • 处理这个Socket网络连接,使用Processor解析及包装成request和response对象,并传递给下一步处理。
    • Engine来处理接下来的动作,匹配虚拟主机Host、上下文Context、Mapping Table中的servlet。
    • Servlet调用相应的方法(service/doGet/doPost…)进行处理,并将结果逐级返回。

    而对于使用HTTP协议或AJP协议进行访问的请求来讲,在解析包装成为request和response对象之后的流程都是一样的,主要的区别就是对socket流量的处理以及使用Processor进行解析的过程的不同。
    提供这部分功能的接口为 org.apache.coyote.Processor<S> ,主要负责请求的预处理。并通过它将请求转发给Adapter,针对不用的协议则具有不同的实现类。
    这个接口里定义了一些重要的方法:
    3. AJP协议数据包处理 - 图2
    这里主要还是针对于HTTP协议和AJP协议,抽象类AbstractProcessorLight及其子类AbstractProcessor还是对共有特性的封装。
    3. AJP协议数据包处理 - 图3
    AbstractProcessor具有三个子类,AjpProcessor 用来处理AJP协议,Http11Processor 用来处理HTTP/1.1,StreamProcessor用来处理HTTP/2,我们先来看看针对平常使用的HTTP协议的处理。
    Http11Processor 重点的process()方法,使用service()方法来处理标准HTTP请求,这里我们重点看一下:
    解析请求行和请求头部分:
    3. AJP协议数据包处理 - 图4
    在Tomcat 8.5 之后,加入了判断是否需要HTTP协议升级:
    3. AJP协议数据包处理 - 图5
    调用prepareRequest(),将相关信息放入Http11InputBuffer对象中
    3. AJP协议数据包处理 - 图6
    然后调用Adapter将请求交给Container处理:
    3. AJP协议数据包处理 - 图7
    然后接下来是一些收尾工作。在了解了这个过程后,我们再来看一下 AjpProcessorservice()方法,大体上是一致的流程,只是具体的细节不同,首先是一些解析数据包读取字节的操作,这里不是重点,暂且不提,然后也是调用 prepareRequest() 方法进行预处理:
    3. AJP协议数据包处理 - 图8
    处理之后同样的调用Adapter将请求交给Container处理
    3. AJP协议数据包处理 - 图9
    而AJP协议的任意文件读取/任意文件包含漏洞,则出现在上面提到的 prepareRequest() 方法中。