【发布时间】:2013-12-13 17:48:04
【问题描述】:
我想为GNUNet创建一个远程控制,所以我开始为GNU OS编写一个自制的多线程通用网络服务器,能够验证用户身份(从system user database读取)并能够执行通用 CGI 程序/脚本。我从头开始,现在只是一个草稿。但是,一切似乎都运行良好。
我有一个问题。
如您所知,CGI 程序/脚本从 STDIN 读取 POST 字符串并将其内容发送到 STDOUT。以下是我编写的代码(部分)。而且它似乎有效。
if (pipe(cgiPipe))
{
perror("pipe");
}
cgiPid = fork();
if (cgiPid == 0)
{
/* child */
/* piping the POST content... */
/* first, send the truncated part of the POST string contained within the request string... */
if (nPOSTLength && (nSentChrs = write(cgiPipe[1], sPOSTSegment,
nReqLen + requestString - sPOSTSegment)) > 0)
{
nPOSTLength -= nSentChrs;
/* after, read and send the rest of the POST string not received yet... */
while (nPOSTLength > 0 && (nReadChrs = read(nRemote, reservedBuffer,
BUFFER_SIZE_PER_USER)) > 0 && (nSentChrs = write(cgiPipe[1], reservedBuffer,
nReadChrs)) > 0 && nReadChrs == nSentChrs)
{
nPOSTLength -= nReadChrs;
}
if (nReadChrs < 0)
{
printf("Error reading POST string.\n");
goto closeThread;
}
if (nSentChrs < 0)
{
printf("Error sending POST string.\n");
goto closeThread;
}
}
else
{
write(cgiPipe[1], "(null)", 6);
}
close(cgiPipe[1]);
/* redirecting the output of the pipe to the STDIN of the child process */
dup2(cgiPipe[0], STDIN_FILENO);
/* redirecting STDOUT of the child process to the remote client */
dup2(nRemote, STDOUT_FILENO);
setuid(nUserID);
if (execve(sLocalPath, NULL, aCGIEnv))
{
/* unable to execute CGI... */
perror("execve");
sendString(nRemote,
"HTTP/1.1 200 OK\r\n"
"Content-length: 97\r\n"
"Content-Type: text/html\r\n\r\n"
"<!doctype html><html><head><title>CGI Error</title></head><body><h1>CGI Error.</h1></body></html>\r\n"
);
}
goto closeThread;
}
else if (cgiPid > 0)
{
/* parent */
close(cgiPipe[0]);
/* wait for child process. */
if (waitpid(cgiPid, NULL, 0) == -1)
{
perror("wait");
}
goto closeThread;
}
else
{
/* parent */
perror("fork");
/* let's try to send it as normal file, if the user has the right permissions... */
}
如您所见,在执行 CGI 程序之前,整个 POST 字符串从客户端接收并通过管道传输(首先是请求中包含的截断部分字符串——通常是几个字节——然后是其余的)。 然后,CGI程序被执行。
现在我的问题...
如果我尝试上传几个 MB 的文件,在调用 CGI 之前 会通过管道传输几个 MB:有没有办法将套接字直接重定向到新的 STDIN进程,为了之前不读取它?但是,可以肯定的是,我必须在之前发送 POST 字符串的读取截断部分。所以,我可以用这种方式来概括我想做的事情:
- 将一个字符串(几个字节)传送到 STDIN,然后
- 将套接字(客户端)重定向到 STDIN,然后
- 执行外部进程(CGI 程序)
有可能吗?你能告诉我怎么做吗?
【问题讨论】:
-
一些声明会有所帮助。
-
这个
write(..., nReqLen + requestString - sPOSTSegment))看起来有问题。第三个参数应该是一个整数。我希望这至少会让编译器发出警告。 -
@alk 没错! requestString 是一个字符数组,sPOSTSegment 是一个指向该数组字符的指针[通过:sPOSTSegment = 4 + strstr(requestString, "\r\n\r\n") – 找到时],所以 sPOSTSegment 减去 requestString 是从requestString 开始计数的POST 段的偏移量。而且,如果我执行 TOTAL_LENGTH_OF_THE_REQUEST - POST_OFFSET,那么我会得到 POST 段的长度。所以 ... nReqLen + requestString - sPOSTSegment ... 是请求字符串中包含的 POST 段的长度(截断或不截断)。是整数! GCC 不会发出任何警告。
-
为什么需要将字符串传送到标准输入?你不能把字符串写到标准输入吗?
-
@GiuseppePes 我想向 STDIN 发送一个小字符串,然后 然后 通过管道将 a socket 发送到 STDIN!有什么想法吗?
标签: c sockets webserver pipe dup2