顯示具有 apache 標籤的文章。 顯示所有文章
顯示具有 apache 標籤的文章。 顯示所有文章

2010年8月13日 星期五

httpd.conf 組態檔

紀錄Apache HTTP Server的組態檔(configuration file),這是預設的原始檔案內容,版本是Apache 2.2.16版。注意下方粗體字是常用的組態指令與注意事項。

#
# This is the main Apache HTTP server configuration file.  It contains the
# configuration directives that give the server its instructions.
# See for detailed information.
# In particular, see
#
# for a discussion of each configuration directive.
#
# Do NOT simply read the instructions in here without understanding
# what they do.  They're here only as hints or reminders.  If you are unsure
# consult the online docs. You have been warned.
#
# Configuration and logfile names: If the filenames you specify for many
# of the server's control files begin with "/" (or "drive:/" for Win32), the
# server will use that explicit path.  If the filenames do *not* begin
# with "/", the value of ServerRoot is prepended -- so "logs/foo.log"
# with ServerRoot set to "C:/Program Files/Apache Software Foundation/Apache2.2" will be interpreted by the
# server as "C:/Program Files/Apache Software Foundation/Apache2.2/logs/foo.log".
#
# NOTE: Where filenames are specified, you must use forward slashes
# instead of backslashes (e.g., "c:/apache" instead of "c:\apache").
# If a drive letter is omitted, the drive on which httpd.exe is located
# will be used by default.  It is recommended that you always supply
# an explicit drive letter in absolute paths to avoid confusion.

#
# ServerRoot: The top of the directory tree under which the server's
# configuration, error, and log files are kept.
#
# Do not add a slash at the end of the directory path.  If you point
# ServerRoot at a non-local disk, be sure to point the LockFile directive
# at a local disk.  If you wish to share the same ServerRoot for multiple
# httpd daemons, you will need to change at least LockFile and PidFile.
#
ServerRoot "C:/Program Files/Apache Software Foundation/Apache2.2"

#
# Listen: Allows you to bind Apache to specific IP addresses and/or
# ports, instead of the default. See also the
# directive.
#
# Change this to Listen on specific IP addresses as shown below to
# prevent Apache from glomming onto all bound IP addresses.
#
#Listen 12.34.56.78:80
Listen 80

#
# Dynamic Shared Object (DSO) Support
#
# To be able to use the functionality of a module which was built as a DSO you
# have to place corresponding `LoadModule' lines at this location so the
# directives contained in it are actually available _before_ they are used.
# Statically compiled modules (those listed by `httpd -l') do not need
# to be loaded here.
#
# Example:
# LoadModule foo_module modules/mod_foo.so
#
LoadModule actions_module modules/mod_actions.so
LoadModule alias_module modules/mod_alias.so
LoadModule asis_module modules/mod_asis.so
LoadModule auth_basic_module modules/mod_auth_basic.so
#LoadModule auth_digest_module modules/mod_auth_digest.so
#LoadModule authn_alias_module modules/mod_authn_alias.so
#LoadModule authn_anon_module modules/mod_authn_anon.so
#LoadModule authn_dbd_module modules/mod_authn_dbd.so
#LoadModule authn_dbm_module modules/mod_authn_dbm.so
LoadModule authn_default_module modules/mod_authn_default.so
LoadModule authn_file_module modules/mod_authn_file.so
#LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
#LoadModule authz_dbm_module modules/mod_authz_dbm.so
LoadModule authz_default_module modules/mod_authz_default.so
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
LoadModule authz_host_module modules/mod_authz_host.so
#LoadModule authz_owner_module modules/mod_authz_owner.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule autoindex_module modules/mod_autoindex.so
#LoadModule cache_module modules/mod_cache.so
#LoadModule cern_meta_module modules/mod_cern_meta.so
LoadModule cgi_module modules/mod_cgi.so
#LoadModule charset_lite_module modules/mod_charset_lite.so
#LoadModule dav_module modules/mod_dav.so
#LoadModule dav_fs_module modules/mod_dav_fs.so
#LoadModule dav_lock_module modules/mod_dav_lock.so
#LoadModule dbd_module modules/mod_dbd.so
#LoadModule deflate_module modules/mod_deflate.so
LoadModule dir_module modules/mod_dir.so
#LoadModule disk_cache_module modules/mod_disk_cache.so
#LoadModule dumpio_module modules/mod_dumpio.so
LoadModule env_module modules/mod_env.so
#LoadModule expires_module modules/mod_expires.so
#LoadModule ext_filter_module modules/mod_ext_filter.so
#LoadModule file_cache_module modules/mod_file_cache.so
#LoadModule filter_module modules/mod_filter.so
#LoadModule headers_module modules/mod_headers.so
#LoadModule ident_module modules/mod_ident.so
#LoadModule imagemap_module modules/mod_imagemap.so
LoadModule include_module modules/mod_include.so
#LoadModule info_module modules/mod_info.so
LoadModule isapi_module modules/mod_isapi.so
#LoadModule ldap_module modules/mod_ldap.so
#LoadModule logio_module modules/mod_logio.so
LoadModule log_config_module modules/mod_log_config.so
#LoadModule log_forensic_module modules/mod_log_forensic.so
#LoadModule mem_cache_module modules/mod_mem_cache.so
LoadModule mime_module modules/mod_mime.so
#LoadModule mime_magic_module modules/mod_mime_magic.so
LoadModule negotiation_module modules/mod_negotiation.so
#LoadModule proxy_module modules/mod_proxy.so
#LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
#LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
#LoadModule proxy_connect_module modules/mod_proxy_connect.so
#LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
#LoadModule proxy_http_module modules/mod_proxy_http.so
#LoadModule reqtimeout_module modules/mod_reqtimeout.so
#LoadModule rewrite_module modules/mod_rewrite.so
LoadModule setenvif_module modules/mod_setenvif.so
#LoadModule speling_module modules/mod_speling.so
#LoadModule ssl_module modules/mod_ssl.so
#LoadModule status_module modules/mod_status.so
#LoadModule substitute_module modules/mod_substitute.so
#LoadModule unique_id_module modules/mod_unique_id.so
#LoadModule userdir_module modules/mod_userdir.so
#LoadModule usertrack_module modules/mod_usertrack.so
#LoadModule version_module modules/mod_version.so
#LoadModule vhost_alias_module modules/mod_vhost_alias.so



#
# If you wish httpd to run as a different user or group, you must run
# httpd as root initially and it will switch.
#
# User/Group: The name (or #number) of the user/group to run httpd as.
# It is usually good practice to create a dedicated user and group for
# running httpd, as with most system services.
#
User daemon
Group daemon




# 'Main' server configuration
#
# The directives in this section set up the values used by the 'main'
# server, which responds to any requests that aren't handled by a
# definition.  These values also provide defaults for
# any containers you may define later in the file.
#
# All of these directives may appear inside containers,
# in which case these default settings will be overridden for the
# virtual host being defined.
#

#
# ServerAdmin: Your address, where problems with the server should be
# e-mailed.  This address appears on some server-generated pages, such
# as error documents.  e.g. admin@your-domain.com
#
ServerAdmin admin@localhost

#
# ServerName gives the name and port that the server uses to identify itself.
# This can often be determined automatically, but we recommend you specify
# it explicitly to prevent problems during startup.
#
# If your host doesn't have a registered DNS name, enter its IP address here.
#
#ServerName localhost:80

#
# DocumentRoot: The directory out of which you will serve your
# documents. By default, all requests are taken from this directory, but
# symbolic links and aliases may be used to point to other locations.
#
DocumentRoot "C:/Program Files/Apache Software Foundation/Apache2.2/htdocs"

#
# Each directory to which Apache has access can be configured with respect
# to which services and features are allowed and/or disabled in that
# directory (and its subdirectories).
#
# First, we configure the "default" to be a very restrictive set of
# features.
#

    Options FollowSymLinks
    AllowOverride None
    Order deny,allow
    Deny from all


#
# Note that from this point forward you must specifically allow
# particular features to be enabled - so if something's not working as
# you might expect, make sure that you have specifically enabled it
# below.
#

