The Java Apache Project

Apache JServ Protocol Version 1.1 (AJPv1.1)

Standard - September 9, 1998

describes the protocol used to communicate between a web server module
and the Apache JServ servlet engine over a TCP socket.


The authentication scheme used for AJPv1.0 (used by Apache JServ 0.9.xx) was considered too simple and worked only on local environments. For this reason, while the request/response phase of the protocol were kept unchanged, authentication handshake was ported from higher versions of the protocol (proposed as a future extension) and implemented here for security reasons.

This will also provide more feedback to developers for newer revisions of the AJP protocol.

Protocol States

A request is made by requesting a TCP connection to the port Apache JServ is listening to.

If authentication is enabled (authentication must be enabled or disabled on both sides) the authentication handshake is performed (see Authentication), otherwise authentication is skipped and request metadata is sent right away.

The client sends the request metadata to the servlet engine (see Request) and waits for response metadata (see Response).

When finished, the servlet engine closes the connection, indicating that the request has been completed.


The AJPv1.1 authentication algorithm depends on all clients and the servlet engine having access to a secret file or string with identical contents. This is based on the assumption that the administration of both sides are either the same or in cooperation with each other.

This algorithm uses MD5 hashing but no strong cryptography, and is therefore exportable under cryptography restrictions for the United States, France and Russia in effect as of July, 1998. It is able to verify that both sides possess secret text (analogous to a password) without passing any of it in the clear over the network.

Note: all numbers are sent on the connection streams using big endian format (network order), where most significant bits come first.

The shared secret is an arbitrary-length string (which does not necessarily need to be ASCII text - it could be any binary file.) The only limitation on the shared secret is that the longer the string, the more processing will be necessary to compute an MD5 hash with it, so, since authentication must be performed on every request and MD5 strength does not depend very much on string length, this could as small as a few lines of text.

The server does not acknowledge the authentication success to the client to avoid round trip time and speed up the request process. For this reason, the client must control the availability of the connection while writing the request, since this indicates the success of that operation.

Authentication may be disabled to increment performance. If this is done, both client and server must disable the authentication handshake and skip the authentication phase. Systems administrators that want to avoid untrusted execution of servlets, should secure their networks using other systems.


The module sends the request metadata to the servlet engine. These are sent as lines, with two parts: a one-character identifier, and the data. This is preceded with a four-digit hex number indicating the length of the following string (with leading 0s), e.g. "000dHDate Friday", where "000d" is the length, "H" is the identifier, and "Date Friday" is the data.

    1. Server name
      The module sends "S<hostname>". This is the virtual host that is requesting the servlet.
    2. Servlet zone and class name
      The module sends "C<zone><tab><classname>". The first element is the servlet zone to which the servlet has been mapped. The class name is the fully qualified name of the class in dot notation. i.e. The servlet would load from one of the repository defined for that zone or from the CLASSPATH.
    3. Environment variables
      The module sends "E<var name><tab><var value>". The vars should contain all the standard CGI variables, but should not include the HTTP_ set, since the HTTP headers are sent later. e.g, "EPATH_INFO /foo" The following variables are required. Most are CGI/1.1 variables, but a few are Apache-specific. The following should all be sent (except for those marked with an asterix(*), which should only be sent if appropriate), as well as any additional CGI variables available:

        AUTH_TYPE(*): The type of authentication used
        CONTENT_LENGTH(*): The length of the request entity
        CONTENT_TYPE(*): The media type of the request entity
        DOCUMENT_ROOT: The server's main document root
        PATH_INFO(*): Extra URI path information
        PATH_TRANSLATED(*): The translated path info
        QUERY_STRING(*): The query arguments
        REQUEST_METHOD: The method used for the request
        REMOTE_USER(*): The authenticated username used for the request
        REMOTE_ADDR: The IP address of the requesting host
        REMOTE_HOST: The hostname of the requesting host (if available)
        SCRIPT_NAME: The URI portion that refers to the servlet
        SERVER_NAME: The hostname of the server
        SERVER_PORT: The port number of the server
        SERVER_PROTOCOL: The protocol used for the request
        SERVER_SOFTWARE: The name of the server software

    4. Request headers
      The module sends all of the client's request headers, in the form "H<header name><tab><header value>". e.g., "HUser-Agent Mozilla/4.0 (Windows NT)"
    5. A blank line
      When all the E and H lines (they may be interpolated), the module sends a blank line. (i.e., 0-length) This indicates that the metadata has been completed.
    6. The request entity
      If there is a request entity, it is sent. If not, nothing further is sent.
    7. Signals
      The servlet engine receives signals with the request data, in the form "s<signal code>" where signal code may be "01" for restart (SIGHUP) or "15" for termination (SIGTERM). If a signal code is received, any other data sent with the request will be discarded and if the signal code is not recognized, the request is terminated with no further processing.


The response consists of two parts, response headers and the response entity. This is sent basically the same way CGI responses are sent:

    1. Response headers
      The headers to be set for the response should then be sent, in MIME format: "<header name>: <header value>", terminated with a crlf. Headers set here will be outputted by the server. The server will add the HTTP line, and Server:, Date: and other headers, so only headers that the servlet needs to set should be set. e.g., Content-type, Cookie, whatever. When the last header has been sent, a blank line should be sent.
      A few headers have special meanings:
      • Status: <code> <string>
        This sets the response status to <code>, with a status message of <string>. This is the same as the CGI output header of the same name. e.g., "Status: 404 Not Found"
      • Servlet-Log: <string>. This sends a message to be logged in the server's log. This is currently not used by JServ 1.0.
      • Servlet-Error: <message>. This indicates that the servlet engine had an error occur. The server should send an error response back to the browser, with the status set by a separate Status: header (see above). 500 should be used if Status: is not present. The <message> strong should be logged to the server's error log, as the reason why the request failed. No response entity will be present for this response.
    2. Response entity
      JServ outputs the contents of the response to the module through the socket. When it is finished, JServ closes the socket. This will indicate to the module that the request has been completed.

Copyright (c) 1997-98 The Java Apache Project.
$Id: AJPv11.html,v 1.3 1999/06/09 05:21:29 jonbolt Exp $
All rights reserved.