<-
Apache > HTTP 伺服器 > 說明文件 > 版本 2.4 > 開發人員說明文件

如何讓過濾器在 Apache 2.0 中作用

可用的語言:  en 

警告

這是一封電子郵件 (<022501c1c529$f63a9550$7f00000a@KOJ>) 的剪貼內容,只重新格式化以提高可讀性,並未更新,但可能作為後續研究的良好開端。

Support Apache!

請另見

top

過濾器類型

有三種基本過濾器類型 (每種類型實際上都可再分成兩種類別,但這是在後面討論) 。

連線
此類型的過濾器在此連線的生命期間內有效 (AP_FTYPE_CONNECTIONAP_FTYPE_NETWORK)。
協定
此類型的過濾器在此要求的生命期間內有效,從客戶端觀點來看,表示這個要求從傳送要求時開始到接收回應時結束 (AP_FTYPE_PROTOCOLAP_FTYPE_TRANSCODE)。
資源
此類型的過濾器在此內容用於滿足要求的期間內有效。對於簡單要求,這與 PROTOCOL 相同,但內部重新導向和子要求可以在要求結束前變更內容 (AP_FTYPE_RESOURCEAP_FTYPE_CONTENT_SET)。

區分協定濾器和資源過濾器非常重要,資源過濾器會繫結到特定資源,也可能繫結到標題資訊,但主要繫結到資源。如果您正在撰寫過濾器,且想要知道它是資源過濾器還是協定過濾器,請正確提出以下問題:如果要求重新導向到不同的資源,是否可以移除這個過濾器?答案如果是,則為資源過濾器;否則,則很有可能是協定過濾器或連線過濾器。我不會深入討論連線過濾器,因為它們似乎已被廣泛了解。基於這個定義,以下幾個範例可能有所幫助

拜特範圍
我們編寫程式碼讓它可以插入所有要求,並且如果未使用的話予以移除。由於這個過濾器在所有要求開始時都會啟用,因此如果它被重新導向,則無法將它移除,所以這是一個協定過濾器。
http_header
這個過濾器實際上會將標題寫入網路。這顯然是一個必要的過濾器 (除了 asis 案例,這是特殊的,將會在下方討論),所以它是一個協定過濾器。
壓縮
管理員會根據請求所要求的文件設定這個濾鏡。如果我們從自動索引頁面內部重新導向到 index.html 頁面,則可能會根據設定新增或移除 deflate 濾鏡,因此這是一種資源濾鏡。

每個類別進一步細分為更多兩種的濾鏡類型純粹是為了排序。我們可以將它移除,並且只允許一種濾鏡類型,但順序可能會錯誤,而且我們需要執行破解才能使其運作。目前,RESOURCE 濾鏡只有一個濾鏡類型,但這應該會改變。

top

濾鏡是如何插入的?

理論上來說,它其實很簡單,但程式碼很複雜。首先,了解每一個要求有三個濾鏡清單非常重要,但它們全都被串接在一起

以前的問題是我們使用單一連接清單建立濾鏡堆疊,而且我們從「正確」的位置開始。這表示,如果我在堆疊中有 RESOURCE 濾鏡,而且我新增 CONNECTION 濾鏡,CONNECTION 濾鏡就會被忽略。這應該合理,因為我們會將連線濾鏡插入 c->output_filters 清單的頂部,但 r->output_filters 的結尾指向以前在 c->output_filters 最前面的濾鏡。這顯然是錯誤的。新的插入程式碼使用雙向連接清單。這樣的好處是我們永遠不會遺失已插入的濾鏡。很不幸地,這會帶來一組獨立的麻煩。

問題在於,我們有兩種不同的情況,會使用子要求。第一個是會在回應中插入更多資料。第二個是使用內部重新導向取代現有的回應。這兩種情況不一樣,需要視情況處理。

在第一種情況中,我們會在處理程式或濾鏡內建立子要求。這表示應該將下一個濾鏡傳遞給 make_sub_request 函式,並且子要求中的最後一個資源濾鏡會指向主要求中的下一個濾鏡。這合理,因為子要求資料需要流經與主要求相同的濾鏡組。圖形化表示可能有幫助

Default_handler --> includes_filter --> byterange --> ...

如果包含濾鏡會產生子要求,那麼我們不想要來自該子要求的資料經過包含濾鏡,因為它可能不是 SSI 資料。所以,子要求會加入以下內容

Default_handler --> includes_filter -/-> byterange --> ...
                                    /
Default_handler --> sub_request_core

如果子請求是 SSI 資料怎麼辦?這很容易,includes_filter 是資源過濾器,因此會在 Default_handlersub_request_core 過濾器之間加入子請求中。

子請求的第二個案例是當子請求即將成為實際請求。每當在處理常式或過濾器外建立子請求,而且 NULL 傳遞做為 make_sub_request 函式的下一個過濾器時,便會發生這種情況。

在此案例中,資源過濾器對新的請求不再有意義,因為資源已變更。因此,我們並未從頭開始,而是簡單地讓子請求的資源過濾器前面指向舊請求的通訊協定過濾器的前面。這表示我們不會遺失任何通訊協定過濾器,也不會嘗試透過不應該看到過濾器的資料來傳送此資料。

問題在於,我們現在對我們的過濾器堆疊使用雙向連結清單。但是,您應該會注意到,在此模型中,兩個清單可以相交。因此,您如何處理先前的指標?這是個很難回答的問題,因為沒有「正確」的答案,兩種方法都同樣有效。我看了一下我們為何使用先前的指標。這樣做的唯一原因是允許更容易新增新的伺服器。有了這層認識,我選擇的解決方案是讓先前的指標始終停留原始請求。

這會導致更複雜的邏輯,但適用於所有案例。我讓指標移至子請求的疑慮是對於更常見的案例(其中子請求用於將資料加入回應),主過濾器鏈會錯誤。對我而言,這似乎不是個好主意。

top

Asis

最後一個主題。 :-) Mod_Asis немного взломан, 但處理常式需要移除所有過濾器(僅保留連線過濾器)並傳送資料。如果您使用 mod_asis,則放棄所有其他設定檔。

top

說明

絕對最後一點是,這個程式碼如此難以處理正確的原因,是因為我們進行過大量的修改以強制程式碼正常運作。我原本撰寫了大部分的修改,所以我得負最大的責任。不過,現在程式碼已正確無誤,我已開始移除一些修改。大多數人都應該看過 reset_filtersadd_required_filters 函式不見了。這些插入通訊協定層級過濾器以因應錯誤狀態,實際上,兩個函式在一個接一個後執行相同的動作,這真的很奇怪。因為我們不再因錯誤案例而遺失通訊協定過濾器,這些修改才得以移除。HTTP_HEADERContent-lengthByterange 過濾器都是在 insert_filters 階段加入的,因為如果這些過濾器在先前加入,我們會有一些有趣的互動。現在,這些過濾器都可以移動,以透過 HTTP_INCORECORE_IN 過濾器加入。這樣可以讓程式碼更容易追蹤。

可用的語言:  en 

top

評論

注意事項
這不是問與答部分。在此發表的留言應指向改進文件或伺服器的建議,而我們的版主可能會移除已實施或被認為無效/離題的留言。關於如何管理 Apache HTTP Server 的問題應提交至 Libera.chat 上的我們的 IRC 頻道 #httpd,或發送至我們的郵件清單