#
# This should be changed to whatever you set DocumentRoot to.
#

    #
    # Possible values for the Options directive are "None", "All",
    # or any combination of:
    #   Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
    #
    # Note that "MultiViews" must be named *explicitly* --- "Options All"
    # doesn't give it to you.
    #
    # The Options directive is both complicated and important.  Please see
    # http://httpd.apache.org/docs/2.2/mod/core.html#options
    # for more information.
    #
    Options Indexes FollowSymLinks

    #
    # AllowOverride controls what directives may be placed in .htaccess files.
    # It can be "All", "None", or any combination of the keywords:
    #   Options FileInfo AuthConfig Limit
    #
    AllowOverride None

    #
    # Controls who can get stuff from this server.
    #
    Order allow,deny
    Allow from all



#
# DirectoryIndex: sets the file that Apache will serve if a directory
# is requested.
#

    DirectoryIndex index.html


#
# The following lines prevent .htaccess and .htpasswd files from being
# viewed by Web clients.
#

    Order allow,deny
    Deny from all
    Satisfy All


#
# ErrorLog: The location of the error log file.
# If you do not specify an ErrorLog directive within a
# container, error messages relating to that virtual host will be
# logged here.  If you *do* define an error logfile for a
# container, that host's errors will be logged there and not here.
#
ErrorLog "logs/error.log"

#
# LogLevel: Control the number of messages logged to the error_log.
# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
#
LogLevel warn


    #
    # The following directives define some format nicknames for use with
    # a CustomLog directive (see below).
    #
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%h %l %u %t \"%r\" %>s %b" common

    
      # You need to enable mod_logio.c to use %I and %O
      LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
  

    #
    # The location and format of the access logfile (Common Logfile Format).
    # If you do not define any access logfiles within a
    # container, they will be logged here.  Contrariwise, if you *do*
    # define per- access logfiles, transactions will be
    # logged therein and *not* in this file.
    #
    CustomLog "logs/access.log" common

    #
    # If you prefer a logfile with access, agent, and referer information
    # (Combined Logfile Format) you can use the following directive.
    #
    #CustomLog "logs/access.log" combined



    #
    # Redirect: Allows you to tell clients about documents that used to
    # exist in your server's namespace, but do not anymore. The client
    # will make a new request for the document at its new location.
    # Example:
    # Redirect permanent /foo http://localhost/bar

    #
    # Alias: Maps web paths into filesystem paths and is used to
    # access content that does not live under the DocumentRoot.
    # Example:
    # Alias /webpath /full/filesystem/path
    #
    # If you include a trailing / on /webpath then the server will
    # require it to be present in the URL.  You will also likely
    # need to provide a section to allow access to
    # the filesystem path.

    #
    # ScriptAlias: This controls which directories contain server scripts.
    # ScriptAliases are essentially the same as Aliases, except that
    # documents in the target directory are treated as applications and
    # run by the server when requested rather than as documents sent to the
    # client.  The same rules about trailing "/" apply to ScriptAlias
    # directives as to Alias.
    #
    ScriptAlias /cgi-bin/ "C:/Program Files/Apache Software Foundation/Apache2.2/cgi-bin/"




    #
    # ScriptSock: On threaded servers, designate the path to the UNIX
    # socket used to communicate with the CGI daemon of mod_cgid.
    #
    #Scriptsock logs/cgisock


#
# "C:/Program Files/Apache Software Foundation/Apache2.2/cgi-bin" should be changed to whatever your ScriptAliased
# CGI directory exists, if you have that configured.
#

    AllowOverride None
    Options None
    Order allow,deny
    Allow from all


#
# DefaultType: the default MIME type the server will use for a document
# if it cannot otherwise determine one, such as from filename extensions.
# If your server contains mostly text or HTML documents, "text/plain" is
# a good value.  If most of your content is binary, such as applications
# or images, you may want to use "application/octet-stream" instead to
# keep browsers from trying to display binary files as though they are
# text.
#
DefaultType text/plain


    #
    # TypesConfig points to the file containing the list of mappings from
    # filename extension to MIME-type.
    #
    TypesConfig conf/mime.types

    #
    # AddType allows you to add to or override the MIME configuration
    # file specified in TypesConfig for specific file types.
    #
    #AddType application/x-gzip .tgz
    #
    # AddEncoding allows you to have certain browsers uncompress
    # information on the fly. Note: Not all browsers support this.
    #
    #AddEncoding x-compress .Z
    #AddEncoding x-gzip .gz .tgz
    #
    # If the AddEncoding directives above are commented-out, then you
    # probably should define those extensions to indicate media types:
    #
    AddType application/x-compress .Z
    AddType application/x-gzip .gz .tgz

    #
    # AddHandler allows you to map certain file extensions to "handlers":
    # actions unrelated to filetype. These can be either built into the server
    # or added with the Action directive (see below)
    #
    # To use CGI scripts outside of ScriptAliased directories:
    # (You will also need to add "ExecCGI" to the "Options" directive.)
    #
    #AddHandler cgi-script .cgi

    # For type maps (negotiated resources):
    #AddHandler type-map var

    #
    # Filters allow you to process content before it is sent to the client.
    #
    # To parse .shtml files for server-side includes (SSI):
    # (You will also need to add "Includes" to the "Options" directive.)
    #
    #AddType text/html .shtml
    #AddOutputFilter INCLUDES .shtml


#
# The mod_mime_magic module allows the server to use various hints from the
# contents of the file itself to determine its type.  The MIMEMagicFile
# directive tells the module where the hint definitions are located.
#
#MIMEMagicFile conf/magic

#
# Customizable error responses come in three flavors:
# 1) plain text 2) local redirects 3) external redirects
#
# Some examples:
#ErrorDocument 500 "The server made a boo boo."
#ErrorDocument 404 /missing.html
#ErrorDocument 404 "/cgi-bin/missing_handler.pl"
#ErrorDocument 402 http://localhost/subscription_info.html
#

#
# EnableMMAP and EnableSendfile: On systems that support it,
# memory-mapping or the sendfile syscall is used to deliver
# files.  This usually improves server performance, but must
# be turned off when serving from networked-mounted
# filesystems or if support for these functions is otherwise
# broken on your system.
#
#EnableMMAP off
#EnableSendfile off

# Supplemental configuration
#
# The configuration files in the conf/extra/ directory can be
# included to add extra features or to modify the default configuration of
# the server, or you may simply copy their contents here and change as
# necessary.

# Server-pool management (MPM specific)
#Include conf/extra/httpd-mpm.conf

# Multi-language error messages
#Include conf/extra/httpd-multilang-errordoc.conf

# Fancy directory listings
#Include conf/extra/httpd-autoindex.conf

# Language settings
#Include conf/extra/httpd-languages.conf

# User home directories
#Include conf/extra/httpd-userdir.conf

# Real-time info on requests and configuration
#Include conf/extra/httpd-info.conf

# Virtual hosts
#Include conf/extra/httpd-vhosts.conf

# Local access to the Apache HTTP Server Manual
#Include conf/extra/httpd-manual.conf

# Distributed authoring and versioning (WebDAV)
#Include conf/extra/httpd-dav.conf

# Various default settings
#Include conf/extra/httpd-default.conf

# Secure (SSL/TLS) connections
#Include conf/extra/httpd-ssl.conf
#
# Note: The following must must be present to support
#       starting without SSL on platforms with no /dev/random equivalent
#       but a statically compiled-in mod_ssl.
#

SSLRandomSeed startup builtin
SSLRandomSeed connect builtin


Apache HTTP Server 主目錄

今天看看Apache HTTP Server安裝於Win32目錄之下的情形,一般來說,預設值的安裝路徑是C:\Program Files\Apache Software Foundation\Apache2.2之中,裡面的資料夾與檔案如下:
  • 檔案資料夾
    • bin,
      主程式(httpd.exe)的存放位置,還有一些工具像是ApacheMonitor.exe的程式。
    • cgi-bin,
      儲存CGI script的地方。
    • conf,
      組態檔(Configuration File)的存放位置,最重要的是httpd.conf檔案
    • error,
      錯誤訊息頁面。
    • htdocs,
      網站根目錄的位置。
    • icons,
      存放圖示檔。
    • logs,
      存放日誌檔案,像是access.log和error.log。
    • manual,
      使用手冊。
    • modules,
      模組的存放位置。
  • 檔案
    • ABOUT_APACHE.txt,說明Apache HTTP Server是什麼、做什麼、誰做的。
    • CHANGES.txt,修改記錄
    • INSTALL.txt,安裝說明文件
    • LICENSE.txt,授權條款(許可說明文件)
    • NOTICE.txt,注意事項
    • README.txt,請先讀我檔案
    • README-win32.txt,有關Windows平台的README檔案
