【问题标题】:Why does getenv("QUERY_STRING") return null in a FastCGI C++ program?为什么 getenv("QUERY_STRING") 在 FastCGI C++ 程序中返回 null?
【发布时间】:2012-03-18 08:46:44
【问题描述】:

所以我有一个使用 Light HTTPd 用 C++ 编写的工作 FastCGI 应用程序,但是我无法使用 getenv("QUERY_STRING") 检索查询字符串。如果我取出查询字符串请求(或添加对 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/html\r\n"
                "\r\n"
                "<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++ fastcgi lighttpd


    【解决方案1】:

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

    基本上,按照the FastCGI specification,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&lt;&lt; 将空的const char* 传递给std::ostream 是非法的。这可能会使您的应用程序崩溃,因为 NULL 不是指定流结束的特殊值。


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


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

    documentation for FCGX_Accept_r() in fcgiapp.h 说:

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

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

    environ = request.envp;
    

    但是,这对于多线程应用程序是不安全的(environ 不在线程本地存储中),因此我建议您改用其他记录在案的方法:

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

    【讨论】:

    • 这实际上是图书馆记录的访问查询字符串的方式,遗憾的是。 fastcgi.com/devkit/doc/fastcgi-prog-guide/ch2c.htm 在我来这里之前,我做了很多事情。我还发现了 null 感谢您确认这一点。
    • @user1202909:更新了我的答案。您的代码不满足文档中所述的先决条件。
    • 实际上,FWIW,libstdc++ 检查 null char const* 的流。当然,它仍然是 UB
    • @user1202909:我是通过阅读 Google 第一次点击的文档找到的。我问的并不是无关紧要的。我的回答是猜测,因为我不知道你的程序是否使用了environ=request.envp;。如果您向我展示您的代码,我会更快地找到您的答案,并且可以为您提供可靠、直接、两行的答案
    • @user1202909:你知道...你问了一个问题,我们试图提供帮助并要求提供更多信息,而你所做的只是反击(首先抵抗,然后侮辱)。以及我是如何解决你的问题的,你告诉我我应该做一些不同的事情。老实说,我真的不明白。无论如何,以后不要指望我的帮助。
    猜你喜欢
    • 2017-01-08
    • 2019-03-30
    • 1970-01-01
    • 2015-12-09
    • 1970-01-01
    • 1970-01-01
    • 2019-05-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多