Apache源代码全景分析第二卷——HTTP请求处理
版權聲明:
本文可以任意進行轉摘,但是必須保留以下內容:
1)、本文原始出處為Aapche中國, http://www.cn-apache.com
2)、HESEE悅色尚品,100%正版原裝進口美妝商城,假一賠三,滿200貨到付款,網址:http://www.hesee.cn
//
HTTP請求處理
10.1??請求處理模型
10.1.1?請求處理概述
從第一卷的分析中,我們知道Apache中對于請求的處理實際只有兩個函數:ap_read_request()和ap_process_request(),一旦通過ap_read_request()讀取了HTTP連接上的某個請求之后,Apache將調用函數ap_process_request對其進行處理。在整個Apache的核心內部,大部分讀者最關心的就是Apache中是如何處理客戶端的請求的。由于HTTP是基于TCP的應用層的協議,而TCP則是面向連接的傳輸層的協議,因此通信的雙方在傳輸數據之前必須建立起網絡連接。因此,通信雙發將首先建立TCP連接,然后接受HTTP數據,最后再關閉連接。
Apache中的HTTP請求是與前面所介紹的掛鉤緊緊關聯在一起的。從大的方面來看,Apache對HTTP的請求可以分為連接、處理和斷開連接三個階段。從小的方面而言,每個階段又可以分為更多的子階段。比如對HTTP的請求,我們可以進一步劃分為客戶身份驗證、客戶權限認證、請求校驗、URL重定向等階段,每一個階段調用相應的函數進行處理。在Apache中,這些子階段可以用術語“掛鉤(HOOK)”來描述。Apache中對請求的處理過程實質上就是依次調用一系列掛鉤的過程,不過由于HTTP請求類型的不同,它們所對應的掛鉤數目和類型也不盡相同。對于典型的HTTP請求,有一個默認的掛鉤調用順序,你可以按照這個默認的順序進行調用,也可以不遵遁這個順序,而根據自己的情況調整調用順序。整個HTTP的請求可以用圖10-1來描述:
圖10-1 HTTP請求模型
在圖10-1中,存在6種不同的掛鉤,對于請求a,只需要調用Hook2、Hook1;對于請求b,則需要調用Hook1、Hook6、Hook5;請求c需要依次調用Hook1、Hook4、Hook3、Hook6四個掛鉤。
在Apache中,掛鉤總是和掛鉤函數聯系在一起的。掛鉤是用來表示在處理HTTP請求中一組類似的操作,與之對應,掛鉤函數就是操作函數。不過即使掛鉤相同,對應的掛鉤函數也未必相同,如圖10-2所示。舉個簡單的例子,配置文件模塊和虛擬主機模塊都需要身份驗證掛鉤來確認訪問者能否訪問相應的資源,但兩個模塊的驗證方法則差別很大。因此,一個掛鉤同時是和一組掛鉤函數聯系在一起的。在請求處理過程中,調用掛鉤的時候實際上就是調用掛鉤函數組中的掛鉤函數。調用過程可以用圖10-2所示。Apache對指定掛鉤的掛鉤函數調用有兩種方式,一種就是將掛鉤函數組中的每個函數都調用一次,比如圖10-2中的掛鉤4;另一種就是從前往后調用,一旦找到合適的就停止繼續調用,圖10-2中的掛鉤1、掛鉤2、掛鉤3就是這種情況。
通過掛鉤機制,你可以自行修改服務器的行為,比如修改掛鉤函數或增加掛鉤函數,甚至增加掛鉤。不過增加掛鉤只是Apache?2.0才提供的功能。
圖10-2 請求掛鉤和掛鉤函數
由于所有的掛鉤函數最終都是定義在模塊之中,各個模塊能夠支持一定數目和一定類型的掛鉤,因此,如果我們將掛鉤、模塊和整個請求進行整體分析,則如圖10-3所示:
從圖10-3中我們可以看到整個請求的處理流程。
所有的模塊A、B、C、D、E組成模塊鏈表,而每個模塊分別支持不同的掛鉤。某一個請求與4種類型的掛鉤HOOK?type1、HOOK?type2、HOOK?type3及HOOK?type4關聯,當請求執行的時候,各個模塊中的對應的掛鉤函數將依次被調用,調用的順序很簡單,先調用掛鉤類型,后調用模塊類型。因此,從圖10-3中可以看出,當一個請求處理完畢,7個函數將被調用。
10.1.2??處理階段劃分
當HTTP頭讀取完畢后,服務器的狀態被修改為“busy_write”,與此同時,服務器將對該請求進行響應處理。整個請求階段可以被劃分為多個階段,各個階段可以用圖10-4進行描述。Apache?2.0版本中的請求處理流程與早期的Apache?1.3版本的處理流程幾乎相同。唯一的區別在于,在過濾器的概念中,Apache?2.0以上的版本中盡管只有一個內容處理器被使用,但是可能由多個模塊同時負責生成響應。
?
圖10-4 請求處理中的各個階段
整個請求處理可以被劃分為多個子階段,這些子階段分別是:
n?Url預處理階段
通常情況下,瀏覽器會自動地將請求的地址欄中的一些特殊字符(比如將空格轉換為%)和十六進制進行組合,比如空格就是“%20”,因此對于服務器而言,其需要將“%xx”格式的字符串重新還原為原來的字符串。同時,Apache有必要剔除URI中一些冗余的字符,比如“./xxx”、“xxx/../”或“.//xxx”等。在進行進一步的處理之前,有必要對這些URI進行規則處理。具體的處理由ap_unescape_url?()和ap_getparents()完成,函數的細節我們在后面的部分將深入了解。
n?請求配置信息查找
在前面我們曾經描述過Apache中的配置信息。配置信息可以分為多個種類:針對整個服務器的全局配置信息、針對某個虛擬主機的配置信息、針對某個連接的配置信息,以及針對某個請求的配置信息。在請求的處理過程中,很多的信息需要依賴這些配置信息去處理,比如授權信息。為此在進行繼續處理之前,服務器必須能夠得到所有的與該請求關聯的配置信息。
Apache中與特定請求關聯的配置信息總是用<Location>…</Location>配置段進行處理,因此,對于請求的URI,Apache需要查找當前的配置信息中是否有針對該URI的配置。配置查找通過location_walk進行。這項工作必須在模塊轉換URI之前進行,因為它可能會影響Apache對URI的轉換。
n?URL重寫(translate_name)
一些模塊會對URL進行重寫,通過對URL重寫,可以在請求文件的保存路徑發生變化的時候避免對外提供的URL被修改。比如mod_alias會將一個符合條件的URL用另一個別名URL進行替換,而mod_rewrite則會對給定的URL進行更加復雜的替換和修改。
在這個階段,如果某個模塊返回DECLINE,那么Apache將會返回一個500的錯誤碼給瀏覽器,這意味著通知瀏覽器“當前請求的URI無法進行轉換”,同時該錯誤被記入日志。
n?再次獲取與該請求相關的配置信息
轉換前的URI可能與轉換后的URI不相同,因此一旦URL經過轉換,Apache將有必要再調用location_walk獲取轉換后的URI所對應的配置信息。同時,核心將調用掛鉤map_to_storage的處理句柄core_map_to_storage()。一旦URI轉換之后,該URI所對應的Location、目錄及文件都將確定下來,此時,有必要獲取每一部分的配置信息。ap_directory_walk()和ap_file_walk()分別用來實現遍歷指定的目錄和文件的配置,這些配置與獲取的location配置信息進行合并,從而得到最終的完整的針對當前請求的URI的配置信息。
n?資源映射(map_to_storag)
該階段的目的僅僅有一個,那就是讓模塊確定特定的資源是否可以在磁盤上找到。使用這個掛鉤的原因是,如果數據要在磁盤上找到,而不是由模塊生成的,那么服務器就必須執行更加嚴格的安全檢查。在這種情況下,服務器所做的檢查越嚴格,就越有可能避免錯誤的發生。如果數據位于磁盤上,那么服務器就必須確保可以提供請求的文件。這個聽起來很簡單,其實并非如此。一些系統支持符號連接,因此,如果在路徑中有符號連接,那么服務器就可能無法理解符號。這種情況必須能夠在map_to_storage中處理。
如果請求的內容不是磁盤上的文件,而是動態生成的,那么這種檢查就沒有必要了。
n?頭信息解析(header_parser)
該階段的主要目的在于檢驗HTTP請求的報文頭,并根據請求頭信息做一些必要的處理。這是一個一般性目的的掛鉤,在配置完全有效且進一步特化之前啟用。在這一階段,你可以根據請求頭中的信息進行相關的設置,比如mod_setenvif就會根據特定的請求頭信息設置一些環境變量。
另外,如果你需要實現Apache中不支持的一些HTTP方法,比如HTTP?PATCH那么你也可以在該掛鉤階段實現。
n?訪問檢查(access_checker)
access_checker掛鉤被設計用于讓模塊根據與模塊的特定基礎限制對資源進行訪問。這很重要,因為它可以讓系統管理員根據任意數量的特性阻止用戶訪問它們的站點。例如,mod_access就可以讓管理員根據客戶的IP地址來限制訪問,這就可以讓相同的Web服務器同時為公共的Web站點和私有的Web站點服務。通過access_checker模塊做一些簡單的配置就可以減少相當一部分的無效的攻擊。
n?用戶檢查(check_user_id)
該掛鉤可以讓模塊認證用戶的名稱和密碼。對于大多數的身份驗證模塊來講,這意味著如果URI有所要求,就要確保隨請求發送口令信息,還要確保所提供的口令對確定用戶有效。服務器會為這個掛鉤運行所有的經過注冊的函數,直到有函數返回DECLINED之外的內容。大多數實現check_user_id的函數模塊都會使用下面的4個有效的返回值:
(1)、OK用戶名和用戶密碼已經成功的通過認證;
(2)、HTTP_UNAUTHORIED沒有找到用戶或該用戶提供的密碼不正確;
(3)、HTTP_INTERNAL_SERVER_ERROR在認證這個用戶的時候出現了嚴重的問題,服務器不能繼續為這個用戶請求服務器;
(4)、DECLINED這個模塊不能支持用戶認證。
n?用戶授權權限檢查(auth_checker)
該模塊用以確定通過認證的用戶是否有權利查看請求的資源。這個掛鉤要依賴由核心實現的require指令。通過使用require指令,管理員就能將資源的訪問權限制到一組已經配置過的用戶組,或者由服務器認可的用戶。這個掛鉤在處理返回代碼的方式上與其余的掛鉤有所不同,如果針對這個掛鉤的所有的模塊都返回DECLINED,并且這個請求已經啟用了認證,那么服務器就會使用錯誤消息終止當前的請求。
access_checker、check_user_id和auth_checker三個掛鉤屬于安全管理的內容,我們在安全管理章節會詳細描述它們。
n?資源類型檢查(type_checker)
該掛鉤會為模塊提供一個機會來確定或修改文檔類型的特性。例如,mod_mime會利用該掛鉤來設置語言、編碼及請求類型。在這個階段,你還可以修改被請求的資源所調用的處理器函數。
n?fixups
請求處理中調用的最后一個掛鉤就是fixups。這是一個一般性的掛鉤,沒有特定的執行意義。該掛鉤被設計用來讓模塊在向客戶端發送響應之前確定響應頭。這是在服務器開始生成數據之前,模塊影響響應數據的最后機會。如果在服務器開始處理器階段之前能找到任何錯誤,那么模塊都應該利用所有的機會來進行這樣的工作。如果服務器開始為無效的請求生成響應,那么你就會在不能發送請求的頁面上浪費時間和資源。
整個請求的概要流程可以用圖10-5描述:
?
在ap_process_request中,各個階段依次按序執行完成,但是完整的HTTP請求至少還要包括下面三個處理階段:
n?insert_filter
在該階段,內容過濾器將被插入到請求中,他們用于對處理器生成的需要返回給客戶端的數據進行過濾處理。
n?handler
該階段被稱為內容生成器,主要的任務就是生成客戶端所請求的響應。
n?logger
該階段用于記錄請求中的對話日志。
所有的掛鉤組合起來可以概括為4個不同的階段:
n?post_read_request階段
該階段標志著從協議到請求處理的過渡,在該掛鉤中主要的任務就是設置request_rec中需要被設置的內容。雖然request_rec已經建立起來,但還是有很多的內容尚未被建立。
n?從translate_name到fixups階段:
該階段通常被稱為“請求準備階段”,主要對請求做必要的準備
n?從insert_filter到handler階段
insert_filter和handler組合在一起構成了Apache中的內容生成器,該階段屬于內容生成階段,生成的內容最終將返回給客戶端。
n?logger階段
這是最后的階段,與請求處理本身的關系不是非常大,主要用于日志記錄。
在下面的部分,我們將描述請求處理中的URI處理,配置數據處理。部分階段的詳細處理我們會在后面的章節中給出,還有一部分屬于模塊的內容如安全處理等,我們會將其放到第三卷中進行更深入的討論。
總結
以上是生活随笔為你收集整理的Apache源代码全景分析第二卷——HTTP请求处理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: rtp h264打包和解包
- 下一篇: Apache与Nginx网络模型