###

2010年8月12日 星期四

Apache The Definitive Guide 技術手冊

經過了一年多一點,這段期間累積對於Windows應用程式開發的知識與經驗,現在回頭看看Apache,我的視野已經不再是相同的高度。再次重拾書籍複習,這本書是「Apache技術手冊(第三版)」,大概是中文書裡唯一有關Apache的經典翻譯書籍!前一年,沒有時間細細品味Apache的美,現在經歷多了,有能力可以仔細咀嚼那其中的奧妙之處。

這只是開端。This is an inception.

Ben Laurie & Peter Laurie原著,郭文生編譯,Apache技術手冊(第三版),台北:歐萊禮,2003。

發行者:美商歐萊禮股份有限公司台灣分公司(O'Reilly Media, Inc. Taiwan Branch)

目錄

第一章 Apache 入門
  • Web伺服器的功能
  • Apache的運作方式
  • Apache與網路
  • HTTP客戶端的運作方式
  • 伺服端的運作方式
  • Apache之安裝規劃
  • Windows的問題
  • Apache的版本
  • 安裝Apache
  • Unix下建製Apache 1.3.X
  • Apache 2.0的新功能
  • 在Unix下製成與安裝Apache 2.0
  • Windows下的Apache
第二章 設定 Apache:起手式
  • Apache 網站的背後
  • site.toddle
  • 架設 Unix 伺服器
  • 指令
第三章 建立真實網站
  • 較佳的網站:site.simple
  • Butterthlies 公司上線了
  • 區塊指令
  • 其它的指令
  • HTTP 的回應標頭
  • 再啟動
  • .htaccess
  • CERN 中介檔
  • 逾期
第四章 虛擬主機
  • 兩個網站與 Apache
  • 虛擬主機
  • 兩個 Apache 的分身
  • 動態設定的虛擬主機
第五章 驗證
  • 驗證協定
  • 驗證指令
  • Unix 下的密碼
  • Win32 下的密碼
  • Web 上的密碼
  • 從用戶端的觀點出發
  • CGI Script
  • 主題的變化
  • Order、Allow、與 Deny
  • Unix 上的 DBM 檔
  • 摘要驗證
  • 匿名存取
  • 實驗
  • 自動的使用者資訊
  • 使用 .htaccess 檔
  • 指令的改寫
第六章 網頁內容描述與修正
  • MIME 類型
  • 網頁內容協商
  • 語言協商
  • 類型對應表
  • 瀏覽器與 HTTP 1.1
  • 過濾器
第七章 製作索引
  • 製作較佳的索引
  • 製作自己的索引
  • 影像地圖(Imagemap)
  • 影像地圖的指令
第八章 重導向
  • Alias
  • Rewrite
  • 重寫的範例
  • 拼字
第九章 代理伺服器
  • 安全防護
  • 代理伺服器的指令
  • 外表上的錯誤
  • 效能
  • 設定
第十章 日誌紀錄
  • 用 Script 及資料庫建立日誌
  • Apache 的日誌機制
  • 組態的日誌紀錄
  • AddModuleInfo
  • 狀態
第十一章 安全防護
  • 內部與外部使用者
  • 數位簽章、虛擬現金
  • 憑證
  • 防火牆
  • 法律上的問題
  • Secure Sockets Layer(SSL)
  • Apache 的安全防護措施
  • SSL 的指令
  • 密碼套件
  • 實際狀況下的安全防護
  • 未來的方向
第十二章 執行大型網站
  • 主機架設
  • 伺服器的安全防護
  • 管理大型網站
  • 支援軟體
  • 擴充性
  • 負載平衡
第十三章 建製應用程式
  • 以網站當作應用程式
  • 提供應用程式的邏輯
  • XML、XSLT,與 Web 應用程式
第十四章 伺服端擴充
  • 檔案大小
  • 檔案修改時間
  • 引入
  • 執行 CGI
  • Echo
  • Apache v2:SSI 過濾器
第十五章 PHP
  • 安裝 PHP
  • site.php
第十六章 CGI 與 Perl
  • CGI 的世界
  • 告訴 Apache 關於 script 的資訊『318』
  • 設定環境變數
  • Cookies
  • Script 指令
  • Unix 上的 suEXEC
  • 處理器(Handler)
  • Actions
  • 瀏覽器
第十七章 mod_perl
  • mod_perl 的運作方式
  • mod_perl 的文件
  • 安裝 mod_perl — 簡易法
  • 修正你的 script 以便在 mod_perl 下執行
  • 全域變數
  • Strict 前置條件
  • 載入變動
  • 開啟與關閉檔案
  • 設定 Apache 以使用 mod_perl
第十八章 mod_jserv 與 Tomcat
  • mod_jserv
  • Tomcat
  • 連接 Tomcat 與 Apache
第十九章 XML 與 Cocoon
  • XML
  • XML 與 Perl
  • Cocoon
  • Cocoon 1.8 與 JServ
  • Cocoon 2.0.3 與 Tomcat
  • 測試 Cocoon
第二十章 Apache 的 API
  • 文件
  • APR
  • 集散區(Pool)
  • 以伺服器為基準的組態
  • 以目錄為基準的組態
  • 以請求為基準(per-request)的資訊
  • 存取組態與請求資訊
  • 掛鉤、選擇性的掛鉤,以及選擇性的函式
  • 過濾器、儲存區,及儲存區串列
  • 模組
第廿一章 編寫 Apache 的模組
  • 概要說明
  • 狀態碼
  • 模組結構
  • 完整的範例
  • 一般的提示
  • 移植至 Apache 2.0
附錄 Apache 1.x 的 API

索引

2009年7月3日 星期五

Apache Filter Module過濾器模組

從應用模組程式開發的角度來看,Apache 2.x的最重要改進與創新就是過濾器(filter)的架構,過濾器使得處理不同的資料可以隨心所欲的運作。

從Apache 2的架構來看,可以分為兩個正交軸,一為處理軸(Processing Axis),另一為資料軸(Data Axis)。每一次的請求皆由處理軸來接受,其中會經過許許多多的掛勾(hook),於是進行一些處理(handler)的呼叫。

過濾器依據過濾資料的處理階段有這幾種不同類型:
  • Content Filter:在接受請求中,用來處理文件的資料。一般來說我們都式設計這類的過濾器居多,例如過濾HTML中特定的文字。
  • Protocol Filter:用來處理通訊協定(protocol)的資料。在Apache中,Protocol Filter用在將HTTP通訊協定轉換request_rec的資料結構。
  • Connection Filter:處理TCP連線的資料。用來處理conn_rec的資料結構,跟HTTP和request_recr皆無關係,你可以看成是操作在傳輸層(Transport Layer)的部分,而Content Filter和Protocol Filter是操作在應用層(Application Layer)。
過濾器依據放置的位置則有這幾種不同類型:
  • Input Filter:處理來自client請求(request)的資料,故稱為輸入過濾器(Input Filter)。
  • Output Filter:處理將回應(response)給client的資料,故稱為輸出過濾器(Output Filter)。
此外,過濾器也有點像掛勾的樣子,有著另一種資料型態來處理過濾器之間的傳遞,是要依靠ap_filter_t的資料結構



/**
* @brief The representation of a filter chain.
*
* Each request has a list
* of these structures which are called in turn to filter the data. Sub
* requests get an exact copy of the main requests filter chain.
*/
struct ap_filter_t {
/** The internal representation of this filter. This includes
* the filter's name, type, and the actual function pointer.
*/
ap_filter_rec_t *frec;

/** A place to store any data associated with the current filter */
void *ctx;

/** The next filter in the chain */
ap_filter_t *next;

/** The request_rec associated with the current filter. If a sub-request
* adds filters, then the sub-request is the request associated with the
* filter.
*/
request_rec *r;

/** The conn_rec associated with the current filter. This is analogous
* to the request_rec, except that it is used for input filtering.
*/
conn_rec *c;
};

如果需要在多個過濾器之間傳送資料,你就需要用ctx這個資料欄位。

2009年6月30日 星期二

Apache WinNT MPM多執行模組的運作方式

WinNT的MPM模組當中,使用一種稱為「I/O Completion Ports」的技術來處理各執行緒的請求分配,「I/O Completion Ports」中文稱為「I/O完全埠」、「I/O完成通訊埠」或「完成端口」等,也有簡稱IOCP

主要資料可以參考MSDN的兩個網址:




2009年6月22日 星期一

Apache MultiThread多執行緒寫法

在WIN32的Apache中,MPM模組(多進程並發處理模塊)使用多執行緒來處理Request,其中避免單一資源被多個執行緒搶奪,必須使用一些技巧,可以參考MSDN中的Synchronization Objects主題文章(http://msdn.microsoft.com/en-us/library/ms686364(VS.85).aspx),常用的Synchronization Object有下列幾種:Event、Mutex、Semaphore和Waitable Timer。利用Synchronization Objects可以被指定給其中之一的Wait Function,讓這些Thread可以等等,如此避掉單一資源被多個執行緒搶奪。

這些Object的特點如下:
除了這四個物件之外,其他可以用來同步執行緒的物件還有:Change notification、Console input、Job、Memory resource notification、Process、Thread等。

這裡還沒有提到一點,為了讓執行緒可以停下來等同步,我們必須使用Wait Function這個功能,Wait Function會在執行的時候block停止住,直到特定的條件(criteria)符合達成才會繼續執行下去,當然你也可以設定一段時間(time-out interval),當條件不符合時,進入等待的狀態,若時間超過則會繼續執行而不等待。


2009年6月12日 星期五

Apache Platform平台運作說明

當我在拆解Apache的同時,發現到一個不能忽略的問題,我們必須將視野提高到較高層次來觀看原始碼(source code),才不會見樹不見林,也較能對Apache的運作有深刻的體悟!樹、林是兩難。

Apache HTTP Server(簡稱Apache)通常在作業系統啟動的時候,就會開始在背後執行,成為 Linux中的Deamon,或是Windows中的Service,有一件事:Apache在啟動的時候,是比較耗費系統資源,所以通常是OS啟動後就Apache提供服務,不太像一般程式,你要用到才去呼叫。

Apache的程式當中分成兩個階段執行,一個是啟動階段(start-up phase),另一個是運行階段(operational pahse)。

啟動階段(start-up phase)的作用有:讀取組態檔(httpd.conf或是.htaccess);載入各個模組(module);初始化系統資源,包含log檔、共享記憶體、資料連結等。

啟動階段完成之後,進入運行階段(operational pahse),運行階段主要由MPM(Multi-Processing Module)模組接管控制,MPM會產生一個或多個的執行緒池(Thread Pool)或是行程(process),像Windows中只會有兩個process(即httpd.exe),其中之一是啟動階段的Master Process,另一個是運行階段的Child Process,由Child Process產生Thread Pool,此後由Thread Pool服務所有的Request請求。主要是因為Windows是支援Multi-Thread的作業系統。


2009年5月31日 星期日

Request Processing in Apache 2.0請求的處理過程

Apache中HTTP Request的程序主要是request.c中的函數來處理,這個函數是ap_process_request_internal,所有的請求都由它處理,包含子請求(subrequest)和轉向(redirect)。

其程式碼如下所示:


/* This is the master logic for processing requests. Do NOT duplicate
* this logic elsewhere, or the security model will be broken by future
* API changes. Each phase must be individually optimized to pick up
* redundant/duplicate calls by subrequests, and redirects.
*/
AP_DECLARE(int) ap_process_request_internal(request_rec *r)
{
int file_req = (r->main && r->filename);
int access_status;

/* Ignore embedded %2F's in path for proxy requests */
if (!r->proxyreq && r->parsed_uri.path) {
core_dir_config *d;
d = ap_get_module_config(r->per_dir_config, &core_module);
if (d->allow_encoded_slashes) {
access_status = ap_unescape_url_keep2f(r->parsed_uri.path);
}
else {
access_status = ap_unescape_url(r->parsed_uri.path);
}
if (access_status) {
if (access_status == HTTP_NOT_FOUND) {
if (! d->allow_encoded_slashes) {
ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
"found %%2f (encoded '/') in URI "
"(decoded='%s'), returning 404",
r->parsed_uri.path);
}
}
return access_status;
}
}

ap_getparents(r->uri); /* OK --- shrinking transformations... */

/* All file subrequests are a huge pain... they cannot bubble through the
* next several steps. Only file subrequests are allowed an empty uri,
* otherwise let translate_name kill the request.
*/
if (!file_req) {
if ((access_status = ap_location_walk(r))) {
return access_status;
}

if ((access_status = ap_run_translate_name(r))) {
return decl_die(access_status, "translate", r);
}
}

/* Reset to the server default config prior to running map_to_storage
*/
r->per_dir_config = r->server->lookup_defaults;

if ((access_status = ap_run_map_to_storage(r))) {
/* This request wasn't in storage (e.g. TRACE) */
return access_status;
}

/* Rerun the location walk, which overrides any map_to_storage config.
*/
if ((access_status = ap_location_walk(r))) {
return access_status;
}

/* Only on the main request! */
if (r->main == NULL) {
if ((access_status = ap_run_header_parser(r))) {
return access_status;
}
}

/* Skip authn/authz if the parent or prior request passed the authn/authz,
* and that configuration didn't change (this requires optimized _walk()
* functions in map_to_storage that use the same merge results given
* identical input.) If the config changes, we must re-auth.
*/
if (r->main && (r->main->per_dir_config == r->per_dir_config)) {
r->user = r->main->user;
r->ap_auth_type = r->main->ap_auth_type;
}
else if (r->prev && (r->prev->per_dir_config == r->per_dir_config)) {
r->user = r->prev->user;
r->ap_auth_type = r->prev->ap_auth_type;
}
else {
switch (ap_satisfies(r)) {
case SATISFY_ALL:
case SATISFY_NOSPEC:
if ((access_status = ap_run_access_checker(r)) != 0) {
return decl_die(access_status, "check access", r);
}

if (ap_some_auth_required(r)) {
if (((access_status = ap_run_check_user_id(r)) != 0)
|| !ap_auth_type(r)) {
return decl_die(access_status, ap_auth_type(r)
? "check user. No user file?"
: "perform authentication. AuthType not set!",
r);
}

if (((access_status = ap_run_auth_checker(r)) != 0)
|| !ap_auth_type(r)) {
return decl_die(access_status, ap_auth_type(r)
? "check access. No groups file?"
: "perform authentication. AuthType not set!",
r);
}
}
break;

case SATISFY_ANY:
if (((access_status = ap_run_access_checker(r)) != 0)) {
if (!ap_some_auth_required(r)) {
return decl_die(access_status, "check access", r);
}

if (((access_status = ap_run_check_user_id(r)) != 0)
|| !ap_auth_type(r)) {
return decl_die(access_status, ap_auth_type(r)
? "check user. No user file?"
: "perform authentication. AuthType not set!",
r);
}

if (((access_status = ap_run_auth_checker(r)) != 0)
|| !ap_auth_type(r)) {
return decl_die(access_status, ap_auth_type(r)
? "check access. No groups file?"
: "perform authentication. AuthType not set!",
r);
}
}
break;
}
}
/* XXX Must make certain the ap_run_type_checker short circuits mime
* in mod-proxy for r->proxyreq && r->parsed_uri.scheme
* && !strcmp(r->parsed_uri.scheme, "http")
*/
if ((access_status = ap_run_type_checker(r)) != 0) {
return decl_die(access_status, "find types", r);
}

if ((access_status = ap_run_fixups(r)) != 0) {
return access_status;
}

return OK;
}

2009年5月25日 星期一

Apache Portable Runtime可移植執行環境

Apache HTTP Server運作時需要依賴另一個程式庫,也就是APR,全名為「Apache Portable Runtime可移植執行環境」,這其實是Apache Software Foundation(ASF)底下另一個專案計畫,請參考http://apr.apache.org/

APR中有一項重要的程式庫模組,這個模組是APR Pools(apr_pools.h),這是APR和Apchee中管理資源的重要模組!其資料型態是apr_poot_t。在APR當中則是Memory Pool Functions這個模組裡面,原始碼是memory\apr_pools.c,他主要功能其實也就是記憶體管理!

其他定義如下(ver 1.3)
Defines
  • #define APR_POOL_DECLARE_ACCESSOR(type)
  • #define APR_POOL_IMPLEMENT_ACCESSOR(type)
  • #define APR_POOL_DEBUG 0
  • #define APR_POOL__FILE_LINE__ __FILE__ ":" APR_STRINGIFY(__LINE__)

Typedefs
  • typedef struct apr_pool_t apr_pool_t
  • typedef int(* apr_abortfunc_t )(int retcode)

Functions
  • apr_status_t apr_pool_initialize (void)
  • void apr_pool_terminate (void)
  • apr_status_t apr_pool_create_ex (apr_pool_t **newpool, apr_pool_t *parent, apr_abortfunc_t abort_fn, apr_allocator_t *allocator)
  • apr_status_t apr_pool_create_core_ex (apr_pool_t **newpool, apr_abortfunc_t abort_fn, apr_allocator_t *allocator)
  • apr_status_t apr_pool_create_unmanaged_ex (apr_pool_t **newpool, apr_abortfunc_t abort_fn, apr_allocator_t *allocator)
  • apr_status_t apr_pool_create_ex_debug (apr_pool_t **newpool, apr_pool_t *parent, apr_abortfunc_t abort_fn, apr_allocator_t *allocator, const char *file_line)
  • apr_status_t apr_pool_create_core_ex_debug (apr_pool_t **newpool, apr_abortfunc_t abort_fn, apr_allocator_t *allocator, const char *file_line)
  • apr_status_t apr_pool_create_unmanaged_ex_debug (apr_pool_t **newpool, apr_abortfunc_t abort_fn, apr_allocator_t *allocator, const char *file_line)
  • apr_status_t apr_pool_create (apr_pool_t **newpool, apr_pool_t *parent)
  • apr_status_t apr_pool_create_core (apr_pool_t **newpool)
  • apr_status_t apr_pool_create_unmanaged (apr_pool_t **newpool)
  • apr_allocator_t * apr_pool_allocator_get (apr_pool_t *pool)
  • void apr_pool_clear (apr_pool_t *p)
  • void apr_pool_clear_debug (apr_pool_t *p, const char *file_line)
  • void apr_pool_destroy (apr_pool_t *p)
  • void apr_pool_destroy_debug (apr_pool_t *p, const char *file_line)
  • void * apr_palloc (apr_pool_t *p, apr_size_t size)
  • void * apr_palloc_debug (apr_pool_t *p, apr_size_t size, const char *file_line)
  • void * apr_pcalloc (apr_pool_t *p, apr_size_t size)
  • void * apr_pcalloc_debug (apr_pool_t *p, apr_size_t size, const char *file_line)
  • void apr_pool_abort_set (apr_abortfunc_t abortfunc, apr_pool_t *pool)
  • apr_abortfunc_t apr_pool_abort_get (apr_pool_t *pool)
  • apr_pool_t * apr_pool_parent_get (apr_pool_t *pool)
  • int apr_pool_is_ancestor (apr_pool_t *a, apr_pool_t *b)
  • void apr_pool_tag (apr_pool_t *pool, const char *tag)
  • apr_status_t apr_pool_userdata_set (const void *data, const char *key, apr_status_t(*cleanup)(void *), apr_pool_t *pool)
  • apr_status_t apr_pool_userdata_setn (const void *data, const char *key, apr_status_t(*cleanup)(void *), apr_pool_t *pool)
  • apr_status_t apr_pool_userdata_get (void **data, const char *key, apr_pool_t *pool)

2009年5月24日 星期日

Request in Apache請求處理的流程

我們必須先知道一件事,使用者的瀏覽器(browser)向Apache伺服器請求資料時,必須先建立TPC連線,依照HTTP通訊協定的規範向Apache伺服器請求資料。也就是說,Aapche處理請求的流程可以分為:建立TPC連線之前、建立TPC連線之後(開始用HTTP),這兩個部分。

請求處理的流程
  1. 接收請求(Accept Request)
  2. 中繼資料處理(Metadata Processing),request會傳遞很多個掛勾(hook),呼叫所屬階段的程序(function)
  3. 產生回應內容(Content Generator)
  4. 記錄(Logging)
正常來說,大致上是依據這個流程,如果是錯誤(error)或是產生新請求,則有可能使得request導向其他程序,另外,每個程序也可以讓其他程序呼叫,簡言之,有點複雜!(應該要畫圖解釋...)

處理的流程當中,Apache提供掛勾(hook)這項功能,可讓我們開發應用模組(module)的時候,利用回呼(callback)的方式值型模組中的功能。掛勾的總類依照請求的先後順序為:
  1. ap_hook_post_read_request
  2. ap_hook_translate_name
  3. ap_hook_map_to_storage
  4. ap_hook_header_parser
  5. ap_hook_access_checker
  6. ap_hook_check_user_id
  7. ap_hook_auth_checker
  8. ap_hook_type_checker
  9. ap_hook_fixups
  10. ap_hook_handler
  11. ap_hook_log_transaction
最後,Apache預設處理請求的程式是掛在ap_hook_handler之中,其函數原形為static int default_handler(request_rec *r),位於server\core.c檔案當中。

2009年5月23日 星期六

Apache Core Objects主要物件

Apache程式碼定義了一些結構可以使用,其中有四個結構相當重要,會在開發應用程式模組中使用到,主要是定義在httpd.h這個標頭檔中,其結構名稱有:
  • request_rec每個請求的相關資訊
  • server_rec每個主機的相關資訊
  • conn_rec每次連線的相關資訊
  • process_rec每個程序的相關資訊
詳細程式碼如下:

struct request_rec {
    /** The pool associated with the request */
    apr_pool_t *pool;
    /** The connection to the client */
    conn_rec *connection;
    /** The virtual host for this request */
    server_rec *server;

    /** Pointer to the redirected request if this is an external redirect */
    request_rec *next;
    /** Pointer to the previous request if this is an internal redirect */
    request_rec *prev;

    /** Pointer to the main request if this is a sub-request
     * (see http_request.h) */
    request_rec *main;

    /* Info about the request itself... we begin with stuff that only
     * protocol.c should ever touch...
     */
    /** First line of request */
    char *the_request;
    /** HTTP/0.9, "simple" request (e.g. GET /foo\n w/no headers) */
    int assbackwards;
    /** A proxy request (calculated during post_read_request/translate_name)
     *  possible values PROXYREQ_NONE, PROXYREQ_PROXY, PROXYREQ_REVERSE,
     *                  PROXYREQ_RESPONSE
     */
    int proxyreq;
    /** HEAD request, as opposed to GET */
    int header_only;
    /** Protocol string, as given to us, or HTTP/0.9 */
    char *protocol;
    /** Protocol version number of protocol; 1.1 = 1001 */
    int proto_num;
    /** Host, as set by full URI or Host: */
    const char *hostname;

    /** Time when the request started */
    apr_time_t request_time;

    /** Status line, if set by script */
    const char *status_line;
    /** Status line */
    int status;

    /* Request method, two ways; also, protocol, etc..  Outside of protocol.c,
     * look, but don't touch.
     */

    /** Request method (eg. GET, HEAD, POST, etc.) */
    const char *method;
    /** M_GET, M_POST, etc. */
    int method_number;

    /**
     *  'allowed' is a bitvector of the allowed methods.
     *
     *  A handler must ensure that the request method is one that
     *  it is capable of handling.  Generally modules should DECLINE
     *  any request methods they do not handle.  Prior to aborting the
     *  handler like this the handler should set r->allowed to the list
     *  of methods that it is willing to handle.  This bitvector is used
     *  to construct the "Allow:" header required for OPTIONS requests,
     *  and HTTP_METHOD_NOT_ALLOWED and HTTP_NOT_IMPLEMENTED status codes.
     *
     *  Since the default_handler deals with OPTIONS, all modules can
     *  usually decline to deal with OPTIONS.  TRACE is always allowed,
     *  modules don't need to set it explicitly.
     *
     *  Since the default_handler will always handle a GET, a
     *  module which does *not* implement GET should probably return
     *  HTTP_METHOD_NOT_ALLOWED.  Unfortunately this means that a Script GET
     *  handler can't be installed by mod_actions.
     */
    apr_int64_t allowed;
    /** Array of extension methods */
    apr_array_header_t *allowed_xmethods; 
    /** List of allowed methods */
    ap_method_list_t *allowed_methods; 

    /** byte count in stream is for body */
    apr_off_t sent_bodyct;
    /** body byte count, for easy access */
    apr_off_t bytes_sent;
    /** Last modified time of the requested resource */
    apr_time_t mtime;

    /* HTTP/1.1 connection-level features */

    /** sending chunked transfer-coding */
    int chunked;
    /** The Range: header */
    const char *range;
    /** The "real" content length */
    apr_off_t clength;

    /** Remaining bytes left to read from the request body */
    apr_off_t remaining;
    /** Number of bytes that have been read  from the request body */
    apr_off_t read_length;
    /** Method for reading the request body
     * (eg. REQUEST_CHUNKED_ERROR, REQUEST_NO_BODY,
     *  REQUEST_CHUNKED_DECHUNK, etc...) */
    int read_body;
    /** reading chunked transfer-coding */
    int read_chunked;
    /** is client waiting for a 100 response? */
    unsigned expecting_100;

    /* MIME header environments, in and out.  Also, an array containing
     * environment variables to be passed to subprocesses, so people can
     * write modules to add to that environment.
     *
     * The difference between headers_out and err_headers_out is that the
     * latter are printed even on error, and persist across internal redirects
     * (so the headers printed for ErrorDocument handlers will have them).
     *
     * The 'notes' apr_table_t is for notes from one module to another, with no
     * other set purpose in mind...
     */

    /** MIME header environment from the request */
    apr_table_t *headers_in;
    /** MIME header environment for the response */
    apr_table_t *headers_out;
    /** MIME header environment for the response, printed even on errors and
     * persist across internal redirects */
    apr_table_t *err_headers_out;
    /** Array of environment variables to be used for sub processes */
    apr_table_t *subprocess_env;
    /** Notes from one module to another */
    apr_table_t *notes;

    /* content_type, handler, content_encoding, and all content_languages 
     * MUST be lowercased strings.  They may be pointers to static strings;
     * they should not be modified in place.
     */
    /** The content-type for the current request */
    const char *content_type; /* Break these out --- we dispatch on 'em */
    /** The handler string that we use to call a handler function */
    const char *handler; /* What we *really* dispatch on */

    /** How to encode the data */
    const char *content_encoding;
    /** Array of strings representing the content languages */
    apr_array_header_t *content_languages;

    /** variant list validator (if negotiated) */
    char *vlist_validator;
    
    /** If an authentication check was made, this gets set to the user name. */
    char *user;
    /** If an authentication check was made, this gets set to the auth type. */
    char *ap_auth_type;

    /** This response can not be cached */
    int no_cache;
    /** There is no local copy of this response */
    int no_local_copy;

    /* What object is being requested (either directly, or via include
     * or content-negotiation mapping).
     */

    /** The URI without any parsing performed */
    char *unparsed_uri;
    /** The path portion of the URI */
    char *uri;
    /** The filename on disk corresponding to this response */
    char *filename;
    /* XXX: What does this mean? Please define "canonicalize" -aaron */
    /** The true filename, we canonicalize r->filename if these don't match */
    char *canonical_filename;
    /** The PATH_INFO extracted from this request */
    char *path_info;
    /** The QUERY_ARGS extracted from this request */
    char *args;
    /**  finfo.protection (st_mode) set to zero if no such file */
    apr_finfo_t finfo;
    /** A struct containing the components of URI */
    apr_uri_t parsed_uri;

    /**
     * Flag for the handler to accept or reject path_info on 
     * the current request.  All modules should respect the
     * AP_REQ_ACCEPT_PATH_INFO and AP_REQ_REJECT_PATH_INFO 
     * values, while AP_REQ_DEFAULT_PATH_INFO indicates they
     * may follow existing conventions.  This is set to the
     * user's preference upon HOOK_VERY_FIRST of the fixups.
     */
    int used_path_info;

    /* Various other config info which may change with .htaccess files
     * These are config vectors, with one void* pointer for each module
     * (the thing pointed to being the module's business).
     */

    /** Options set in config files, etc. */
    struct ap_conf_vector_t *per_dir_config;
    /** Notes on *this* request */
    struct ap_conf_vector_t *request_config;

    /**
     * A linked list of the .htaccess configuration directives
     * accessed by this request.
     * N.B. always add to the head of the list, _never_ to the end.
     * that way, a sub request's list can (temporarily) point to a parent's list
     */
    const struct htaccess_result *htaccess;

    /** A list of output filters to be used for this request */
    struct ap_filter_t *output_filters;
    /** A list of input filters to be used for this request */
    struct ap_filter_t *input_filters;

    /** A list of protocol level output filters to be used for this
     *  request */
    struct ap_filter_t *proto_output_filters;
    /** A list of protocol level input filters to be used for this
     *  request */
    struct ap_filter_t *proto_input_filters;

    /** A flag to determine if the eos bucket has been sent yet */
    int eos_sent;

/* Things placed at the end of the record to avoid breaking binary
 * compatibility.  It would be nice to remember to reorder the entire
 * record to improve 64bit alignment the next time we need to break
 * binary compatibility for some other reason.
 */
};

struct server_rec {
    /** The process this server is running in */這個伺服器正在執行的行程,也許是虛擬伺服器
    process_rec *process;
    /** The next server in the list */位於清單中,下一個伺服器組態
    server_rec *next;

    /** The name of the server */這個伺服器的名子
    const char *defn_name;
    /** The line of the config file that the server was defined on */組態檔httpd.conf中,定義伺服器的行號
    unsigned defn_line_number;

    /* Contact information */

    /** The admin's contact information */管理員的聯絡資訊(電子信箱)
    char *server_admin;
    /** The server hostname */這個伺服器的主機名稱
    char *server_hostname;
    /** for redirects, etc. */用於重新導向,埠號
    apr_port_t port;

    /* Log files --- note that transfer log is now in the modules... */

    /** The name of the error log */錯誤記錄檔的名稱
    char *error_fname;
    /** A file descriptor that references the error log */指標,指向錯誤記錄檔
    apr_file_t *error_log;
    /** The log level for this server */記錄檔記錄的層次
    int loglevel;

    /* Module-specific configuration for server, and defaults... */

    /** true if this is the virtual server */是否是虛擬伺服器
    int is_virtual;
    /** Config vector containing pointers to modules' per-server config 
     *  structures. */指向伺服器組態的向量
    struct ap_conf_vector_t *module_config; 
    /** MIME type info, etc., before we start checking per-directory info */MIME型態資訊
    struct ap_conf_vector_t *lookup_defaults;

    /* Transaction handling */

    /** I haven't got a clue */還不知道這是什麼!
    server_addr_rec *addrs;
    /** Timeout, as an apr interval, before we give up */逾時時間
    apr_interval_time_t timeout;
    /** The apr interval we will wait for another request */持續連線的逾時時間
    apr_interval_time_t keep_alive_timeout;
    /** Maximum requests per connection */每個連線的最大請求數目
    int keep_alive_max;
    /** Use persistent connections? */是否使用http的持續連線
    int keep_alive;

    /** Pathname for ServerPath */伺服器路徑的名稱
    const char *path;
    /** Length of path */路徑長度
    int pathlen;

    /** Normal names for ServerAlias servers */別名伺服器的正常名稱
    apr_array_header_t *names;
    /** Wildcarded names for ServerAlias servers */別名伺服器的萬用名稱
    apr_array_header_t *wild_names;

    /** limit on size of the HTTP request line    */請求的行數限制
    int limit_req_line;
    /** limit on size of any request header field */請求標頭欄位大小的限制
    int limit_req_fieldsize;
    /** limit on number of request header fields  */請求標頭欄位數目的限制
    int limit_req_fields; 

    /** The server request scheme for redirect responses */重新導向的請求方法
    const char *server_scheme;
};

struct conn_rec {
    /** Pool associated with this connection */
    apr_pool_t *pool;
    /** Physical vhost this conn came in on */
    server_rec *base_server;
    /** used by http_vhost.c */
    void *vhost_lookup_data;

    /* Information about the connection itself */
    /** local address */
    apr_sockaddr_t *local_addr;
    /** remote address */
    apr_sockaddr_t *remote_addr;

    /** Client's IP address */
    char *remote_ip;
    /** Client's DNS name, if known.  NULL if DNS hasn't been checked,
     *  "" if it has and no address was found.  N.B. Only access this though
     * get_remote_host() */
    char *remote_host;
    /** Only ever set if doing rfc1413 lookups.  N.B. Only access this through
     *  get_remote_logname() */
    char *remote_logname;

    /** Are we still talking? */
    unsigned aborted:1;

    /** Are we going to keep the connection alive for another request?
     * @see ap_conn_keepalive_e */
    ap_conn_keepalive_e keepalive;

    /** have we done double-reverse DNS? -1 yes/failure, 0 not yet, 
     *  1 yes/success */
    signed int double_reverse:2;

    /** How many times have we used it? */
    int keepalives;
    /** server IP address */
    char *local_ip;
    /** used for ap_get_server_name when UseCanonicalName is set to DNS
     *  (ignores setting of HostnameLookups) */
    char *local_host;

    /** ID of this connection; unique at any point in time */
    long id; 
    /** Config vector containing pointers to connections per-server
     *  config structures. */
    struct ap_conf_vector_t *conn_config;
    /** Notes on *this* connection: send note from one module to
     *  another. must remain valid for all requests on this conn */
    apr_table_t *notes;
    /** A list of input filters to be used for this connection */
    struct ap_filter_t *input_filters;
    /** A list of output filters to be used for this connection */
    struct ap_filter_t *output_filters;
    /** handle to scoreboard information for this connection */
    void *sbh;
    /** The bucket allocator to use for all bucket/brigade creations */
    struct apr_bucket_alloc_t *bucket_alloc;
    /** The current state of this connection */
    conn_state_t *cs;
    /** Is there data pending in the input filters? */ 
    int data_in_input_filters;
    
    /** Are there any filters that clogg/buffer the input stream, breaking
     *  the event mpm.
     */
    int clogging_input_filters;
};

struct process_rec {
    /** Global pool. Cleared upon normal exit */
    apr_pool_t *pool;
    /** Configuration pool. Cleared upon restart */
    apr_pool_t *pconf;
    /** Number of command line arguments passed to the program */
    int argc;
    /** The command line arguments */
    const char * const *argv;
    /** The program name used to execute the program */
    const char *short_name;
};

Apache Multi-Processing Modules多行程模組

MPM是Apache中的一個模組,全名為Multi-Processing Module多行程模組,這個模組是介於APR和底層的作業系統(Operation System, OS)的一個模組,其目的是用來最佳化,使得Apache在各式的OS上能有傑出的效能表現。

MPM本身是系統層級(system-level)的模組,意思就是說,開發上和其他模組會不一樣,哪裡不一樣?目前還在研究當中。不過,我們大多數的應用只會按照一般模組的樣子來開發,絕大多數都是這種開發方式(即非系統層級)。

早期Apache發展在UNIX之類的作業系統上,這類系統多為多處理器的伺服器,而作業系統會依照請求(request)分岔(fork)產生其他行程(process)來處理,一般來說,Apache啟動的時候,會產生一個集散區(pool,也有稱為"池")來管理這些行程。之後2.0版本,為了能夠跨平台(cross-platform)的高效率、最佳化運作,所以才設計出MPM這個模組。

實務應用上來說,只有UNIX之類的作業系統有較多的設定可供選擇使用。我目前是以windows開發,真的選項就只有兩個可以設定:MaxRequestsPerChildThreadsPerChild兩個指令。其他指令請參考http://httpd.apache.org/docs/2.2/mod/mpm_common.html

在MPM這個部分當中,因為跟底層OS有密切關係,其實MPM有好幾個類別,有些是給UNIX用的,有些是給Windows(WIN32)用的,有些則給其他OS用的,所以再看這些指令的時候,必須注意它所依賴的模組,否則社定會失敗。另一個問題是,我們可以選擇使用哪個MPM嗎?應該是不行,除非你自己重新complie一次,MPM的設定在編譯Apache時就已經決定了!

以UNIX這群的MPM來說,有Prefork MPM、Worker MPM以及正在試驗的Event MPM。
  • Prefork MPM是非執行緒的架構,和以往1版的類似。
  • Worker MPM是多執行緒的架構,其執行緒和每個請求連線有關。
  • Event MPM是正在試驗當中,將執行緒與請求連線的關係解耦合,可以避免請求連線超出執行緒的問題。
結論:開發Apache的模組、應用程式來說,不需要理會MPM,請忽略MPM這個模組!

我目前以windows開發,所以主要是專注於mpm_winnt,其指令Directives有
  • CoreDumpDirectory
  • Listen
  • ListenBacklog
  • MaxMemFree
  • MaxRequestsPerChild
  • PidFile
  • ReceiveBufferSize
  • ScoreBoardFile
  • SendBufferSize
  • ThreadLimit
  • ThreadsPerChild
  • ThreadStackSize
  • Win32DisableAcceptEx

2009年5月22日 星期五

Deconstruction of Apache Code解構阿帕契程式碼

太久,真的是一個月沒有更新部落格。忙著,也跟著茫了。

目前正在使用Apache Http Server的程式撰寫。我想之後會寫有關於Apache的程式碼內容,希望有這個能力和空閒時間。(忙著活下去,還有時間嗎!好問題~)

先講參考書籍,討論Apache的書籍很少(手指頭的數目之內),中文可以參考下面這本:
Ben Laurie & Peter Laurie原著,郭文生編譯,Apache技術手冊(第三版),台北:歐萊禮,2003。

怎麼開始呢?Deconstruction,解構。應該不稱之為解構主義,一方面我現在不了解何謂解構主義,只是想將Apache的Code猜(拆)解開來看看,這套軟體的運作方式?我們有沒有能力做出這樣的軟體呢?需要哪些能力和人力?如何設計更是大問題!(我的疑問)

Apache的進入點是main.c,在httpd這個專案(Project)裡面,程式碼架構如下:

用到的標頭檔,Apache底層是Apache Portability Runtime(APR),因此會引入許多apr_的header file,而基於APR建置的程式庫則有APR-util,簡稱APU,以及實現iconv()的APR-iconv。另外,http_是關於http protocol的一些處理,也需要因引入。

#include "apr.h" //平台定義
#include "apr_strings.h" //字串處理程式庫
#include "apr_getopt.h" //命令參數
#include "apr_general.h" //混雜的程式庫,未歸類的
#include "apr_lib.h" //通用程式庫
#include "apr_md5.h" //md5的程式庫,屬於APU
#include "apr_time.h" //時間程式庫
#include "apr_version.h" //APR的版本介面
#include "apu_version.h" //APU的版本介面

#define APR_WANT_STDIO
#define APR_WANT_STRFUNC
#include "apr_want.h" //APR對於標準標頭檔支援

#define CORE_PRIVATE
#include "ap_config.h" //定義掛勾hook的標頭檔
#include "httpd.h" //主要基本的定義
#include "http_main.h" //main程式的定義
#include "http_log.h" //記錄檔的定義
#include "http_config.h" //一些設定的定義
#include "http_core.h" //核心模組的定義
#include "http_vhost.h" //虛擬主機的定義
#include "apr_uri.h" //uri的程式庫,屬於APU
#include "util_ebcdic.h" //定義Extended Binary Coded Decimal Interchange Code(EBCDIC)的轉換功能
#include "ap_mpm.h" //定義Multi-Processing Module(MPM),多處理模組
#include "mpm_common.h" //MPM用的程式庫

定義到的函數(function):
static void show_mpm_settings(void)
static void show_compile_settings(void)
static void destroy_and_exit_process(process_rec *process, int process_exit_value)
static process_rec *init_process(int *argc, const char * const * *argv)
static void usage(process_rec *process)

主程式碼:


int main(int argc, const char * const argv[])
{
char c;
int configtestonly = 0;
const char *confname = SERVER_CONFIG_FILE;
const char *def_server_root = HTTPD_ROOT;
const char *temp_error_log = NULL;
const char *error;
process_rec *process;
server_rec *server_conf;
apr_pool_t *pglobal;
apr_pool_t *pconf;
apr_pool_t *plog; /* Pool of log streams, reset _after_ each read of conf */
apr_pool_t *ptemp; /* Pool for temporary config stuff, reset often */
apr_pool_t *pcommands; /* Pool for -D, -C and -c switches */
apr_getopt_t *opt;
apr_status_t rv;
module **mod;
const char *optarg;
APR_OPTIONAL_FN_TYPE(ap_signal_server) *signal_server;

AP_MONCONTROL(0); /* turn off profiling of startup */

process = init_process(&argc, &argv);
pglobal = process->pool;
pconf = process->pconf;
ap_server_argv0 = process->short_name;

#if APR_CHARSET_EBCDIC
if (ap_init_ebcdic(pglobal) != APR_SUCCESS) {
destroy_and_exit_process(process, 1);
}
#endif

apr_pool_create(&pcommands, pglobal);
apr_pool_tag(pcommands, "pcommands");
ap_server_pre_read_config = apr_array_make(pcommands, 1, sizeof(char *));
ap_server_post_read_config = apr_array_make(pcommands, 1, sizeof(char *));
ap_server_config_defines = apr_array_make(pcommands, 1, sizeof(char *));

error = ap_setup_prelinked_modules(process);
if (error) {
ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_EMERG, 0, NULL, "%s: %s",
ap_server_argv0, error);
destroy_and_exit_process(process, 1);
}

ap_run_rewrite_args(process);

/* Maintain AP_SERVER_BASEARGS list in http_main.h to allow the MPM
* to safely pass on our args from its rewrite_args() handler.
*/
apr_getopt_init(&opt, pcommands, process->argc, process->argv);

while ((rv = apr_getopt(opt, AP_SERVER_BASEARGS, &c, &optarg))
== APR_SUCCESS) {
char **new;

switch (c) {
case 'c':
new = (char **)apr_array_push(ap_server_post_read_config);
*new = apr_pstrdup(pcommands, optarg);
break;

case 'C':
new = (char **)apr_array_push(ap_server_pre_read_config);
*new = apr_pstrdup(pcommands, optarg);
break;

case 'd':
def_server_root = optarg;
break;

case 'D':
new = (char **)apr_array_push(ap_server_config_defines);
*new = apr_pstrdup(pcommands, optarg);
/* Setting -D DUMP_VHOSTS is equivalent to setting -S */
if (strcmp(optarg, "DUMP_VHOSTS") == 0)
configtestonly = 1;
/* Setting -D DUMP_MODULES is equivalent to setting -M */
if (strcmp(optarg, "DUMP_MODULES") == 0)
configtestonly = 1;
break;

case 'e':
if (strcasecmp(optarg, "emerg") == 0) {
ap_default_loglevel = APLOG_EMERG;
}
else if (strcasecmp(optarg, "alert") == 0) {
ap_default_loglevel = APLOG_ALERT;
}
else if (strcasecmp(optarg, "crit") == 0) {
ap_default_loglevel = APLOG_CRIT;
}
else if (strncasecmp(optarg, "err", 3) == 0) {
ap_default_loglevel = APLOG_ERR;
}
else if (strncasecmp(optarg, "warn", 4) == 0) {
ap_default_loglevel = APLOG_WARNING;
}
else if (strcasecmp(optarg, "notice") == 0) {
ap_default_loglevel = APLOG_NOTICE;
}
else if (strcasecmp(optarg, "info") == 0) {
ap_default_loglevel = APLOG_INFO;
}
else if (strcasecmp(optarg, "debug") == 0) {
ap_default_loglevel = APLOG_DEBUG;
}
else {
usage(process);
}
break;

case 'E':
temp_error_log = apr_pstrdup(process->pool, optarg);
break;

case 'X':
new = (char **)apr_array_push(ap_server_config_defines);
*new = "DEBUG";
break;

case 'f':
confname = optarg;
break;

case 'v':
printf("Server version: %s\n", ap_get_server_description());
printf("Server built: %s\n", ap_get_server_built());
destroy_and_exit_process(process, 0);

case 'V':
show_compile_settings();
destroy_and_exit_process(process, 0);

case 'l':
ap_show_modules();
destroy_and_exit_process(process, 0);

case 'L':
ap_show_directives();
destroy_and_exit_process(process, 0);

case 't':
configtestonly = 1;
break;

case 'S':
configtestonly = 1;
new = (char **)apr_array_push(ap_server_config_defines);
*new = "DUMP_VHOSTS";
break;

case 'M':
configtestonly = 1;
new = (char **)apr_array_push(ap_server_config_defines);
*new = "DUMP_MODULES";
break;

case 'h':
case '?':
usage(process);
}
}

/* bad cmdline option? then we die */
if (rv != APR_EOF || opt->ind < opt->argc) {
usage(process);
}

apr_pool_create(&plog, pglobal);
apr_pool_tag(plog, "plog");
apr_pool_create(&ptemp, pconf);
apr_pool_tag(ptemp, "ptemp");

/* Note that we preflight the config file once
* before reading it _again_ in the main loop.
* This allows things, log files configuration
* for example, to settle down.
*/

ap_server_root = def_server_root;
if (temp_error_log) {
ap_replace_stderr_log(process->pool, temp_error_log);
}
server_conf = ap_read_config(process, ptemp, confname, &ap_conftree);
if (!server_conf) {
destroy_and_exit_process(process, 1);
}

if (ap_run_pre_config(pconf, plog, ptemp) != OK) {
ap_log_error(APLOG_MARK, APLOG_STARTUP |APLOG_ERR, 0,
NULL, "Pre-configuration failed");
destroy_and_exit_process(process, 1);
}

rv = ap_process_config_tree(server_conf, ap_conftree,
process->pconf, ptemp);
if (rv == OK) {
ap_fixup_virtual_hosts(pconf, server_conf);
ap_fini_vhost_config(pconf, server_conf);
apr_hook_sort_all();

if (configtestonly) {
ap_run_test_config(pconf, server_conf);
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, "Syntax OK");
destroy_and_exit_process(process, 0);
}
}

