一、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_TYPE
PATH_INFO
REMOTE_ADDR
REMOTE_HOST
REQUEST_METHOD
SCRIPT_NAME
SERVER_NAME
等 - 请求体:post 数据等
- 请求方法:
GET
POST
HEAD
等 - 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
,重定向相关头信息,包含:Location
client-Location
local-Location
fragment-URI
fragment
local-pathquery
abs-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 要对
path
query_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)等。
网友评论