AJP Protocol – Understanding the protocol by diving deep into it
The ajp13 protocol is packet-oriented. A binary format was presumably chosen over the more readable plain text for reasons of performance
Once the web server has opened a connection to the servlet container, the connection can be in one of the following states:
At this point, the servlet container is presumably ready to start processing the request. As it does so, it can send the following messages back to the web server:
Send a set of headers back to the browser.
Send a chunk of body data back to the browser.
Get further data from the request if it hasn’t all been transferred yet. This is necessary because the packets have a fixed maximum size and arbitrary amounts of data can be included the body of a request (for uploaded files, for example). (Note: this is unrelated to HTTP chunked tranfer).
Finish the request-handling cycle.
Packets sent from the server to the container begin with 0x1234. Packets sent from the container to the server begin with AB (that’s the ASCII code for A followed by the ASCII code for B). After those first two bytes, there is an integer (encoded as above) with the length of the payload.
For most packets, the first byte of the payload encodes the type of message. The exception is for request body packets sent from the server to the container — they are sent with a standard packet header (0x1234 and then length of the packet), but without any prefix code after that (this seems like a mistake to me).
For example code ‘2’ means a forward request(Begin the request-processing cycle with the following data), ‘7’ means shutdown(web server asking servlet container to shutdown).
From servlet container to web server, 2 means send body chunk to webserver(and presumably, onto the browser), 4 means send headers, 5 means end resposne, 6 means Get further data from the request if it hasn’t all been transferred yet.
Let’s now dig more into the binary data being excahnged between web server and servlet container.
For messages from the server to the container of type “Forward Request”:
prefix_code (byte) 0x02 = JK_AJP13_FORWARD_REQUEST
Here method is represented by a single byte. For example, 1 means OPTIONS, 2 means GET
Common header names are encoded as integers, to save space. For example, accept-encoding has code value 0xA003. The Java code that reads this grabs the first two-byte integer and if it sees an ‘0xA0‘ in the most significant byte, it uses the integer in the second byte as an index into an array of header names.
For messages which the container can send back to the server.
Again we have codes for common response headers. For example code value for header Content-Type is 0xA001
End response : Signals the end of this request-handling cycle. If the reuse flag is true (anything other than 0 in the actual C code), this TCP connection can now be used to handle new incoming requests. If reuse is false (==0), the connection should be closed.