Apache HTTP 伺服器版本 2.4
可用的語言: en
這是一封電子郵件 (<022501c1c529$f63a9550$7f00000a@KOJ>) 的剪貼內容,只重新格式化以提高可讀性,並未更新,但可能作為後續研究的良好開端。
有三種基本過濾器類型 (每種類型實際上都可再分成兩種類別,但這是在後面討論) 。
連線
AP_FTYPE_CONNECTION
、AP_FTYPE_NETWORK
)。協定
AP_FTYPE_PROTOCOL
、AP_FTYPE_TRANSCODE
)。資源
PROTOCOL
相同,但內部重新導向和子要求可以在要求結束前變更內容 (AP_FTYPE_RESOURCE
、AP_FTYPE_CONTENT_SET
)。區分協定濾器和資源過濾器非常重要,資源過濾器會繫結到特定資源,也可能繫結到標題資訊,但主要繫結到資源。如果您正在撰寫過濾器,且想要知道它是資源過濾器還是協定過濾器,請正確提出以下問題:如果要求重新導向到不同的資源,是否可以移除這個過濾器?答案如果是,則為資源過濾器;否則,則很有可能是協定過濾器或連線過濾器。我不會深入討論連線過濾器,因為它們似乎已被廣泛了解。基於這個定義,以下幾個範例可能有所幫助
每個類別進一步細分為更多兩種的濾鏡類型純粹是為了排序。我們可以將它移除,並且只允許一種濾鏡類型,但順序可能會錯誤,而且我們需要執行破解才能使其運作。目前,RESOURCE
濾鏡只有一個濾鏡類型,但這應該會改變。
理論上來說,它其實很簡單,但程式碼很複雜。首先,了解每一個要求有三個濾鏡清單非常重要,但它們全都被串接在一起
r->output_filters
(對應到 RESOURCE)r->proto_output_filters
(對應到 PROTOCOL)r->connection->output_filters
(對應到 CONNECTION)以前的問題是我們使用單一連接清單建立濾鏡堆疊,而且我們從「正確」的位置開始。這表示,如果我在堆疊中有 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_handler
和 sub_request_core
過濾器之間加入子請求中。
子請求的第二個案例是當子請求即將成為實際請求。每當在處理常式或過濾器外建立子請求,而且 NULL 傳遞做為 make_sub_request
函式的下一個過濾器時,便會發生這種情況。
在此案例中,資源過濾器對新的請求不再有意義,因為資源已變更。因此,我們並未從頭開始,而是簡單地讓子請求的資源過濾器前面指向舊請求的通訊協定過濾器的前面。這表示我們不會遺失任何通訊協定過濾器,也不會嘗試透過不應該看到過濾器的資料來傳送此資料。
問題在於,我們現在對我們的過濾器堆疊使用雙向連結清單。但是,您應該會注意到,在此模型中,兩個清單可以相交。因此,您如何處理先前的指標?這是個很難回答的問題,因為沒有「正確」的答案,兩種方法都同樣有效。我看了一下我們為何使用先前的指標。這樣做的唯一原因是允許更容易新增新的伺服器。有了這層認識,我選擇的解決方案是讓先前的指標始終停留原始請求。
這會導致更複雜的邏輯,但適用於所有案例。我讓指標移至子請求的疑慮是對於更常見的案例(其中子請求用於將資料加入回應),主過濾器鏈會錯誤。對我而言,這似乎不是個好主意。
絕對最後一點是,這個程式碼如此難以處理正確的原因,是因為我們進行過大量的修改以強制程式碼正常運作。我原本撰寫了大部分的修改,所以我得負最大的責任。不過,現在程式碼已正確無誤,我已開始移除一些修改。大多數人都應該看過 reset_filters
和 add_required_filters
函式不見了。這些插入通訊協定層級過濾器以因應錯誤狀態,實際上,兩個函式在一個接一個後執行相同的動作,這真的很奇怪。因為我們不再因錯誤案例而遺失通訊協定過濾器,這些修改才得以移除。HTTP_HEADER
、Content-length
和 Byterange
過濾器都是在 insert_filters
階段加入的,因為如果這些過濾器在先前加入,我們會有一些有趣的互動。現在,這些過濾器都可以移動,以透過 HTTP_IN
、CORE
和 CORE_IN
過濾器加入。這樣可以讓程式碼更容易追蹤。
可用的語言: en