为什么 getenv( "QUERY_STRING" ) 在 FastCGI C++ 程序中返回 null?

Why does getenv("QUERY_STRING") return null in a FastCGI C++ program?

本文关键字:程序 C++ 返回 null FastCGI getenv QUERY 为什么 STRING      更新时间:2023-10-16

所以我有一个使用Light HTTPd用C++编写的FastCGI应用程序,但我无法使用getenv("QUERY_STRING")检索查询字符串。如果我去掉querystring请求(或添加一个null检查),一切都很好,但这样做会失败:

#include <stdlib.h>
#ifdef _WIN32
#include <process.h>
#else
#include <unistd.h>
extern char ** environ;
#endif
#include "fcgio.h"
#include "fcgi_config.h"  // HAVE_IOSTREAM_WITHASSIGN_STREAMBUF
#include "redisclient.h"

 while (FCGX_Accept_r(&request) == 0)
 {        
    fcgi_streambuf cin_fcgi_streambuf(request.in);
    fcgi_streambuf cout_fcgi_streambuf(request.out);
    fcgi_streambuf cerr_fcgi_streambuf(request.err);

    cout << "Content-type: text/htmlrn"
                "rn"
                "<TITLE>^_^</TITLE>n"
                "<H1>echo-cfpp</H1>n"
                "<H4>PID: " << pid << "</H4>n"
                "<H4>Request Number: " << ++count << "</H4>n";
    // If I make this conditional on getenv("QUERY_STRING") not returning null,
    // then the program behaves reliably.
    cout <<getenv("QUERY_STRING");
 }

我已经验证了我在请求中传递了一个查询字符串,那么为什么getenv("QUERY_STRING")返回null呢?我应该做什么来检索它?

我对C/C++的参考FastCGI库没有丰富的经验,但我过去曾为Windows实现过CGI和FastCGI库,因此以下内容可能会有所帮助。

基本上,根据FastCGI规范,CGI环境变量通过FCGI_PARAMS流传递,通常由FastCGI库解码。现在,FastCGI并没有详细说明什么是需要的,什么不是,并且假设规则与CGI基本相同。CGI规范第4.1.7节介绍了以下关于QUERY_STRING环境变量的内容:

服务器必须设置此变量;如果Script-URI不包括查询组件,则QUERY_STRING必须定义为空字符串("")。

现在,这基本上意味着您的FastCGI库正在解码FCGI_PARAMS流中的QUERY_STRING参数(否则网关服务器不遵循规范)。

由于引用库试图在同一程序中抽象CGI和FastCGI库,并支持多线程,我强烈怀疑您是否会在环境变量中找到结果(或者存在竞争条件)。

基本上,这意味着getenv()总是返回NULL,并且通过operator<<将空const char*传递给std::ostream是非法的。这可能会使您的应用程序崩溃,因为NULL不是指定流结束的特殊值。


TL;DR:您无法通过流程环境访问QUERY_STRING值,因为您使用的是FastCGI,而不是CGI。您需要阅读库的文档,了解访问请求的查询字符串的标准方法。


编辑:我有关于这种情况的更多信息。

fcgiapp.hFCGX_Accept_r()的文档中写道:

创建要访问的参数数据结构通过getenv(3)如果分配给environ)或通过FCGX_GetParam并将其分配给CCD_ 21。

FCGX_Accept_r之后使用以下内容可以解决问题:

environ = request.envp;

但是,这对于多线程应用程序来说是不安全的(environ不在线程本地存储中),所以我建议您使用其他有文档记录的方法:

const char * query_string = FCGX_GetParam("QUERY_STRING", request.envp);