4.4连接(connection)处理器
连接处理器处理连接到服务器的TCP连接。不同于HTTP处理器,连接处理器接收connection对象做参数。连接处理器可以用于实现协议。如下例配置:
PythonConnectionHandler echo
实现文件echo.py:
from mod_python import apache
def connectionhandler(conn):
while 1:
conn.write(conn.readline())
return apache.OK
4.5apache-访问Apache内部
apache内部对Python的接口也恰好叫做apache,在mod_python包。提供了连接apache内部的重要功能,比如有用的函数,文档等(request对象也提供访问Apache内部的接口,但不在本节)。
apache模块仅可作为mod_python下的一个脚本来导入,因为它依赖于mod_python内建的_apache模块。最好按照如下导入:
from mod_python import apache
mod_python.apache模块定义了如下函数和对象,更多深入的信息查看Apache文档。
4.5.1函数
log_error(message[,level,server])
Apache函数ap_log_error()的接口,message是错误信息,level是如下值:
APLOG_EMERG
APLOG_ALERT
APLOG_CRIT
APLOG_ERR
APLOG_WARNING
APLOG_NOTICE
APLOG_INFO
APLOG_DEBUG
APLOG_NOERRNO
server是req.server对象的引用。如果没有指定则写入到缺省的日志,否则写入到对应虚拟服务器的日志中。当server没有指定时,日志级别也无效,日志级别是httpd在编译时指定的,经常为warn。
如果拥有请求对象的引用,最好用req.log_error,这样将会存入请求相关信息,如源IP等。
import_module(module_name[,autoreload=1,log=0,path=None])
mod_python的内部高级特性,用于在模块改变时自动重新载入模块。
module_name是模块名,可以包含点的包名。
autoreload标志查看包是否有所改变,如果改变则自动重新载入。
如果log为True则这个事件会记入日志。
path严格指定模块的位置。
例子:
from mod_python import apache
mymodule=apache.import_module('mymodule',log=1)
allow_methods([*args])
用于设置req.allowed。req.allowed是多个标志位的叠加,对应'Allow:'头。可以在返回HTTP_NOT_IMPLEMENTED错误之前设置。参数如下:
M_GET
M_PUT
M_POST
M_DELETE
M_CONNECT
M_OPTIONS
M_TRACE
M_PATCH
M_PROPFIND
M_PROPPATCH
M_MKCOL
M_COPY
M_MOVE
M_LOCK
M_UNLOCK
M_VERSION_CONTROL
M_CHECKOUT
M_UNCHECKOUT
M_CHECKIN
M_UPDATE
M_LABEL
M_REPORT
M_MKWORKSPACE
M_MKACTIVITY
M_BASELINE_CONTROL
M_MERGE
M_INVALID
exists_config_define(name)
确定Apache是否存在一个name配置。比如Apache定义了-DFOOBAR则如下测试为真:
apache.exists_config_define('FOOBAR')
register_cleanup(handler[,data])
注册一个清除行为,等同于req.register_cleanup()或reg.server.register_cleanup(),除非服务器或请求对象不需要。
config_tree()
返回服务器级(server-level)配置树。这些配置不包含.htaccess文件的标志。返回的是副本,修改对配置没有效果。
server_root()
返回配置标志'ServerRoot'的值。
make_table()
一个作废的函数,可用table代替。
mpm_query(code)
允许查询MPM参数变量来处理线程。返回值是如下三种常量之一:
AP_MPMQ_NOT_SUPPORTED=0
指MPM支持线程或子进程
AP_MPMQ_STATIC=1
指MPM正在使用静态守护线程
AP_MPMQ_DYNAMIC=2
指MPM正在使用动态守护线程
code参数是如下值:
AP_MPMQ_MAX_DAEMON_Used=1 最大允许使用的守护线程数量
AP_MPMQ_IS_THREADED=2 MPM是否允许使用线程
AP_MPMQ_IS_FORKED=3 MPM是否可用fork生成子进程
AP_MPMQ_HARD_LIMIT_DAEMONS=4 编译时允许的最大守护进程数量
AP_MPMQ_HARD_LIMIT_THREADS=5 编译时允许最大线程数量
AP_MPMQ_MAX_THREADS=6 threads/child配置允许的最大线程数量
AP_MPMQ_MIN_SPARE_DAEMONS=7 最小剩余守护数
AP_MPMQ_MIN_SPARE_THREADS=8 最小剩余线程数
AP_MPMQ_MAX_SPARE_DAEMONS=9 最大剩余守护数
AP_MPMQ_MAX_SPARE_THREADS=10 最大剩余线程数
AP_MPMQ_MAX_REQUESTS_DAEMON=11每个守护最大允许请求数量
AP_MPMQ_MAX_DAEMONS=12 配置允许的最大守护数量
例如:
if apache.mpm_query(apache.AP_MPMQ_IS_THREADED):
# do something
else:
# do something else
4.5.2表格对象(mp_table)
class table([mapping-or-sequence])
返回一个新的mp_table表格对象。mapping-or-sequence提供了表格的初始化数据。表格对象是对APR表格对象的包装(wrapper)。表格对象的行为(behave)非常像词典(还支持Python2.2以后的in操作符),但是有以下不同:
键和值都必须是字符串
键的查询不区分大小写
允许相同的键,即一个键对应一个列表的值
很多apache的信息存储在表格中,如req.headers_in和req.headers_out。mod_python提供的所有表格对象都是真正(actual)映射(mapping)到apache结构的,所以改变表格的值也会改变apache的表格。
除了(in addition to)像词典一样的行为(behavior)之外,表格对象还支持如下操作:
add(key,val)
这个方法允许使用相同的键,这对重复的头很有用,比如"Set-Cookie:"就需要。这个功能从3.0开始提供。
4.5.3请求对象
请求对象是映射到apache的request_rec结构的对象。当处理器被调用时,会传递唯一个的一个参数就是请求对象。可以为请求对象指定属性,用于在处理器之间通信。如下是方法:
add_common_vars()
间接调用ap_add_common_vars()函数。调用后,req.subprocess_env会包含大量的CGI信息。
add_handler(htype,handler[,dir])
允许动态注册处理器。htype是要添加的处理器的标志,如'PythonHandler',但不可以是过滤器(filter)或连接(connection)。handler是包含模块名或函数名的处理器函数。可选参数dir是需要添加到pythonpath环境变量的路径。如果未指定目录,而且有同类型的处理器,则继承路径,否则用前一路径。如果有PythonPath标志存在,则sys.path将会设置为它。
通过这种方式添加的处理器生存期为这个请求。为同一个类型添加多个处理器是很有用的,不过要注意避免死循环(infinite loop)。
动态注册处理器是一种很有用的技术,比如用于PythonAuthenHandler,可以为不同的认证级别指定不同的权限。如:
if manager:
req.add_handler("PythonHandler","menu::admin")
else:
req.add_handler("PythonHandler","menu::basic")
注意,如果传递了一个无效处理器,则会在寻找处理器时发生异常。
allow_methods(methods[,reset])
添加方法到req.allowed_methods列表。这个列表将会允许传递,在头部指定HTTP_METHOD_NOT_ALLOWED或HTTP_NOT_IMPLEMENTED返回到客户端。注意apache并不会对这些方法起作用。这个列表仅仅用于构造头部。实际的方法处理逻辑在处理器代码中提供。
methods是一个字符串列表,如果reset设置为1,则列表会被清空。
document_root()
返回DocumentRoot设置
get_basic_auth_pw()
返回简单认证时的密码字符串
get_config()
返回包含mod_python配置的表格对象的引用,用于当前请求,除了Python*Handler和PythonOption(可以通过req.get_options()获得)。表格包含键,和值列表。
get_remote_host([type,str_is_ip])
用于查询客户端的DNS名和IP地址,首次调用时查询DNS,其后的查询返回缓存数据。
可选参数type可为如下值:
apache.REMOTE_HOST:查询DNS名,当apache标志hostnameLookups为off时返回None,无法查询。
apache.REMOTE_NAME:缺省值,尽可能返回DNS名,否则返回IP地址字符串。
apache.REMOTE_NOLOOKUP:不执行DNS查询,直接返回IP地址。如果曾经执行过查询,则返回缓存的机器名。
apache.REMOTE_DOUBLE_REV:强制使用double-reverse查询,失败返回None。
如果str_is_ip设为None或未指定,则返回值为DNS名或IP地址的字符串。如果str_is_ip不为None,则返回一个(address,str_is_ip)元组。当str_is_ip为非零则address为IP地址字符串。失败返回None。
get_options()
返回PythonOptions标志的选项表格的引用。
internal_redirect(new_uri)
对请求进行内部重定向。new_uri是字符串。内部重定向将会创建一个新的请求对象,并执行所有的阶段。req.prev包含重定向之前的地址。
log_error(message[,level])
对apache函数ap_log_error()函数的接口。message是日志信息,level是日志级别标志,可为如下值:
APLOG_EMERG
APLOG_ALERT
APLOG_CRIT
APLOG_ERR
APLOG_WARNNING
APLOG_NOTICE
APLOG_INFO
APLOG_DEBUG
APLOG_NOERRNO
如果需要写入日志而不是通过请求对象,可用apache.log_error函数。
meets_conditions()
调用apache函数ap_meets_conditions()返回状态码。如果status是apache.OK,则响应正确。如果不是则简单的返回状态码status。注意req.headers_out将会被优先(prior)设置,并也会影响req.status的值,假如不是返回apache.OK。
例如:
...
r.headers_out['ETag']="1130794f-3774-4584-a4ea-0ab19e684268"
r.headers_out['Last-Modified']='Wed, 23 Feb 2005 00:00:00 GMT'
r.headers_out['Expires']='Mon, 18 Apr 2005 17:30:00 GMT'
status=r.meets_conditons()
if status!=apache.OK:
return status
... 处理响应内容 ...
requires()
返回包含require标志参数的元组。例如如下apache配置:
AuthType Basic
require user joe
require valid-user
函数将会返回('user joe','valid-user')
read([len])
从客户端读取最多len字节的数据,返回字符串数据。如果len为负数(negative)或者缺省(omitted),则读取所有的数据。这个函数也会受到apache配置标志Timeout的影响,如果读取时超时则会终端,并抛出IOError异常。
这个函数依赖于(rely的复数relies)客户端提供的Content-length头。如果未提供这个头,则缺省为0。不正确的Content-length将会导致函数试图读取更多的数据,并且在超时到达之前一直出于阻塞状态。
readline([len])
像read()一样读取到行尾。注意,同HTTP定义一样,大多数客户端的行结束是'"r"n',而不是简单的'"n'。
readlines([sizehint])
读取sizehint字节以内的所有行,并返回行列表。
register_cleanup(callable[,data])
注册一个清理行为。参数callable可以为任何可调用对象,可选参数data可以是任何对象,缺省为None。在每个请求结束的时候,而在请求对象被销毁之前,callable将会被调用,并且传递一个唯一的参数data。
推荐传递请求对象作为data,但是注意,在执行清理行为时,请求对象的处理已经完成,这时再对客户端进行写操作是无意义的(pointless)。
如果在执行清理时遇到(encounter)错误,将会被日志记录。除非直接影响请求处理,否则执行清理中的bug很难辨认(spot)。
如果在清理行为之前,服务器关闭了,则很可能不会被执行。
sendfile(path[,offset,len])
发送path文件到客户端,开始为offset,并发送len字节。offset缺省为0,而len缺省为-1,发送整个(entire)文件。
返回成功发送的字节数,或者在出错时抛出IOError异常。这个函数提供了向客户端发送文件的最有效(most efficient)的方式。
write(string[,flush=1])
将字符串立即(directly)写入客户端,然活清空(flush)缓存,除非flush是0。
flush()
将缓存数据写入客户端,并清空缓存。
set_content_length(len)
设置req.length和"Content-length"头。注意必须在任何发送数据之前设置,比如req.write()之前,否则是无意义的(meaningless)。
请求对象的成员:
connection
这个请求的连接对象。查看后面的详细介绍。只读。
server
请求所属的服务器对象。查看后面的详细介绍。只读。
next
如果是内部重定向,重定向到的请求对象。只读。
prev
如果是内部重定向,来自重定向的请求对象。只读。
main
如果这是一个子请求,指向主请求。只读。
the_request
包含请求的第一行的字符串。只读。
assbackwards
指定HTTP/0.9的简单请求。这意味着响应不包含任何头,仅包含信息主体。用于兼容古老的浏览器。也可以指定这个选项用于在重定向中避免(avoid)发送头。
proxyreq
代理请求。一个apache.PROXYREQ_*值。只读。
header_only
指定HEAD请求的布尔变量,反对GET。只读。
protocol
客户端提供的协议,或者是'HTTP/0.9'。同CGI SERVER_PROTOCOL。只读。
proto_num
整数,协议版本号,比如1.1对应1001。只读。
hostname
字符串,由URI或Host:设置,头。只读。
request_time
长整数,请求发生的时间。只读。
status_line
状态行,如'200 OK'。只读。
status
状态,apache.HTTP_*中的一个值。
method
包含方法的字符串,如'GET','HEAD','POST'。同CGI REQUEST_METHOD。只读。
method_number
方法号,整数。只读。
allowed
整数,允许方法的位逻辑。使用允许结构:头响应HTTP_METHOD_NOT_ALLOWED或HTTP_NOT_IMPLEMENTED。这个字段是apache内部使用的。需要设置则使用req.allow_methods()方法。只读。
allowed_xmethods
元组,允许的扩展(extension)方法。只读。
allowed_methods
元组,允许的方法,使用METHOD_NOT_ALLOWED的关系。这个成员无法被req.allow_methods()方法修改。只读。
sent_bodyct
整数,正文的字节数。只读。
bytes_sent
长整数,已经发送的字节数。只读。
mtime
长整数,资源的修改时间。只读。
chunked
传送大块数据时的编码,布尔值。只读。
range
字符串'Range:'头。只读。
clength
长整数,真正的正文长度。只读。
remaining
长整数,等待读取的数据字节数,只在一个读取操作中有效,只读。
read_length
长整数,已经读取的字节数,只读。
read_body
整数,请求体怎样被读取,只读。
read_chunked
布尔值,读取大块数据的编码。只读。
expecting_100
布尔值,是否客户端需要等待100(HTTP_CONTINUE)响应,只读。
headers_in
客户端发来的头的表格对象。
headers_out
需要发送给客户端的头的表格对象。
err_headers_out
当出错时需要发送的头的表格对象,用于出错时替换headers_out。
subprocess_env
包含CGI信息的表格对象。在需要信息之前需要先调用req.add_common_vars()方法来填充信息。
notes
与请求拥有共同生存期的对象,用于存储各种信息,可以在一个请求的各个处理器之间传递信息。如果确实需要在各个处理器之间传递信息,最好的方式是给请求对象添加成员。
phase
正在处理的阶段,比如'PythonHandler',只读。
interpreter
正在运行的子解释器名。
content_type
字符串,正文类型。mod_python维护一个内部标志(req._content_type_set)来保持content_type的设置。发布器按照如下方式使用这个标志:当content_type没有明确(explicitly)的设置时,它依靠输出的前几个字节来猜测(attempt)。
content_languages
元组。用字符串列表表示正文的语言。
handler
当前处理器的名字。由mod_mime设置,而不是mod_python处理器。大多数情况还是'mod_python',只读。
content_encoding
字符串,正文编码,只读。
vlist_validator
整数,有效变量的列表(如果为负数),只读。
user
获取验证的用户名。同CGI REMOTE_USER,只读。注意,req.get_basic_auth_pw()必须在此之前调用(be called prior)。
ap_auth_type
验证类型,同CGI AUTH_TYPE,只读。
no_cache
布尔值,如果为true则没有缓存,只读。
no_local_copy
布尔值,如果没有本地副本,只读。
unparsed_uri
URI没有经过任何转换,只读。
uri
URI的一部分路径,只读。
filename
请求的文件名字符串。
canonical_filename
字符串,真实的文件名(req.filename是有效的,如果她们不同)。只读。
path_info
字符串,在文件名之后,查询参数之前的部分。同CGI PATH_INFO。
args
字符串,同CGI QUERY_ARGS,只读。
finfo
元组,文件信息结构,类似于POSIX状态,URI指向的文件的信息(mode,ino,dev,nlink,uid,gid,size,atime,mtime,ctime,fname,name)。模块apache定义了FINFO_*变量的常量,可用于存取其中的元素,如:
fname=req.finfo[apache.FINFO_FNAME]
只读。
parsed_uri
元组,被分解开的URI:(scheme,hostinfo,user, password, hostname, port,path,query,fragment)。模块apache定义了URI*常量用于存取元组的元素,如:
fname=req.parsed_uri[apache.URI_PATH]
只读。
used_path_info
当前请求中被拒绝(reject)的path_info,只读。
eos_sent
布尔值,是否发送过EOS,只读。(EOS=end of stream)
4.5.4连接对象(mp_conn)
连接对象是apache的conn_rec结构的映射。
连接对象的方法:
read([length])
从客户端读取最多length字节的数据。在读到任何数据之前将会阻塞。如果length是-1,则读取直到套接字关闭,就是http服务器代码的EXHAUSTIVE模式。仅可在连接处理器中使用。
注意从3.0.3版本开始,这个方法的行为有所改变,在此前是阻塞读取直到length个字节读取完成。
readline([length])
读取一行,最多到length个字节。
仅可在连接处理器中使用。
write(string)
向客户端写入字符串。仅可在连接处理器中使用。
连接对象的成员:
base_server
连接通过的虚拟主机,只读。
local_addr
服务器的地址元组(address,port),只读。
remote_addr
客户端地址元组(address,port),只读。
remote_ip
客户端的IP地址,同CGI REMOTE_ADDR,只读。
remote_host
字符串,客户端的DNS名称,如果没有检查DNS则返回None,如果没有名字则返回""。同CGI REMOTE_HOST,只读。
remote_logname
远程的名字,如果使用了RFC1413识别信号(ident)。同CGI REMOTE_IDENT,只读。
aborted
布尔值,如果连接被中断则为真,只读。
keepalive
整数,1代表连接保持到下一个请求,0代表未定,-1代表严重错误,只读。
double_reverse
整数,1代表执行反向DNS查询,0代表未启用,-1代表查询失败,只读。
keepalives
连接被使用过的次数,只读。
local_ip
本机的服务器IP地址,只读。
local_host
服务器的DNS名称,只读。
id
长整数,一个唯一的连接ID,只读。
notes
表格对象,包含各种与连接具有相同生命周期的信息。
4.5.5过滤器对象(mp_filter)
过滤器对象控制mod_python的输入输出,通常用于提取信息,获取信息并存入过滤器栈。
过滤器的方法:
pass_on()
不处理任何数据,全部放行。
read([length])
从临近过滤器至多读取length个字节的数据,返回字符串数据,如果读取流结束则返回None。过滤器在遇到EOS之后必须关闭。如果未指定length或为负数,则读取当前所有有效数据。
readline([length])
读取一行至多length个字节。
write(string)
将字符串写入临近的过滤器。
flush()
将缓存输出到FLUSH缓存桶。
close()
关闭过滤器,并发送EOS标志。之后关于这个过滤器的IO操作会抛出异常。
disable()
告知mod_python忽略处理器并让数据放行。在mod_python内部使用打印栈跟踪,防止进入死循环。
过滤器成员:
closed
布尔值,指示过滤器是否关闭,只读。
name
字符串,过滤器的注册名,只读。
req
请求对象的引用,只读。
is_input
布尔值,如果是一个输入过滤器则为True,只读。
handler
字符串,配置中的处理器名称,只读。
4.5.6服务器对象(mp_server)
请求对象映射到apache的request_rec结构。服务器结构描述了服务器(也可能是虚拟服务器)如何处理请求。
服务器方法:
get_config()
类似于req.get_config(),但返回指向server->module_config的配置向量。
register_cleanup(request,callable[,data])
注册一个清除行为。类似于req.register_cleanup(),除了在子结束时间以外(字句不通)。这个函数需要一个额外的参数-请求对象。
服务器成员:
defn_name
字符串,配置文件中服务器定义名,只读。
defn_line_number
整数,服务器定义所在配置文件的行号,只读。
server_admin
ServerAdmin标志的值,只读。
server_hostname
ServerName标志的值,同CGI SERVER_NAME,只读。
names
元组,Serveralias标志的列表,不包含通配符,用wild_names分隔,只读。
wild_names
元组,ServerAlias标志的通配服务器名,只读。
port
整数,TCP/IP端口号,同CGI SERVER_ROOT。在apache2.0开始只是显示为0,可以查看req.connection.local_addr。只读。
error_fname
错误日志文件的文件名,只读。
loglevel
整数,日志级别,只读。
is_virtual
布尔值,如果是一个虚拟服务器则为True,只读。
timeout
整数,Timeout标志的值,只读。
keep_alive_timeout
整数,保持连接的超时时间,只读。
keep_alive_max
每个连接最大允许的请求数,只读。
keep_alive
保持连接?只读。
path
字符串,ServerPath标志的值,服务器路径,只读。
pathlen
整数,路径长度,只读。
limit_req_line
整数,HTTP请求行的长度限制,只读。
limit_req_fieldsize
整数,请求头的长度限制,只读。
limit_req_fields
整数,请求头的字段数量限制,只读。
4.6util-工具箱
util模块提供了类似于cgi模块的多种实用工具。util模块的实现也是非常有效率的,直接调用Apache的API,并且通过环境变量传递信息。
推荐使用以下模块的方式:
from mod_python import util
参考CGI文档:
http://CGI-spec.golux.com
4.6.1FieldStorage类
通过FieldStorage类传递数据,这个类类似于标准模块cgi FieldStorage。
class FieldStorage(req[,keep_blank_values,strict_parsing])
这个类提供了处理从客户端提交的HTML。req是mod_python请求对象的实例。
可选参数keep_blank_values是一个标志选项,判定是否把从数据编码而得的URL中的空值作为空字符串处理。缺省值为False,代表忽略空值,好像他们没有出现过一样。
可选参数strict_parsing还没有实现。
初始化时,FieldStorage类读取所有从客户端提交的信息。当所有客户端信息处理完成时,只剩下一个对应一个请求的FieldStorage类的实例。你也可以尝试在FieldStorage实例化之前和之后访问客户端数据。
从客户端读取的数据将会被转换成Field对象,每项数据一个字段。从HTML提交的输入类型file,将会被以临时文件的形式稍后提交成Field对象的file属性。
FieldStorage类有一个映射对象接口,可以作为词典来处理。当使用映射时,键名是输入字段名,返回的词典值可能是如下的:
StringField的实例,包含输入值。仅限输入一个值的时候。StringField是str的子类提供了value属性来兼容cgi模块。
Field类的实例,如果输入是一个上传文件。
StringField或者/和Field对象的列表。当输入多个值时,比如HTML标签<select>的元素。
注意:不同于标准库cgi模块的FieldStorage类,一个Field对象只能返回上传文件。其他情况返回StringField的实例。这意味着不需要使用.value属性就可以存取字段值,在大多数时候。
除了普通的映射对象方法(指词典),FieldStorage对象还有如下属性:
list
这是Field对象的列表,对应每个输入。如果具有同名的多个输入,则列表中也会拥有多个对象。
FieldStorage类的方法:
getfirst(name[,default])
总是返回表单数据名name的一个值。如果没有对应的字段则返回default指定的值。缺省返回None如果未指定default。
getlist(name)
返回表单字段name的值列表。如果没有对应字段则返回空列表。即使只有一个值也会返回包含这个值的列表。
4.6.2Field类
class Field()
这个类用于FieldStorage的内部实现。每个Field类实例对应一个HTML表单的输入。
Field实例包含如下属性:
name
输入名
value
输入值。这个属性用于读取数据上传文件的数据。但是注意处理大文件,因为整个文件都会被读入内存。
file
类似文件对象,指向上传的临时文件TemporaryFile实例。(更多信息参考python标准tempfile模块中的TemporaryFile类)
简单的来说,它是一个StringIO对象,所以你可以使用这个属性读取字符串值来更好的代替value属性。
filename
客户端提供的文件名。
type
客户端提交的content-type内容类型。
type_options
真实的内容类型,从客户端提交头的content-type提供的。这是一个词典。
disposition
提交头的content-disposition的第一部分的值。
disposition_options
提交头的content-disposition的第二部分的值,词典。
参考:
RFC1867,HTML表单提交文件,"Form-based File Upload in HTML"