[nginx源码]FastCGI模块详解

目录1.初识FastCGI协议1.1消息头1.2消息体举例2. 基础知识2.1 FastCGI配置2.2FastCGI配置预处理3.构造FastCGI请求3.1FastCGI请求结构3.2 计算请求第一部分长度3.3填充请求第一部分3.4填充请求第二三部分4. 实战4.1配置4.2FastCGI请求包总结1.初识FastCGI协议...
摘要由CSDN通过智能技术生成

目录

1.初识FastCGI协议

1.1消息头

1.2消息体举例

2. 基础知识

2.1 FastCGI配置

2.2FastCGI配置预处理

3.构造FastCGI请求

3.1FastCGI请求结构

3.2 计算请求第一部分长度

3.3填充请求第一部分

3.4填充请求第二三部分

4. 实战

4.1配置

4.2FastCGI请求包

总结


1.初识FastCGI协议

FastCGI 是一种协议,规定了FastCGI应用和支持FastCGI的Web服务器之间的接口。FastCGI是二进制连续传递的。

1.1消息头

FastCGI定义了多种类型的消息;nginx对FastCGI消息类型定义如下:

#define NGX_HTTP_FASTCGI_BEGIN_REQUEST  1
#define NGX_HTTP_FASTCGI_ABORT_REQUEST  2
#define NGX_HTTP_FASTCGI_END_REQUEST    3
#define NGX_HTTP_FASTCGI_PARAMS         4
#define NGX_HTTP_FASTCGI_STDIN          5
#define NGX_HTTP_FASTCGI_STDOUT         6
#define NGX_HTTP_FASTCGI_STDERR         7
#define NGX_HTTP_FASTCGI_DATA           8

一般情况下,最先发送的是BEGIN_REQUEST类型的消息,然后是PARAMS和STDIN类型的消息;

当FastCGI响应处理完后,将发送STDOUT和STDERR类型的消息,最后以END_REQUEST表示请求的结束。

FastCGI定义了一个统一结构的8个字节消息头,用来标识每个消息的消息体,以及实现消息数据的分割。结构体定义如下:

typedef struct {
    u_char  version; //FastCGI协议版本
    u_char  type;    //消息类型
    u_char  request_id_hi; //请求ID
    u_char  request_id_lo;
    u_char  content_length_hi; //内容
    u_char  content_length_lo;
    u_char  padding_length;    //内容填充长度
    u_char  reserved;          //保留
} ngx_http_fastcgi_header_t;

我们看到请求ID与内容长度分别用两个u_char存储,实际结果的计算方法如下:

requestId = (request_id_hi << 8) + request_id_lo;
contentLength = (content_length_hi << 8) + content_length_lo;

消息体的长度始终是8字节的整数倍,当实际内容长度不足时,需要填充若干字节;填充代码如下所示:

padding = 8 - len % 8;
padding = (padding == 8) ? 0 : padding;

1.2消息体举例

BEGIN_REQUEST类型的消息标识FastCGI请求的开始,结构固定,定义如下:

typedef struct {
    u_char  role_hi; //标记FastCGI应用应该扮演的角色
    u_char  role_lo;
    u_char  flags;
    u_char  reserved[5];
} ngx_http_fastcgi_begin_request_t;

角色同样使用两个u_char存储,计算方法为:

role = (role_hi << 8) + role_lo;

最常用的是响应器(Responder)角色,FastCGI应用接收所有与HTTP请求相关的信息,并产生一个HTTP响应。

nginx配置文件中,fastcgi_param指令配置的若干参数,以及HTTP请求的消息头,都是通过FCGI_PARAMS类型的消息传递的,此消息就是若干个名—值对(此名—值对在php中可以通过$_SERVER[ ]获取);

传输格式为nameLength+valueLength+name+value。

为了节省空间,对于0~127长度的值,Length使用了一个char来表示,第一位为0,对于大于127的长度的值,Length使用了4个char来表示,第一位为1;如下图所示:

