這份文件是 Apache JServ 協定版本 1.3(也稱為 ajp13)演進的建議。我不會在這裡涵蓋完整的協定,只會涵蓋 ajp13 的附加元件。第 n 次傳遞包含來自 tomcat-dev 清單的意見,以及在開發過程中發現的遺漏事項。
AJP13 中遺漏的功能
ajp13 是將 servlet 引擎(例如 tomcat)連結到網路伺服器(例如 Apache)的良好協定
- 使用持久連線,避免每次請求重新連線的時間
- 編碼許多 http 指令以減少串流大小
- 將許多網路伺服器資訊(例如 SSL 憑證)傳送給 servlet 引擎
但 ajp13 缺乏對下列項目的支援
- 網路伺服器和 servlet 引擎之間的安全性。任何人都可以連線到 ajp13 連接埠(不使用登入機制)。例如,您可以透過 telnet 連線,並透過不傳送任何資料(連線中沒有逾時)來保持遠端執行緒執行。
- 從 servlet 引擎傳遞到網路伺服器的內容資訊。JK(網路伺服器連接器)設定的一部分是指示網路伺服器要處理哪個 URI。mod_jk JkMount 指令告訴網路伺服器必須將哪個 URI 轉發到 servlet 引擎。servlet 引擎已經知道它處理哪個 URI,而 TC 3.3 已經能夠從可用內容清單產生 JK 的設定檔。
- 伺服器引擎至網路伺服器之內容狀態更新。大型網站具有 Tomcat 農場,例如 ISP 和虛擬主機,可能需要停止內容以進行管理目的。在這種情況下,前端網路伺服器必須知道內容目前已關閉,以最終將要求轉送至另一部 Tomcat
- 在傳送要求前驗證連線狀態。實際上,JK 會將要求傳送至伺服器引擎,然後等待回應。但是,Socket API 的其中一項優點是,您可以在不產生任何錯誤報告的情況下對已關閉的連線進行 write(),但對已關閉的連線進行 read() 會傳回錯誤代碼。
建議新增至 AJP13 的附加元件
讓我們在此說明可新增至 AJP13 的功能和附加元件。由於本文件為提案,因此一開始必須預期會有一段時間的混亂。請務必在 Tomcat 清單上進行討論,以協助釐清重點、新增功能,但目前的清單看來像是「最低限度」
- 連線時間的高階登入功能
- 基本授權系統,其中網路伺服器和伺服器引擎中存在共用密鑰。
- 基本協定協商,僅用於確保未來在 AJP13 中新增功能時,目前的實作仍可運作。
- 清除處理「未知封包」
- 從網路伺服器傳遞至伺服器引擎的延伸環境變數。
- 新增 Servlet 2.3 API 所需的額外 SSL 資訊(例如 SSL_KEY_SIZE)
高階登入
- 網路伺服器傳送 LOGIN INIT CMD + NEGOCIATION DATA + WEB SERVER INFO
- TOMCAT 回應 LOGIN SEED CMD + RANDOM DATA
- 網路伺服器計算 RANDOM DATA+SECRET DATA 的 MD5
- 網路伺服器傳送 LOGIN COMP CMD + MD5 (SECRET DATA + RANDOM DATA)
- TOMCAT 回應 LOGIN STATUS CMD + NEGOCIED DATA + SERVLET ENGINE INFO
訊息串流
+----------------+------------------+-----------------+
| LOGIN INIT CMD | NEGOCIATION DATA | WEB SERVER INFO |
+----------------+------------------+-----------------+
+----------------+----------------+
| LOGIN SEED CMD | MD5 of entropy |
+----------------+----------------+
+----------------+----------------------------+
| LOGIN COMP CMD | MD5 of RANDOM + SECRET KEY |
+----------------+----------------------------+
+-----------+---------------+---------------------+
| LOGOK CMD | NEGOCIED DATA | SERVLET ENGINE INFO |
+-----------+---------------+---------------------+
+------------+--------------+
| LOGNOK CMD | FAILURE CODE |
+------------+--------------+
- LOGIN INIT CMD、LOGIN SEED CMD、LOGIN COMP CMD、LOGOK CMD、LOGNOK CMD 長度為 1 位元組。
- MD5、RANDOM 的 MD5 + SECRET KEY 長度為 32 個字元。
- 協商資料、協商資料、失敗代碼長度為 32 位元。
- WEB 伺服器資訊、SERVLET 引擎資訊為 CString。
worker.ajp13.port=8009
worker.ajp13.host=localhost
worker.ajp13.type=ajp13
worker.ajp13.secretkey=myverysecretkey
關閉功能
AJP13 遺漏了 AJP12 的一項功能,也就是關閉指令。登出將告知 servlet 引擎自行關閉。
+--------------+----------------------------+
| SHUTDOWN CMD | MD5 of RANDOM + SECRET KEY |
+--------------+----------------------------+
+------------+
| SHUTOK CMD |
+------------+
+-------------+--------------+
| SHUTNOK CMD | FAILURE CODE |
+-------------+--------------+
- SHUTDOWN CMD、SHUTOK CMD、SHUTNOK CMD 長度為 1 位元組。
- RANDOM 的 MD5 + SECRET KEY 長度為 32 個字元。
- 失敗代碼長度為 32 位元。
延伸環境變數功能
備註:在 JK 中處理 AJP13 時,我真正發現了「JkEnvVar」。由於已在原始實作中提供,以下「延伸環境變數功能」說明可能未在延伸 AJP13 中實作。說明:許多使用者會希望將部分 Web 伺服器環境變數傳遞至其 servlet 引擎。為了減少網路流量,Web 伺服器將傳送一個表格,以較簡短的方式說明外部變數。我們將在此使用 AJP13 中已有的功能,也就是屬性清單:在 AJP13 中,我們有
AJP13_FORWARD_REQUEST :=
prefix_code 2
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)
?context (byte string)
?servlet_path (byte string)
?remote_user (byte string)
?auth_type (byte string)
?query_string (byte string)
?route (byte string)
?ssl_cert (byte string)
?ssl_cipher (byte string)
?ssl_session (byte string)
?attributes *(attribute_name attribute_value)
request_terminator (byte)
+-------------------+---------------------------+-------------------------------+----+
| EXTENDED VARS CMD | WEB SERVER ATTRIBUTE NAME | SERVLET ENGINE ATTRIBUTE NAME | ES |
+-------------------+---------------------------+-------------------------------+----+
JkExtVars S1 SSL_CLIENT_V_START javax.servlet.request.ssl_start_cert_date
JkExtVars S2 SSL_CLIENT_V_END javax.servlet.request.ssl_end_cert_date
JkExtVars S3 SSL_SESSION_ID javax.servlet.request.ssl_session_id
+-------------------+----+-------------------------------------------+
| EXTENDED VARS CMD | S1 | javax.servlet.request.ssl_start_cert_date |
+-------------------+----+-------------------------------------------+
+----+-----------------------------------------+
| S2 | javax.servlet.request.ssl_end_cert_date |
+----+-----------------------------------------+
+----+-----------------------------------------+
| S3 | javax.servlet.request.ssl_end_cert_date |
+----+-----------------------------------------+
- EXTENDED VARS CMD 長度為 1 個位元組。
- WEB 伺服器屬性名稱、SERVLET 引擎屬性名稱為 CString。
- ES 為空的 CString。
將內容資訊轉送自 Servlet 引擎至 Web 伺服器
在登入階段之後,Web 伺服器會要求 Servlet 引擎處理的內容和 URL/URI 清單。這將簡化許多網站的安裝、減少 tomcat-user 清單上的組態問題,並為 servlet API 2.3 做好準備。此模式將由新的指令 JkAutoMount 啟用,例如:JkAutoMount examples myworker1 /examples/ 如果我們要取得 Servlet 引擎處理的所有內容,可以使用通配符,例如:JkAutoMount * myworker1 * Servlet 引擎可能有多個內容,例如 /examples、/admin、/test。我們可能只想對特定工作者使用部分內容。這在過去的 Apache HTTP Server 中已完成,例如透過在 Apache 的每個 [虛擬] 區域中手動設定 JkMount。如果您的 Web 伺服器支援虛擬主機,我們也會將該資訊轉送至 Servlet 引擎,而 Servlet 引擎只會傳回該虛擬主機的內容。在這種情況下,Servlet 引擎只會傳回與特定虛擬伺服器 (在 server.xml 中定義) 相符的 URL/URI。這項功能將有助於 ISP 和大型網站,這些網站會在負載平衡組態中相互使用大量的 Tomcat 農場。
+-----------------+-------------------+----------+----------+----+
| CONTEXT QRY CMD | VIRTUAL HOST NAME | CONTEXTA | CONTEXTB | ES |
+-----------------+-------------------+----------+----------+----+
+------------------+-------------------+----------+-------------------+----------+---------------+----+
| CONTEXT INFO CMD | VIRTUAL HOST NAME | CONTEXTA | URL1 URL2 URL3 ES | CONTEXTB | URL1 URL2 ... | ES |
+------------------+-------------------+----------+-------------------+----------+---------------+----+
- 內容查詢 CMD 和內容資訊 CMD 長度為 1 個位元組。
- 虛擬主機名稱為 CString,即以空位元組 (/0) 結尾的字元陣列。
- 空字串只是一個空位元組 (/0)。
- ES 為空的 CString。表示 URI/URL 結束或內容結束。
當不使用 VirtualMode 時,虛擬主機名稱為 '*”。在這種情況下,Servlet 引擎將傳送所有處理的內容。
自 Servlet 引擎至 Web 伺服器的內容資訊更新
內容更新是每次內容停用/重新啟用時從 Servlet 引擎傳來的訊息。當指令 JkUpdateMount 使用時,將使用更新。此指令將設定 AJP13_CONTEXT_UPDATE_NEG 旗標。例如:JkUpdateMount myworker1
+--------------------+-------------------+----------+--------+----------+--------+----+
| CONTEXT UPDATE CMD | VIRTUAL HOST NAME | CONTEXTA | STATUS | CONTEXTB | STATUS | ES |
+--------------------+-------------------+----------+--------+----------+--------+----+
- 內容更新 CMD、狀態長度為 1 個位元組。
- 虛擬主機名稱、內容為 CString。
- ES 為空的 CString。表示內容結束。
當 VirtualMode 未使用時,虛擬主機名稱為 '*'. STATUS 為一個位元組,表示內容為 UP/DOWN/INVALID
內容狀態查詢至 Servlet 引擎
此查詢將由網路伺服器使用,以確定特定內容為 UP、DOWN 或 INVALID(且應移除)。
+-------------------+--------------------+----------+----------+----+
| CONTEXT STATE CMD | VIRTUAL HOST NAME | CONTEXTA | CONTEXTB | ES |
+-------------------+--------------------+----------+----------+----+
+-------------------------+-------------------+----------+--------+----------+--------+----+
| CONTEXT STATE REPLY CMD | VIRTUAL HOST NAME | CONTEXTA | STATUS | CONTEXTB | STATUS | ES |
+-------------------------+-------------------+----------+-------------------+--------+----+
- 內容狀態指令、內容狀態回覆指令、STATUS 長度為 1 個位元組。
- 虛擬主機名稱、內容為 CString
- ES 為一個空的 CString
當 VirtualMode 未使用時,虛擬主機名稱為一個空的字串。
處理未知封包
有時,即使使用協商良好的通訊協定,我們也可能遇到一端(網路伺服器或 servlet 引擎)收到無法理解的訊息的情況。在這種情況下,接收器將傳送一個「未知封包指令」,並附加未處理的訊息。
+--------------------+------------------------+-------------------+
| UNKNOWN PACKET CMD | UNHANDLED MESSAGE SIZE | UNHANDLED MESSAGE |
+--------------------+------------------------+-------------------+
- 未知封包指令長度為 1 個位元組。
- 未處理訊息大小長度為 16 位元。
- 未處理訊息為一個位元組陣列(長度包含在未處理訊息大小中)
新增未處理訊息大小(開發中)
傳送請求前驗證連線
備註:此功能可能永遠不會使用,因為它可能會減慢正常處理速度,因為在轉送請求之前需要在網路伺服器端進行額外的 IO(讀取)......Socket API 的優點之一是您可以在半關閉的 socket 上寫入。當 servlet 引擎關閉 socket 時,網路伺服器只會在下次對 socket 進行 read() 時發現它。基本上,在 AJP13 通訊協定中,網路伺服器將 HTTP 標頭和 HTTP 主體(以 8K 塊進行 POST)傳送至 servlet 引擎,然後嘗試接收回覆。如果連線中斷,網路伺服器只會在接收時發現它。我們可以使用緩衝機制,但當您使用 servlet 引擎進行超過 8ko 資料的上傳作業時會發生什麼情況?AJP13 通訊協定中的技巧是在服務結束後新增一些位元組以進行讀取
EXAMPLE OF DISCUSSION BETWEEN WEB SERVER AND SERVLET ENGINE
AJP HTTP-HEADER (+ HTTP-POST) (WEB->SERVLET)
AJP HTTP-REPLY (SERVLET->WEB)
AJP END OF DISCUSSION (SERVLET->WEB)
---> AJP STATUS (SERVLET->WEB AJP13)
+------------+-------------+
| STATUS CMD | STATUS DATA |
+------------+-------------+
- 狀態指令和狀態資料長度為一個位元組。