signal_server = APR_RETRIEVE_OPTIONAL_FN(ap_signal_server);
if (signal_server) {
int exit_status;

if (signal_server(&exit_status, pconf) != 0) {
destroy_and_exit_process(process, exit_status);
}
}

/* If our config failed, deal with that here. */
if (rv != OK) {
destroy_and_exit_process(process, 1);
}

apr_pool_clear(plog);

if ( ap_run_open_logs(pconf, plog, ptemp, server_conf) != OK) {
ap_log_error(APLOG_MARK, APLOG_STARTUP |APLOG_ERR,
0, NULL, "Unable to open logs");
destroy_and_exit_process(process, 1);
}

if ( ap_run_post_config(pconf, plog, ptemp, server_conf) != OK) {
ap_log_error(APLOG_MARK, APLOG_STARTUP |APLOG_ERR, 0,
NULL, "Configuration Failed");
destroy_and_exit_process(process, 1);
}

apr_pool_destroy(ptemp);

for (;;) {
apr_hook_deregister_all();
apr_pool_clear(pconf);

for (mod = ap_prelinked_modules; *mod != NULL; mod++) {
ap_register_hooks(*mod, pconf);
}

/* This is a hack until we finish the code so that it only reads
* the config file once and just operates on the tree already in
* memory. rbb
*/
ap_conftree = NULL;
apr_pool_create(&ptemp, pconf);
apr_pool_tag(ptemp, "ptemp");
ap_server_root = def_server_root;
server_conf = ap_read_config(process, ptemp, confname, &ap_conftree);
if (!server_conf) {
destroy_and_exit_process(process, 1);
}

if (ap_run_pre_config(pconf, plog, ptemp) != OK) {
ap_log_error(APLOG_MARK, APLOG_STARTUP |APLOG_ERR,
0, NULL, "Pre-configuration failed");
destroy_and_exit_process(process, 1);
}

if (ap_process_config_tree(server_conf, ap_conftree, process->pconf,
ptemp) != OK) {
destroy_and_exit_process(process, 1);
}
ap_fixup_virtual_hosts(pconf, server_conf);
ap_fini_vhost_config(pconf, server_conf);
apr_hook_sort_all();
apr_pool_clear(plog);
if (ap_run_open_logs(pconf, plog, ptemp, server_conf) != OK) {
ap_log_error(APLOG_MARK, APLOG_STARTUP |APLOG_ERR,
0, NULL, "Unable to open logs");
destroy_and_exit_process(process, 1);
}

if (ap_run_post_config(pconf, plog, ptemp, server_conf) != OK) {
ap_log_error(APLOG_MARK, APLOG_STARTUP |APLOG_ERR,
0, NULL, "Configuration Failed");
destroy_and_exit_process(process, 1);
}

apr_pool_destroy(ptemp);
apr_pool_lock(pconf, 1);

ap_run_optional_fn_retrieve();

if (ap_mpm_run(pconf, plog, server_conf))
break;

apr_pool_lock(pconf, 0);
}

apr_pool_lock(pconf, 0);
destroy_and_exit_process(process, 0);

return 0; /* Termination 'ok' */
}