目录
- 1.介绍
- 2.初始化状态
- 2.1. 参数列表
- 2.2. 文件描述符
- 2.3. 环境变量
- 2.4. 其他状态
- 3.协议基础
- 3.1.表达式
- 3.2.接受传输连接
- 3.3.记录
- 3.4.名字-值的对
- 3.5.关闭传输连接
- 4.管理记录类型
- 4.1.FCGI_GET_VALUES, FCGI_GET_VALUES_RESULT
- 4.2.FCGI_UNKNOWN_TYPE
- 5.应用记录类型
- 5.1.FCGI_BEGIN_REQUEST
- 5.2.名字-值的对的流:FCGI_PARAMS, FCGI_RESULTS
- 5.3.字节流:FCGI_STDIN, FCGI_DATA, FCGI_STDOUT, FCGI_STDERR
- 5.4.FCGI_ABORT_REQUEST
- 5.5.FCGI_END_REQUEST
- 6.角色
- 6.1.角色协议
- 6.2.响应者
- 6.3.授权者
- 6.4.过滤者
- 7.错误
- 8.类型和常量
- 9.引用
- A.表:记录类型的熟悉
- B.类型的协议消息流
- C.英文原文
1.介绍
FastCGI全程Fast Common Gateway Interface。FastCGI协议是由CGI协议发展而来。为网络应用提供高性能的支持而不需要受到web服务器的api限制。
该协议规范是一个很狭窄的目标:从应用的观点说明位于一个FastCGI接口和一个Web服务器(支持FastCGi协议)之间的接口。许多与FastCGI相关联的web服务器特性,例如应用管理设施,没有做任何事情在应用到web服务器接口上,这里不做描述。
这个规范是对Unix(更准确地,对支持伯克利socket的POSIX系统),说明的主体是一个简单的通信协议,它是依赖字节的顺序和可以扩展到其他系统。
我们会介绍FastCGI通过比较它和传统的Unix实现的CGI/1.1。FastCGI是被设计去支持长连接的应用进程,这是个主要的不同相较与传统Unix实现的CGI/1.1,它构建一个应用进程,用来响应一个请求然后退出。
FastCGI进程的初始化的状态是比CGI/1.1进程的初始化的状态更简朴的,因为FastCGI的进程不会启动生命连接任何事情。它不会按照惯例的打开文件 stdout,stdin和stderr。它也不会接受许多的信息通过环境变量。初始化状态的关键的部分在FastCGI进程是开始监听socket,通过他来接受来自web服务器的接连。
在FastCGI进程接受连接在它的socket之后,进程执行一个简单的协议接受和发送数据。协议提供两个目的,第一:协议多路复用单个传输连接在几个独立的FastCGI请求,这个支持应用有能力去处理并行的请求用事件驱动或多线程编程技术。第二:在每个请求协议提供几个独立的数据流在每个方向。这种方式,举个例子,stdout和stdin两者数据通过一个传输连接从应用到web服务器而不是像CGI/1.1那样需要各自的通道。
一个FastCGI扮演这个几个定义好的角色中的一个。最熟悉的是响应者角色,在该角色下应用接受所有关于一个HTTP请求信息和产生一个HTTP响应。比如CGI/1.1扮演的角色。第二个角色是授权者,在该角色下,应用接受所有关于一个HTTP请求的信息和产生一个已授权或未授权的决定。第三个角色是过虑者,在该角色下,应用接受所有关于一个HTTP请求加一个额外数据流来着一个文件存储在web服务器的信息和产出一个过滤后的数据流版本作为一个HTTP响应。这个框架是可扩展以至于更多的FastCGI能被以后再定义。
在这个说明的剩余部分项目“FastCGI应用”,“应用进程”或“应用服务者”是缩写为“应用”,无论何时这样不会引起混乱。
2.初始化状态
2.1.参数列表
通过默认web服务器创建一个参数列表包含单个元素,应用的名字,作为可运行路径名的最后一个组件。web服务器可提供一种方式去说明啊一个不同的应用名或一个更多复杂的参数列表。标记文件执行通过web服务器可能被一个编译器文件(一个文本文件以字符#!开始),在这种情况下应用的参数是构建作为描述的在execve主页。
2.2.文件描述符
web服务器只留下一个文件描述符,CGI_LISTENSOCK_FILENO,当应用开始执行时打开,这个描述符涉及如去监听由web服务器创建的socket。FCGI_LISTENSOCK_FILENO等于STDIN_FILENO,标准的描述符STDIN_FILENO和STDERR_FILENO被关闭当应用开始执行。一个可靠的方法对于应用是决定是否它是被引用用CGI或FastCGI是去调用getpeername(FCGI_LISTENSOCK_FILENO),当返回-1并设置errno为ENOTCONN 对于FastCGI应用。web服务器的可靠的传输选择,Unix流通道(AF_UNIX)或TCP/IP(AF_INET)对于FastCGI应用。
2.3.环境变量
web服务器可用环境变量来传输参数给应用,这个说明定义一个例如FCGI_WEB_SERVER_ADDRS;我们期望更多的被定义随着规范的发展和进步。web服务器可提供一种方式去绑定其他的环境变量,例如PATH变量。
2.4.其他状态
web服务器可提供一种方式去说明一个应用初始化进程状态的其他组件,例如进程的优先级,用户ID,组ID,根目录和工作目录。
3.协议基础
3.1.表达式
3.1表达式
我们用C语言表达定义协议消息格式,所以的结构元素被定义在项目的无符号字符类型,是被安置在其中以至ISO C编译器放置它们在明显的方法中,没有覆盖。第一个字节定义在结构中是传输的第一次,第二个字节是第二次,以此类推。我们用两个约定去缩写我们的定义。
第一,当两个相邻的结构组件是被命名表示性的期望为前缀“B1”和“B2”,它意味着两个组件可被看作为一个数字,计算为B1<<8+B0。这个单个数字的名字是组件的名字,减去前缀。这个约定的概括在一个明显方式去处理这个数字代表在超过两个字节。第二,为扩展C结构允许格式
struct {
unsigned char mumbleLengthB1;
unsigned char mumbleLengthB0;
... /* other stuff */
unsigned char mumbleData[mumbleLength];
};
意味着一个可变长度的结构,这里的组件长度是通过表明更早的组件或组件组被决定。
3.2.接受传输连接
一个FastCGI应用调用函数accept()在socket引用上通过文件描述符FCGI_LISTENSOCK_FILENO去接受新的传输连接。如果accept()成功,FCGI_WEB_SERVER_ADDRS 环境变量被绑定,应用立刻表现如下特殊的操作:
- FCGI_WEB_SERVER_ADDRS :值是个ip地址的有些列表对于web服务器。如果FCGI_WEB_SERVER_ADDRS 被绑定,应用在列表中检查新的连接的通道ip地址以获取成员。如果检查失败(包括可能的连接不能用 TCP/IP传输),应用响应通过关闭连接。
- FCGI_WEB_SERVER_ADDRS是被表达作为一个逗号分隔列的IP地址,每一个ip地址是被写作为一个四个数字在范围0-255用小数点分隔。所以对于这个表里FCGI_WEB_SERVER_ADDRS绑定的合法变量是199.170.183.28.199,199.170.183.71。
一个应用可能接受几个并行的传输连接,但是它不必要如此。
3.3.记录
应用执行请求需要从web服务器用一个简单协议。协议的详细依赖在应用的角色,
但是粗略的说web服务器第一次发送参数和其他数据给应用,应用发送结果数据给web服务器和最后地应用发送给web服务器一个这个请求结束的标志。
所有流通通过传输连接的数据是被传输在FastCGI记录。FastCGI记录完成两个事情,第一,记录复用传输连接在多个独立的FastCGI请求。这个多路复用支持应用有能力去处理并行请求用事件驱动或多线程编程技术。第二,记录提供多个独立的数据流在每个方向在一个请求内,这个方式,举个例子,stdout和stderr数据能通过单个传输连接从应用到web服务器,而不是用不同的连接。
typedef struct {
unsigned char version;
unsigned char type;
unsigned char requestIdB1;
unsigned char requestIdB0;
unsigned char contentLengthB1;
unsigned char contentLengthB0;
unsigned char paddingLength;
unsigned char reserved;
unsigned char contentData[contentLength];
unsigned char paddingData[paddingLength];
} FCGI_Record;
一个FastCGI记录由一个固定长度的前缀设置通过一个变量内容的数字和追加的字节。一个揭露包含七个组件:
-
version:标示FastCGI协议的版本,这个规范文档是FCGI_VERSION_1。
-
type:标示FastCGI记录类型,通用函数记录的表现。指明记录类型和他们的方法会被详细说明在下面的段落中。
-
requestId:标示记录所属的FastCGI请求。
-
contentLength:这字节数字在contentData组件的记录。
-
paddingLength:这字节数字在paddingData组件的记录。
-
contentData:在0到65535字节之间的数据。解释根据记录类型。
-
paddingData:在0到255字节之间的数据。它会被忽略。
我们用松散的C结构初始化格式去指定常量FastCGI记录,我们忽略版本组件,
忽略padding和对待requestId作为一个数字,因此{FCGI_END_REQUEST,1,{FCGI_REQUEST_COMPLETE,0}}是一个记录,类型为FCGI_END_REQUEST,requestId == 1,
和contentData == {FCGI_REQUEST_COMPLETE,0}。
填充
协议允许发送者填充他们发生的记录,需要接受者去解释这个paddingLength和跳过这个paddingData,填充允许发送者去保持数据整齐为了更高效的处理,X窗系统的经验显示了对其的表现优势。我们推荐记录以8位字节的倍数来填充边界。固定长度的部分的FCGI_Record是8个字节。
管理请求ID
web服务器重新使用FastCGI请求ID,应用保持每个请求ID当前状态追踪在给的传输连接上,一个请求ID R变成活跃当应用受到一个记录{FCGU_BEGIN_REQUEST,R,...}和变成不活跃当应用发送一个记录{FCGU_END_REQUEST,R,...}给web服务器。当一个请求ID R 是不活跃的,应用忽略记录ID==R,期望对于FCGU_BEGIN_REQUEST记录仅仅是描述的。web服务器企图去保持FastCGI请求IDs 小,这个方式使应用能保持追踪请求ID状态用小的数组而不是长的数组或者是哈希表。一个应用也有选项的接受仅仅在请求在一个时间,在这情况下应用简单的检查进入的requestId值对比与当前的请求Id。
记录的类型
这儿有两个有用方式的分类FastCGI记录类型。
第一个目的是在管理和应用记录之间。一个管理记录保持信息是没有明确说明的对于任何web服务器请求,例如信息关于协议的能力的应用,一个应用记录包括信息关于一个详细的请求,表示通过requestId组件。
管理记录由一个requestId为0的值,也被称为空请求ID,应用记录有非零的requestId。
第二目的是在离散的和流的记录之间。一个离散的记录包含有用的信息单元数据。一个流记录是流的一部分,一个序列的零活更多的非空记录的流类型,支持一个空的记录的流类型contentData 组件的流记录,当连接从一个字节序列,这个自己叙事是流的值,因此流的值是独立的在许多记录它所包含的或它的字节是被分隔在在非空的记录之中。
这里有两种分类是独立的,在记录类型的定义在FastCGI协议的版本中,所有的管理记录记录类型也是离散的记录类型。几乎所有的应用记录类型是流记录类型,但是三个应用记录是离散的,没有东西阻止定义管理记录类型,该类型是协议的某些新版本中的流。
3.4.名字-值对
在许多的角色,FastCGI应用需要读和写变动的数字对的可表长度值,所以它是有用的对于采用一个标准的格式去编码一个名字-值得对。FastCGI传送一个名字-值得对作为名字的长度,根据值的长度,根据名字,根据值。127字节的长度和少于被编码在一个字节的,当更长长度总是被编码在四个字节中。
typedef struct {
unsigned char nameLengthB0; /* nameLengthB0 >> 7 == 0 */
unsigned char valueLengthB0; /* valueLengthB0 >> 7 == 0 */
unsigned char nameData[nameLength];
unsigned char valueData[valueLength];
} FCGI_NameValuePair11;
typedef struct {
unsigned char nameLengthB0; /* nameLengthB0 >> 7 == 0 */
unsigned char valueLengthB3; /* valueLengthB3 >> 7 == 1 */
unsigned char valueLengthB2;
unsigned char valueLengthB1;
unsigned char valueLengthB0;
unsigned char nameData[nameLength];
unsigned char valueData[valueLength
((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0];
} FCGI_NameValuePair14;
typedef struct {
unsigned char nameLengthB3; /* nameLengthB3 >> 7 == 1 */
unsigned char nameLengthB2;
unsigned char nameLengthB1;
unsigned char nameLengthB0;
unsigned char valueLengthB0; /* valueLengthB0 >> 7 == 0 */
unsigned char nameData[nameLength
((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0];
unsigned char valueData[valueLength];
} FCGI_NameValuePair41;
typedef struct {
unsigned char nameLengthB3; /* nameLengthB3 >> 7 == 1 */
unsigned char nameLengthB2;
unsigned char nameLengthB1;
unsigned char nameLengthB0;
unsigned char valueLengthB3; /* valueLengthB3 >> 7 == 1 */
unsigned char valueLengthB2;
unsigned char valueLengthB1;
unsigned char valueLengthB0;
unsigned char nameData[nameLength
((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0];
unsigned char valueData[valueLength
((B3 & 0x7f) << 24) + (B2 << 16) + (B1 << 8) + B0];
} FCGI_NameValuePair44;
高顺序字的顺序的第一个字节的长度表明长度的编码,一个高位零含有一个字节编码,一个四字节编码。这个名字-值对格式运行发送者传送二进制值在不用附加编码情况下。是可使接受者能立刻定位正确存储数量甚至为大的值。
3.5.关闭传输连接
web服务器控制传输连接的生命周期。web服务器能关闭一个连接当没有请求是活跃的。
或web服务器能代表关闭授权给应用(看FCGI_BEGIN_REQUEST)。在这种情况下应用关闭连接在最后说明请求。这个灵活的考虑一个多样的应用类型。简单的应用会操作一个请求在一个时间和接受一个新的传输连接对没有请求。更复杂的应用会处理并行的请求,通过一个或多个传输连接,会保持传输连接打开在长时间的周期。一个简单的应用得到一个重要的表现增长通过关闭传输连接当他已经完成写入它的响应时。
web服务器需要控制连接生命周期在一个长连接中。当一个应用关闭一个连接或者找到一个呗关闭的连接时,应用初始化按一个新的连接。
4.管理记录类型
4.1.FCGI_GET_VALUES,FCGI_GET_VALUES_RESULT
web服务器能查询在应用中特殊的变量,服务者会典型的执行一个茶轩在应用开始的时候为了自动的确定系统层面的配置。应用接受通过发送一个记录{FCGI_GET_VALUES, 0, …},一个FCGU_GET_VALUES记录的contentData部分包括一系列空值的名字-值的对。应用响应通过提供一个值来发送一个记录{FCGI_GET_VALUES_RESULT, 0, …},如果应用不能理解包含在查询中的一个变量名,它会从响应中忽略这个名字。FCGI_GET_VALUES是被设计去允许一个开放变量的结束设置,,这个初始化设置提供信息去帮
助服务器执行应用和连接管理:
- FCGI_MAX_CONNS:这个应用的最大的并行传输连接数量会接受例如1或10。
- FCGI_MAX_REQS:应用的最大并行请求数量会接受例如1或50。
- FCGI_MPXS_CONNS:"0" 如果这个应用没有多路连接(例如处理并行请求通过每个连接),“1”表示否。
一个应用可能接受FCGI_GET_VALUES 记录在任何时间。这个应用的响应应该不涉及应用本身,而只涉及FastCGI库。
4.2.FCGU_UNKOWN_TYPE
管理记录的设置是这个协议的成长在特性版本中,去提供这个进化,协议包括FCGI_UNKOWN_TYPE管理记录。当一个应用受到一个管理记录,这记录类型为T,应用无法理解,应用响应{FCGI_UNKNOWN_TYPE, 0, {T}}。
一个FCGU_UNKOWN_TYPE记录的contentData组件格式如下:
typedef struct {
unsigned char type;
unsigned char reserved[7];
} FCGI_UnknownTypeBody;
类型组件是无法识别的管理组件类型。
5.应用记录类型
5.1.FCGI_BEGIN_REQUEST
web服务器发送一个FCGI_BEGIN_REQUEST记录开始一个请求。
FCGI_BEGIN_REQUEST记录的contentData组件有如下格式
typedef struct {
unsigned char roleB1;
unsigned char roleB0;
unsigned char flags;
unsigned char reserved[5];
} FCGI_BeginRequestBody;
这个角色组件设置了web服务器期望应用扮演的角色,当前的角色定义是:
- FCGI_RESPONDER
- FCGI_AUTHORIZER
- FCGI_FILTER
角色是被描述更多细节在章节6中。
这个标志位组件包含一个字来控制连接关闭:flags&FCGI_KEEP_CONN:如果是零,应用关闭连接在响应这个请求之后,如果非零,应用不会关闭连接在响应之后,web服务器保持响应能力在这个链接上。
5.2.名字-值的对 流:FCGI_PARAMS
FCGU_PARAMS
是个流记录被作用在发送名字-值得对从web服务器到应用。名字-值的对是被发送流一个一个发送切没有明确顺序。
5.3字节流:FCGI_STDIN,FCGI_DATA,FCGI_STDOUT,FCGI_STDERR
- FCGI_STDIN
是一个流记录类型用来在发送任意的数据从web服务器到应用。 - FCGI_DATA
是第二种流记录类型,用来发送追加的数据给应用。 - FCGI_STDOUT/FCGI_STDERR
是流记录类型发送期望的数据和错误数据从应用到web服务器。
5.4.FCGI_ABORT_REQUEST
web服务器发送一个FCGI_ABORT_REQUEST 记录投结束请求,在收到{FCGI_ABORT_REQUEST,R}之后,应用响应尽可能快的{FCGI_END_REQUEST, R, {FCGI_REQUEST_COMPLETE, appStatus}}。这是真实的一个响应从应用,非低级知识面从FastCGI库。
一个web服务器结束一个FastCGI请求当一个http客户端关闭它的传输连接在FastCGI请求已经跑在代表那个客户端。这种情况可能看起来不常见,所有FastCGI是缓慢的,但是FastCGI应用能被延时和另一个系统通信或执行一个服务推送。当web服务器不是一个多路复用的请求通过一个传输连接,web服务器能终止这个请求通过关闭请求的传输连接。但是随着多路复用请求,关闭传输连接已经不好的影响在关闭在连接上的所有的请求。
5.5.FCGI_END_REQUEST
应用发送FCGI_END_REQUEST记录去终结一个请求,要么是因为应用已经处理了请求,或者因为应用已经拒绝了请求。
FCGI_END_REQUEST记录的contentData组件有如下格式:
typedef struct {
unsigned char appStatusB3;
unsigned char appStatusB2;
unsigned char appStatusB1;
unsigned char appStatusB0;
unsigned char protocolStatus;
unsigned char reserved[3];
} FCGI_EndRequestBody;
appStatus组件是一个应用级别的状态码,每个角色记录appSstatus的用法
protocolStatus组件是协议级别的状态码;操作protocolStatus的值是:
- FCGI_REQUEST_COMPLETE:正常的请求结束。
F- CGI_CANT_MPX_CONN:拒绝一个新的请求,这个发生在web服务器发送一个并行请求通过一个连接给应用时,该应用是被设计去处理一个请求在一个时间每切割连接 - FCGI_OVERLOADED:拒绝一个新请求,这个发生在应用用光一些资源,例如数据库连接等。
- FCGI_UNKOWN_ROLE:拒绝一个新请求,这个发生在web服务器已经指明一个角色,但是对于应用来说是未知的。
6.角色是被描述更多细节在章节6中。
6.1角色协议
角色协议仅包含应用记录类型的记录,它们本质上用流来传输所有的数据。为了是协议可靠和简单的应用编程,交涉协议被定义去用贴近连续的编程,在协议中严格顺序的编程。应用接受它的第一次输出,然后它的第二次,以此类推。直到塔接受完毕。相似的,应用发送它的第一次输出,然后第二次,以此类推。直到发送完毕。输入不是对于彼此不是交错的,输出也不是。连续的编组角色对一些FastCGI角色是过于限制的。因为FastCGI编程能写stdout和stderr没有时间性的限制。所以角色协议用FCGI_STDOUT和FCGI_STDERR允许这两个流被交错。
所有的角色协议用FCGI_STDERR流仅是stderr被用作传统的应用编程的一种方式。去报告一个应用级别的错误用可理解的方式。FCGI_STDERR流的使用是可选的。,如果一个应用没有错误去报告,它要么不发送FCGI_STDERR记录或者零长度的FCGI_STDERR记录。
当一个角色协议调用去传送一个其他流而不是FCGI_STDERR,至少是一个流类型的记录总是被传送的,甚至如果流是空的。再者在可靠协议的和简单的应用编程这些有兴趣的方面,角色协议是被设计去贴近请求和响应。在真实的请求和响应协议,应用接受所有的输入记录在发送第一个输出记录之前。请求和响应协议不总是运行流水线。请求和响应视同FCGI_PARAMS去传输文本型的值,例如CGI程序从环境变量获得的值,值得长度不包括结束的空字节。值它本身也不包括空的字节。一个应用需要去提供environ(7)格式的名字-值的对必须插入一个等于的签名在名字和值还有追加的空字节在值得后面。角色协议不支持无法解析的头特性的CGI,FastCGI应用设置响应状态用Status和location CGI头组。
6.2.响应者
一个响应者的FastCGI应用有相同的目的作为CGI/1.1程序:她接受所有关联一个HTTP请求的信息和生产一个HTTP响应。它的足够去解释每个CGI/1.1的元素怎样去模仿作为一个响应者:
- 响应者应用接受CGI/1.1 环境变量从web服务通过FCGI_PARAMS。
- 下一步响应者应用接受CGI/1.1 stdin数据从web服务器通过FCGI_STDIN。应用接受几乎为CONTENT_LENGTH字节从这个流上在接受终止流的最后标示之前。
- 响应者应用发送CGI/1.1 stdout数据给web服务器通过FCGI_STDOUT,CGI/1.1 stderr数据通过FCGI_STDERR。应用发送这些并行的,而不是一个接着一个。应用必须等待完成读取FCGI_PARAMS在它开始写FCGI_STDOUT和FCGI_STDERR之前,但是它不必完成从FCGI_STDIN读取在它开始写这两个流之前。
- 在发送它所有的stdout和stderr数据之后,响应者应用发送一个FCGI_END_REQUEST记录。应用设置protocolStatus组件给FCGI_REQUEST_COMPLETE和appStatus组件的CGI程序会返回通过exit的系统调用的状态码。
一个响应者执行更新,例如执行一个POST方式,应该比较从FCGI_STDIN通过CONTENT_LENGTH的字节的数量和终止更新如果两个数字不相等。
6.3.授权者
一个授权者FastCGI应用接受所有关于HTTP请求的信息和生产一个授权/非授权的决定。在这种情况下一个授权决定授权者也能和HTTP请求关联名字-值的对。当给一个非授权的决定时授权者发送一个完全的响应给HTTP客户端。只从CGI/1.1定义了一种近乎完美的好方法去表示联系HTTP请求的信息,授权者用相同的表示:
- 授权者应用接受HTTP请求信息从web服务器在fcgi_params流上,用相同的格式作为响应者。web服务器不会发送CONTENT_LENGTH,PATH_INFO,PATH_TRANSLATED和SCRIPT_NAME头。
- 授权者应用发送stdout和stderr数据用相同的方式作为一个响应者。CGI/1.1响应状态说明请求的处理。如果应用大宋状态码200(OK),web服务器运行访问,依赖于它的配置,web服务器可能进行其他的访问检查,包括请求其他的授权者。
一个授权者应用的200响应可能包括明智是前缀为Variable-的头。这些头通过名字-值的对在应用与web服务器沟通。
举个例子,响应的头
Variable-AUTH_METHOD: database lookup
传输“database lookup”用名字AUTH_METHOD,这个服务例如名字-值得对是与HTTP请求有联系,包括在随后的CGI或者FastCGI请求执行在处理HTTP请求时。当应用给一个200响应,服务忽略这些以Variable-为前缀的响应头,也会忽略任何响应内容。对与授权者响应状态值是非200(OK),web服务器拒绝访问并发送响应状态,头和内容返回给HTTP客户端。
6.4.过虑者
一个过虑者FastCGI应用接受所有与HTTP请求相关的信息,加上一个额外的数据流从在web服务器上的文件存储,生产一个过滤后的版本的数据流作为HTTP响应。一个过虑者是和响应者具有类似的功能,都是处理数据文件作为参数。不同的是作为一个过虑者,数据文件和过虑者自己都能被控制访问使用web服务器的访问控制机制,当一个响应者获得一个数据文件的名字作为一个参数时必须处理它自己的访问控制检查在这个数据文件上。
过虑者的步骤处理是与响应者是相似的。第一服务表示过虑者用环境变量,然后标准的输入(正常的从POST数据),最后数据文件输入:
- 像响应者一样,过虑者应用接受名字-值对从web服务器通过FCGI_PARAMS。过虑者应用接受两个过滤说明参数:FCGI_DATA_LAST_MOD和FCGI_DATA_LENGTH。
- 下一步过虑者应用接受CGI/1.1 stdin数据从web服务器通过FCGI_STDIN。应用接受CONTENT_LENGTH长度的字节从这个流上在接受结束表示之前。(如果HTTP客户端不能提供,例如客户端挂了,应用接受少于content_length字节的数据)。
-下一步过虑者应用接受文件数据从web服务器通过FCGI_DATA,这个文件的最后修改时间(表示为一个整形的从1970-01-01开始的数字)是FCGI_DATA_LAST_MOD;应用读取FCGI_DATA_LENGTH字节的数据从这个流上在接受到结束流标示之前。 - 过虑者应用发送CGI/1.1 stdout数据导问服务器通过FCGI_STDOUT和CGI/1.1 stderr数据通过FCG_STDERR。这个应用发送这些并行的数据,而不是一个一个发送。应用必须等待结束读取FCGI_STDIN在它开始写FCGI_STDOUT和FCGI_STDERR之前,但是它不必结束读取FCGI_DATA在它开始写这两个流之前。
- 在发送所有的stdout和stderr数据之后,应用发送一个FCGI_END_REQUEST记录。应用设置一个protocolStatus组件给FCGI_REQUEST_COMPLETE和appstatus组件的状态码,这是类似的CGI程序会通过exit系统调用返回的。
一个过滤器应该比较在FCGI_STDIN收到的字节的数量和CONTENT_LENGTH的值,与FCGI_DATA和FCGI_DATA_LENGTH。如果这个数字是不匹配的和过滤器是一个查询,过虑者响应会提供一个标示数据丢失。如果数字不匹配且过滤器是一个更新,过滤器应该终止更新。
7.错误码
一个FastCGI应用以零状态退出标示它已经完成目的,比如为了执行一种粗略的垃圾回收。
一个FastCGI应用以非零状态退出似乎除了崩溃。一个web服务器或其他应用怎么管理响应给一个以零或非零退出码是不在这次规范的范围内。
一个web服务器能请求一个FastCGI应用退出通过发送给它一个STGERM信号。如果应用忽略STGTERM信号web服务器能再发送SIGKILL信号。
FastCGI应用报告应用级别错误通过FCGI_STDERR流和FCGI_END_REQUEST的appStatus组件,在许多情况下一个错误会被直接报告通过FCGI_STDOUT流。
在UNIX,应用报告基础级别错误,包括FastCGI协议错误和格式错误在FastCGI环境版本,通过syslog。依赖错误的级别,应用能要么继续要么以非零码退出。
8.类型和常量
/*
* Listening socket file number
*/
#define FCGI_LISTENSOCK_FILENO 0
typedef struct {
unsigned char version;
unsigned char type;
unsigned char requestIdB1;
unsigned char requestIdB0;
unsigned char contentLengthB1;
unsigned char contentLengthB0;
unsigned char paddingLength;
unsigned char reserved;
} FCGI_Header;
/*
* Number of bytes in a FCGI_Header. Future versions of the protocol
* will not reduce this number.
*/
#define FCGI_HEADER_LEN 8
/*
* Value for version component of FCGI_Header
*/
#define FCGI_VERSION_1 1
/*
* Values for type component of FCGI_Header
*/
#define FCGI_BEGIN_REQUEST 1
#define FCGI_ABORT_REQUEST 2
#define FCGI_END_REQUEST 3
#define FCGI_PARAMS 4
#define FCGI_STDIN 5
#define FCGI_STDOUT 6
#define FCGI_STDERR 7
#define FCGI_DATA 8
#define FCGI_GET_VALUES 9
#define FCGI_GET_VALUES_RESULT 10
#define FCGI_UNKNOWN_TYPE 11
#define FCGI_MAXTYPE (FCGI_UNKNOWN_TYPE)
/*
* Value for requestId component of FCGI_Header
*/
#define FCGI_NULL_REQUEST_ID 0
typedef struct {
unsigned char roleB1;
unsigned char roleB0;
unsigned char flags;
unsigned char reserved[5];
} FCGI_BeginRequestBody;
typedef struct {
FCGI_Header header;
FCGI_BeginRequestBody body;
} FCGI_BeginRequestRecord;
/*
* Mask for flags component of FCGI_BeginRequestBody
*/
#define FCGI_KEEP_CONN 1
/*
* Values for role component of FCGI_BeginRequestBody
*/
#define FCGI_RESPONDER 1
#define FCGI_AUTHORIZER 2
#define FCGI_FILTER 3
typedef struct {
unsigned char appStatusB3;
unsigned char appStatusB2;
unsigned char appStatusB1;
unsigned char appStatusB0;
unsigned char protocolStatus;
unsigned char reserved[3];
} FCGI_EndRequestBody;
typedef struct {
FCGI_Header header;
FCGI_EndRequestBody body;
} FCGI_EndRequestRecord;
/*
* Values for protocolStatus component of FCGI_EndRequestBody
*/
#define FCGI_REQUEST_COMPLETE 0
#define FCGI_CANT_MPX_CONN 1
#define FCGI_OVERLOADED 2
#define FCGI_UNKNOWN_ROLE 3
/*
* Variable names for FCGI_GET_VALUES / FCGI_GET_VALUES_RESULT records
*/
#define FCGI_MAX_CONNS "FCGI_MAX_CONNS"
#define FCGI_MAX_REQS "FCGI_MAX_REQS"
#define FCGI_MPXS_CONNS "FCGI_MPXS_CONNS"
typedef struct {
unsigned char type;
unsigned char reserved[7];
} FCGI_UnknownTypeBody;
typedef struct {
FCGI_Header header;
FCGI_UnknownTypeBody body;
} FCGI_UnknownTypeRecord;
9.引用
The WWW Common Gateway Interface at W3C
A.表:记录类型的属性
如下的图表列出了所有的记录类型和标示这每一个属性:
- WS->App:这个记录的类型仅能被发送通过web服务器给应用。其他类型的记录仅能被发送通过应用给web服务器。
- management:这个类型的记录保存信息是不被web服务器特别指明的是用在空请求ID上。其他记录的类型保持请求说明信息不能用在空请求ID上
- stream:这个记录的类型来自流,结束通过空长度的记录。其他记录的类型是不一样的;每一个运载一个有用的单元数据。
WS->App management stream
FCGI_GET_VALUES x x
FCGI_GET_VALUES_RESULT x
FCGI_UNKNOWN_TYPE x
FCGI_BEGIN_REQUEST x
FCGI_ABORT_REQUEST x
FCGI_END_REQUEST
FCGI_PARAMS x x
FCGI_STDIN x x
FCGI_DATA x x
FCGI_STDOUT x
FCGI_STDERR x
B.典型的协议信息流
示例的其他符合的惯例
- contentData的流记录(FCGI_PARAMS, FCGI_STDIN, FCGI_STDOUT, and FCGI_STDERR)是以字符串来标示的,一个字符在“...”过长去显示,所以只有前缀被显示。
- 消息发送给web服务器是缩进的,代表消息被接受从web服务器。
- 消息被展示通过应用在时间系列的经验上。
1.一个简单的请求,没有数据再stdin,且是一个成功的响应
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, 0}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
2.相似与例子1,但是这个时间数据再stdin。web服务器选择发送参数用更多的FCGI_PARAMS记录在之前:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, 0}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SER"}
{FCGI_PARAMS, 1, "VER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_STDIN, 1, "quantity=100&item=3047936"}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
3.相似与例子1,但是这个时间应用检测到错误,应用记录这个消息在stderr上,返回一个页面给客户端,返回一个非零的退出状态给web服务器。
应用悬着去发送页面使用更多的FCGI_STDOUT记录:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, 0}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n<ht"}
{FCGI_STDERR, 1, "config error: missing SI_UID\n"}
{FCGI_STDOUT, 1, "ml>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_STDERR, 1, ""}
{FCGI_END_REQUEST, 1, {938, FCGI_REQUEST_COMPLETE}}
4.两个实例的例子1,多路复用在一个连接上。第一个请求是比第二个更困难,所以应用结束请求的完成顺序:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, FCGI_KEEP_CONN}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_BEGIN_REQUEST, 2, {FCGI_RESPONDER, FCGI_KEEP_CONN}}
{FCGI_PARAMS, 2, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n"}
{FCGI_PARAMS, 2, ""}
{FCGI_STDIN, 2, ""}
{FCGI_STDOUT, 2, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
{FCGI_STDOUT, 2, ""}
{FCGI_END_REQUEST, 2, {0, FCGI_REQUEST_COMPLETE}}
{FCGI_STDOUT, 1, "<html>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
网友评论