一、cgi 规范
官方文档:RFC3875: CGI - the Common Gateway Interface`
1. CGI 目的
The Common Gateway Interface (CGI) allows an HTTP server and a CGI script to share responsibility for responding to client requests.
CGI 使得 Http-Server 和 CGI 程序 可以在 客户端请求提供相应 上分工合作、各司其职。
2. Server 职责
The server acts as an application gateway. It receives the request from the client, selects a CGI script to handle the request, converts the client request to a CGI request, executes the script and converts the CGI response into a response for the client.
Http-Server 作为一个应用网关,负责:
- 接受http请求
 - 选择一个cgi程序处理http请求
 - 将http请求转化成cgi请求
 - 执行cgi程序
 - 将cgi程序的响应转为为http响应
 
3. server 发起 CGI 请求
Server 在发起 cgi 请求时,需要从 http 请求中解析到以下信息:
- Meta-variables: 
CONTENT_TYPEPATH_INFOREMOTE_ADDRREMOTE_HOSTREQUEST_METHODSCRIPT_NAMESERVER_NAME等 - 请求体:post 数据等
 - 请求方法:
GETPOSTHEAD等 - cgi 程序的执行命令
 
4. server 解析 CGI 响应
- 接收 cgi 响应:
 
cgi 程序通过使用 server 提供的方法 或者 标准输出文件符 将结果返回给 server,同时,server 也会实现一个等待 cgi 返回的超时策略,用来终止超时未返回的 cgi 进程。
- 
解析 cgi 响应类型:
- 
document-response,文档响应,如:Content-Type [ Status ] *other-field NL response-body。server会在此基础上做一些改动,以符合 http 协议。 - 
local-redir-response,本地重定向响应,如:local-Location NL。server需要根据此影响,发起另一次的cgi 请求。 - 
client-redir-response,客户端重定向响应,如:client-Location *extension-field NL。对于 http 请求,server需要返回给客户端一个302 found的客户端重定向响应。 - 
client-redirdoc-response,客户端文档重定向响应,如:client-Location Status Content-Type *other-field NL response-body。 
 - 
 - 
解析 cgi 响应头信息:
- 
Content-Type,响应类型,如:"Content-Type:" media-type - 
Location,重定向相关头信息,包含:Locationclient-Locationlocal-Locationfragment-URIfragmentlocal-pathqueryabs-path等。 - 
Status,处理状态,定义:Status:" status-code SP reason-phrase NL,如:200 'OK',302 'Found',400 'Bad Request',501 'Not Implemented'等。 - 
Protocol-Specific Header Fields,协议特殊响应,如:HTTP/1.0,HTTP/1.1等。 - 
Extension Header Fields,扩展头信息,以X-CGI-打头的响应头。 
 - 
 解析 cgi 响应内容:
cgi 响应体的定义是 response-body = *OCTET,server 需要将 cgi 响应体原封不动的返回给客户端,除非 cgi 响应头信息中要求了 transfer-codings,content-codings,charset conversions 相关的转化。
5. cgi 对 server 的规范要求
define any restrictions on allowed path segments, in particular whether non-terminal NULL segments are permitted;
- server 要对 
允许访问的 path进行限制 
define the behaviour for "." or ".." path segments; i.e., whether they are prohibited, treated as ordinary path segments or interpreted in accordance with the relative URL specification.
- server 要明确 
.和..的处理方式 
define any limits of the implementation, including limits on path or search string lengths, and limits on the volume of header fields the server will parse.
- server 要对 
pathquery_string头信息数量及长度进行限制 
6. cgi 对 cgi 程序的规范要求
- 对于无法处理的 
path_info给与404 Not Found响应。 - 对于无法确认 
content_type的表单给与415 'Unsupported Media Type'响应。即:不是application/x-www-form-urlencoded且不是multipart/form-data的表单。 - 在返回头信息时,cgi 程序应当在 http 头信息之前,尽可能快的返回 cgi 头信息,以便节省 server 的内存使用。
 - cgi 应该明白 
REMOTE_ADDR和REMOTE_HOST并不能正确表明请求的最终来源,这些只表明了请求的最近来源,而这个来源可能是代理或者网关。 
7. cgi 中的安全考虑
- 
get和head请求方法应该是安全的,幂等的(多次请求和一次请求的效果是一样的)。 - 对于 http 头信息中包含的 
敏感信息,如:HTTP_AUTHORIZATION,server 不应该将这些头信息传递给 cgi 程序。 - 重要的数据应该作为 post 请求的消息体,而不是在 uri 中或者 header 中。
 - 对于 
TLS连接的认证,应该在 server 端完成,而不是 cgi 程序来完成。 - 在一般的 cgi 实现中,cgi 进程作为 server 进程的子进程,用户 server 一样的 
user和group,cgi 程序不应该影响 server 进程,包含:配置文件、文档、日志等。 - 固定长度缓冲区的使用如果不仔细检查溢出,可能会导致攻击者利用操作系统的“stack smashing”或“stack overflow”漏洞。
 - 要充分考虑 web 请求的无状态性,对于构成一个 
web 事务的多次请求,要充分验证数据的合法性,不能对发起请求的网络代理(user-agent)做任何上下文的假设。 
二、fastcgi 规范
官网:www.fastcgi.com
二手中文文档:FastCGI规范
fastcgi 在 cgi 的基础上进行了优化,主要体现在:cgi 程序的执行方式 和 cgi 程序的角色 两方面。
1. 执行方式上的优化
- 在 cgi 模式中,server 对于每一个请求,都启动一个进程,由这个进程负责 cgi 程序的执行,得到影响后退出进程。即:
fork-and-execute。 - 在 fastcgi 模式中:
- server 和 fastcgi 分开部署,server 和 fastcgi 基于 socket 通信
 - fastcgi 包含 
一个负责 socket 通信的父进程和若干个负责处理请求的子进程 - fastcgi 的子进程在处理完一个请求后,
并不退出,会等待处理下一个请求 
 
2. 角色上的变化
- 在 cgi 模式中,server 解析 http 请求,组织 cgi 请求参数,转化为 cgi 请求,由 cgi 程序给出响应,然后再由 server 转化为 http 响应,发送给客户端。即:一个 
Responder角色。 - 在 fastcgi 模式中,cgi 程序:
- 
Responder,像 cgi 模式中一样,作为响应者给出响应。 - 
Authorizer,根据所收到的 cgi 请求信息,对请求做出一个认可或者未认可的判定。 - 
Filter,对所收到的 http 请求信息进行过滤,返回一个过滤后的 http 请求信息。 
 - 
 
3. fastcgi 工作流程
- 
fastcgi进程启动一个 socket 监听,等待server进程的 socket 连接,并启动若干个子进程,用于 cgi 程序的执行。 - 
server与fastcgi进行 socket 通信,并以fastcgi协议的形式,发送cgi环境变量和标准输入数据给用于 cgi 执行的子进程。 - 
用于 cgi 执行的子进程在执行完 cgi 程序后将响应发送给server进程。 - 
用于 cgi 执行的子进程处理完一个 socket 连接,等待下一个连接。 
三、 cgi 个人理解
综上对 rfc3875 的阅读整理以及对 fastcgi 的学习,个人对 cgi 的理解是:
cgi是一个协议规范,它在职责、实现要求、通信方式、安全性等方面对 server 和 cgi 程序进行了规范,使得很多语言在满足 CGI 规范的前提下,能和 server 分工合作,构建起了我们的动态网站(Dynamic website)。cgi规范中缺少 server 对 cgi-script 执行方式的规范,使得 cgi 的执行停留在fork-and-execute阶段,性能低下。fastcgi在 cgi 程序的执行方式上进行了优化,以server和fastcgi进行 socket 通信的方式实现了分开部署,甚至多机器部署。fastcgi还进一步扩充了 cgi 程序的角色,使得 cgi 程序在单一的Responder的基础上,有了Authorizer和Filter两个功能。php-cgi是fastcgi的一个php 版本实现,使得 php 可以作为 cgi 语言的一种,承担动态网站的开发。php-fpm即FastCGI Process Manager,它是php-cgi的一个进程管理器,提供了对php-cgi进程的一系列管理功能,如:平滑终止、平滑重启(加载新的php.ini)等。