https://i-blog.csdnimg.cn/blog_migrate/f22c84d74c75f30781dac35abe758bfa.png

Length字段编码的逻辑如下:

if (val_len > 127) {
    *b->last++ = (u_char) (((val_len >> 24) & 0x7f) | 0x80);
    *b->last++ = (u_char) ((val_len >> 16) & 0xff);
    *b->last++ = (u_char) ((val_len >> 8) & 0xff);
    *b->last++ = (u_char) (val_len & 0xff);
 
} else {
    *b->last++ = (u_char) val_len;
}

2. 基础知识

2.1 FastCGI配置

代码中搜索ngx_http_fastcgi_commands,查看fastcgi模块提供的配置指令;

static ngx_command_t  ngx_http_fastcgi_commands[] = {
 
    { ngx_string("fastcgi_pass"),
      NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1, //只能出现在location块中
      ngx_http_fastcgi_pass,
      NGX_HTTP_LOC_CONF_OFFSET,
      0,
      NULL },
    { ngx_string("fastcgi_param"),
      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE23, //可以出现在http配置块、server配置块、location配置块中
      ngx_http_upstream_param_set_slot,
      NGX_HTTP_LOC_CONF_OFFSET,
      offsetof(ngx_http_fastcgi_loc_conf_t, params_source),   //ngx_http_fastcgi_loc_conf_t结构的params_source字段是存储配置参数的array,
      NULL },
    …………
}

fastcgi_pass指令用于配置上游FastCGI应用的ip:port,ngx_http_fastcgi_pass方法解析此指令(设置handler为ngx_http_fastcgi_handler方法,命中当前location规则的HTTP请求,请求处理的内容产生阶段会调用此handler);

fastcgi_param用于配置nginx向FastCGI应用传递的参数,在php中,我们可以通过$_SERVER[" "]获取这些参数;

解析fastcgi_param配置的代码实现如下:

char * ngx_http_upstream_param_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    a = (ngx_array_t **) (p + cmd->offset);   //ngx_http_fastcgi_loc_conf_t结构首地址加params_source字段的偏移
    param = ngx_array_push(*a);
     
    value = cf->args->elts;
    param->key = value[1];
    param->value = value[2];
    param->skip_empty = 0;
 
    if (cf->args->nelts == 4) {   //if_not_empty用于配置参数是否必传(如果配置,当值为空时不会传向FastCGI应用传递此参数)
        if (ngx_strcmp(value[3].data, "if_not_empty") != 0) {
            return NGX_CONF_ERROR;
        }
        param->skip_empty = 1;
    }
    return NGX_CONF_OK;
}

2.2FastCGI配置预处理

fastcgi_param配置的所有参数会会存储在ngx_http_fastcgi_loc_conf_t结构体的params_source字段;

nginx为了方便生成fastcgi请求数据,会提前对params_source做一些预处理,预先初始化号每个名—值对的长度以及数据拷贝方法等;

2.1节查看fastcgi模块提供的配置指令时发现,某些配置指令出现在location配置块,有些配置却可以出现http配置块、server配置块和location配置块;即可能出现同一个指令同时出现在好几个配置块中,此时如何解析配置?

对于这些配置指令,nginx最终会执行一个merge操作,合并多个配置为一个;观察nginx的HTTP模块,大多模块都会存在一个merge_loc_conf字段(函数指针),用于merge配置;

fastcgi模块的merge操作由ngx_http_fastcgi_merge_loc_conf完成,其同时对params_source进行了一些预处理;代码如下:

static char * ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
    ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
                          prev->upstream.connect_timeout, 60000);
    ngx_conf_merge_value(conf->upstream.pass_request_headers,
                          prev->upstream.pass_request_headers, 1);  //配置HTTP头部是否传递给FastCGI应用,默认为1
    ngx_conf_merge_value(conf->upstream.pass_request_body,
                          prev->upstream.pass_request_body, 1);     //
  • 3
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值