一旦一个连接被分配给一个特定的请求,在连接上发送的基本请求信息是高度压缩的。在这点,SERVLET容器大概准备开始处理请求,当它处理的时候,它能发回下面的信息给WEB服务器:
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://guojuanjun.blog.51cto.com/277646/688559
(格式显示不好,本文已放附件中)
AJP协议是定向包(面向包)协议,采用二进制形式代替文本形式,以提高性能。Web Server一般维持和Web Container的多个TCP Connecions,即TCP连接池,多个request/respons循环重用同一个Connection。但是当Connection被分配(Assigned)到某个请求时,该请求完成之前,其他请求不得使用该连接。
Tcp Connection 具有两种状态:
(1). Idle
没有请求正使用该连接。
(2). Assigned
当前连接正在处理某个请求.
数据类型:
AJP协议中包括四种数据类型:Byte, Boolean, Integer and String.
Byte: 一个字节
Boolean: 一个字节,1 = true, 0 = false。
Integer:两个字节,无符号整数,高位字节在前。
String:可变字符串,最大长度为2^16. 字符串的前而会有二个字节(Integer型)表示字符串的长度,-1表示null。字符串后面会跟上终结符”\0”,而且字符串长度不包括这个终结符。
AJP的包结构,图表1:
包方向
0
1
2
3
4…(n+3)
Server->Container
0x12
0x34
数据长度(n)
数据(payload)
Container->Server
A
B
数据长度(n)
数据(payload)
图表1
可以看出,从apache发向tomcat包都带有0x1234头,而从tomcat发向apache的包都带有AB(ascii码)头,随后二字节代表数据的长度(不包括前四个字节).所认AJP包的最大长度可以接近2^16,但目前的版本支持的最大包长度为2^13,即8K。
再看数据部分(payload),除Server->Container的请求体包外,其他包的数据部分的首字节为其消息类型(code),如下表(描述部分是原文,译成中文本人认为更难理解,英文表义比中文是好一些):
方向
code
包类型
描述
Server->Container
2
Forward Request
Begin the request-processing cycle with the following data。
7
Shutdown
The web server asks the container to shut itself down
8
Ping
The web server asks the container to take control (secure login phase).
10
Cping
The web server asks the container to respond quickly with a CPong
none
Data
Size (2 bytes) and corresponding body data.
Container->Server
3
Send Body Chunk
Send a chunk of the body from the servlet container to the web server
4
Send Headers
Send the response headers from the servlet container to the web server
5
End Response
Marks the end of the response
6
Get Body Chunk
Get further data from the request if it hasn't all been transferred yet
9
CPong Reply
The reply to a CPing request
Forward Request包数据部分(payload)结构:
AJP13_FORWARD_REQUEST :=
prefix_code (byte) 0x02 = JK_AJP13_FORWARD_REQUEST
method (byte)
protocol (string)
req_uri (string)
remote_addr (string)
remote_host (string)
server_name (string)
server_port (integer)
is_ssl (boolean)
num_headers (integer)
request_headers *(req_header_name req_header_value)
attributes *(attribut_name attribute_value)
request_terminator (byte) OxFF
---------------------------------------------------------------------------------------------------------------------------------
req_header_name :=
sc_req_header_name | (string) [see below for how this is parsed]
---------------------------------------------------------------------------------------------------------------------------------
sc_req_header_name := 0xA0xx (integer)
req_header_value := (string)
---------------------------------------------------------------------------------------------------------------------------------
attribute_name := sc_a_name | (sc_a_req_attribute string)
attribute_value := (string)
(1) prefix_code 所有的Forward Request包都是0x02.
(2) Method: 一个字节,对方法的编码,其对应如下(只列了部分):
Command Name
code
POST
4
OPTIONS
1
PUT
5
GET
2
DELETE
6
HEAD
3
TRACE
7
(参考:http://tomcat.apache.org/connectors-doc/ajp/ajpv13a.html)
(3) protocol, req_uri, remote_addr, remote_host, server_name, server_port, is_ssl: 每个请求包都有这几个字段,格式都是 长度+字符串值+\0结束符。
(4) num_headers: 请求头的个数,两个字节。
(5) request_headers:
请求头名称分化为两类,一类请求头被转换为0xA0xx格式(如下表所示),其他请求头仍然用原字符串编码。
请求头
Code 值
Code 名称
accept
0xA001
SC_REQ_ACCEPT
accept-charset
0xA002
SC_REQ_ACCEPT_CHARSET
accept-encoding
0xA003
SC_REQ_ACCEPT_ENCODING
accept-language
0xA004
SC_REQ_ACCEPT_LANGUAGE
authorization
0xA005
SC_REQ_AUTHORIZATION
connection
0xA006
SC_REQ_CONNECTION
content-type
0xA007
SC_REQ_CONTENT_TYPE
content-length
0xA008
SC_REQ_CONTENT_LENGTH
cookie
0xA009
SC_REQ_COOKIE
cookie2
0xA00A
SC_REQ_COOKIE2
host
0xA00B
SC_REQ_HOST 0xA00C
pragma
0xA00C
SC_REQ_PRAGMA
referer
0xA00D
SC_REQ_REFERER
user-agent
0xA00E
SC_REQ_USER_AGENT
(6) Java代码读取头两个字节的整数型,如果高位字节为”0xA0” ,则第二字节为上在列表的索引。如果高位字节不是”0xA0”,则这两个字节为随后请求头名称的长度。
(7) Attributes:很少用,直接看tomcat文档吧。
(8) request_terminator: 一个字节0xFF,请求结束符。
响应包数据部分(payload)结构:
AJP13_SEND_HEADERS :=
prefix_code 4
http_status_code (integer)
http_status_msg (string)
num_headers (integer)
response_headers *(res_header_name header_value)
res_header_name :=
sc_res_header_name | (string) [see below for how this is parsed]
sc_res_header_name := 0xA0 (byte)
header_value := (string)
AJP13_SEND_BODY_CHUNK :=
prefix_code 3
chunk_length (integer)
chunk *(byte)
AJP13_END_RESPONSE :=
prefix_code 5
reuse (boolean)
AJP13_GET_BODY_CHUNK :=
prefix_code 6
requested_length (integer)
1. response_headers: 和请求头一样,一类响应头被转换为0xA0xx格式(如下表所示),其他响应头名称采用原字符串编码。
请求头
Code 值
Code 名称
Content-Type
0xA001
SC_RESP_CONTENT_TYPE
Content-Language
0xA002
SC_RESP_CONTENT_LANGUAGE
Content-Length
0xA003
SC_RESP_CONTENT_LENGTH
Date
0xA004
SC_RESP_DATE
Last-Modified
0xA005
SC_RESP_LAST_MODIFIED
Location
0xA006
SC_RESP_LOCATION
Set-Cookie
0xA007
SC_RESP_SET_COOKIE
Set-Cookie2
0xA008
SC_RESP_SET_COOKIE2
Servlet-Engine
0xA009
SC_RESP_SERVLET_ENGINE
Status
0xA00A
SC_RESP_STATUS
WWW-Authenticate
0xA00B
SC_RESP_WWW_AUTHENTICATE
2. reuse: 如果为1,表示该连接可以被子重用,否则这个连接应该关闭。
下面我们来看一个简单AJP请求过程中抓到的请求包:
http://localhost/test/testCluster.jsp请求:
1,2字节是上文所说的Server->Container包头,3,4字节表示包长度(0x01b0=432),即从第5个字节到最后的一个字节(ff)的长度。第5个字节(02)代表是”Forward Request”包。
第6个字节(02)代表是Get请求。第7,8字节(0x0008)代表protocol字符串的长度,后8个字节为protocol字符串(HTTP/1.1),第9个字节为protocol字符串的终结符“\0”。
18-41字节代表req_uri字符串(0x15+2+1=24个)。
42-53字节代表remote_addr字符串(0x09+2+1=12个)
54-55 两字节(0xffff=-1)代表null字符串,即remote_host不存在。
56-67两字节代表server_name字符串(0x09+2+1=12个)
68-69两字节(0x0050=80)代表server_port
70字节(0x00)代表is_ssl为false
71-72两字节(0x0009)代表该请求有9个请求头,如图中的前9个红色椭圆.
第10个红色椭圆(0x06)代表Attributes的route.
第11个红椭圆之后,代表AJP_REMOTE_PORT与JK_LB_ACTIVATION两个请求属性.
最后一个字节0xFF表示请求结束。
响应头数据包:
和请示头比较类似,不再细描述。其中第5个字节0x04代表”Send Headers”响应。
并且没有终结符字节0xFF.
响应正文数据包:
响应结束End Response:
其中最后一个字节(01),代表当前连接仍然可用。
(完)
本文出自 “天下无贼” 博客,请务必保留此出处http://guojuanjun.blog.51cto.com/277646/688559