协议简述
该协议是基于Apache AJP协议的学习整理版本.AJP是面向数据包设计的,使用二进制字节进行数据传输.端与端之间保持长链接,用以避免套接字创建的开销
请求不是通过连接多路复用的,即将连接分配给特定请求后,在请求处理周期终止之前,不会将其用于任何其他请求.
请求的基本信息比如请求头,请求方法等都以高度精简的形式进行传输(公共字符串被编码为整数)
数据包数据类型
协议中有四种数据类型: bytes, booleans, integers, string和bytes.
- byte: 单个字节
- boolean:单字节,1=true;0=false
- Integer:取值范围是0到2^16 (32768),使用两个字节进行存储
- string:首先将长度编码为两个字节,然后是字符串+终止符号\0(终止符不计长度)
- bytes:首先将长度编码为两个字节,然后是数据+终止符号\0(终止符不计长度)
包大小
最大数据包大小为8 * 1024字节(8k).数据包的实际长度在包头中编码.
包头
从客户端发往服务端的包头开始于0x1234,从服务端发往客户端的包头开始于0x4142.在前两个字节之后,有一个带有有效数据包长度的整数.
包格式(客户端 - >服务端)
字节 | 0 | 1 | 2 | 3 | 4 ……第(n + 3) |
---|---|---|---|---|---|
内容 | 0×12 | 0x34 | 长度第一个字节 | 长度第二个字节 | 数据 |
包格式(服务端 - >服务端)
字节 | 0 | 1 | 2 | 3 | 4 ……第(n + 3) |
---|---|---|---|---|---|
内容 | 0x41 | 0x42 | 长度第一个字节 | 长度第二个字节 | 数据 |
对于一个正常的数据包的payload,第一个字节用来指示消息类型.
数据包类型
请求的数据包
Code | Type of Packet | Meaning |
---|---|---|
2 | Forward Request | 使用接下来的数据处理请求 |
10 | CPing | 客户端向要求服务端快速响应CPong |
响应的数据包
Code | Type of Packet | Meaning |
---|---|---|
3 | Send Body Chunk | 发送数据块作为请求的响应 |
4 | Send Headers | 发送响应头数据 |
5 | End Response | 标志response的完结 |
6 | Get Body Chunk | 发起请求获取请求体内容 |
9 | CPong Reply | CPing的响应 |
请求包结构
AJP13_FORWARD_REQUEST :=
prefix_code (byte) 0x02 = Forward Request
method (byte)
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
request_headers具备以下的结构
req_header_name := sc_req_header_name(以下会描述sc_req_header_name映射关系)
sc_req_header_name := 0x000A (integer)
req_header_value := (string)
attributes具备以下结构
attribute_name := attribute_type(如果是请求参数, 后面会跟参数名称,类型为 string)
attribute_value := (string)
请求方法
请求方法,编码为单个字节:
Method Name | Code |
---|---|
OPTIONS | 1 |
GET | 2 |
HEAD | 3 |
POST | 4 |
PUT | 5 |
DELETE | 6 |
请求头
对于请求头的结构,首先通过num_headers
编码请求头的数量,接下来是一系列req_header_name
和req_header_value
键值对,其中req_header_name
使用数值类型进行编码,编码列表如下:
Name | Code value | Constant name |
---|---|---|
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 |
pragma | 0xA00C | SC_REQ_PRAGMA |
referer | 0xA00D | SC_REQ_REFERER |
user-agent | 0xA00E | SC_REQ_USER_AGENT |
属性
属性可通过多种方式传递,如请求参数,query string, basic认证信息(user:pwd@localhost/path)等.
对于每个属性,都有一个字节代码表示属性的类型,然后是一个字符串来给出它的值.
发送一个特殊的终止代码来发信号通知可选属性列表的末尾(0xFF)
Information | Code Value | Note |
---|---|---|
remote_user | 0x03 | 请求认证 |
auth_type | 0x04 | 请求认证 |
query_string | 0x05 | |
route | 0x06 | 请求粘性 |
ssl_cert | 0x07 | |
ssl_cipher | 0x08 | |
ssl_session | 0x09 | |
req_attribute | 0x0A | 请求参数 |
ssl_key_size | 0x0B | |
secret | 0x0C | |
stored_method | 0x0D | |
are_done | 0xFF | request_terminator |
响应包结构
AJP13_SEND_BODY_CHUNK :=
prefix_code 3
chunk_length (integer)
chunk (bytes)
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 (以下会描述sc_req_header_name映射关系)
sc_res_header_name := 0xA0 (byte)
header_value := (string)
AJP13_END_RESPONSE :=
prefix_code 5
reuse (boolean)
AJP13_GET_BODY_CHUNK :=
prefix_code 6
requested_length (integer)
Send Headers
状态代码和消息是通常的请求状态的描述(例如“200”和“OK”). 响应头的编码格式和请求头类似,映射关系如下:
Name | Code value |
---|---|
Content-Type | 0xA001 |
Content-Language | 0xA002 |
Content-Length | 0xA003 |
Date | 0xA004 |
Last-Modified | 0xA005 |
Location | 0xA006 |
Set-Cookie | 0xA007 |
Set-Cookie2 | 0xA008 |
Servlet-Engine | 0xA009 |
Status | 0xA00A |
WWW-Authenticate | 0xA00B |
End Response
该消息标志着响应的终止,如果reuse=0,标志着连接发生错误,将关闭连接,正常情况reuse=1,标志连接正常,可重用.
Get Body Chunk
该数据包用于向服务端获取更多的请求体数据,请求体数据使用数据包code为3的Send Body Chunk
类型数据作为响应.