10.处理POST方法的 CGI 请求
在WEB环境中,浏览器与服务器之间的数据交互,很多是通过 HTML 中form 表单完成的。form提供了两种数据传输的方式---GET 和POST。虽然他们都是数据的提交方式,但是在实际传输时确有很大的不同,并且可能会对数据产生严重的影响。二者主要的区别如下:
1.GET是用来从服务器上获得数据,而POST是用来向服务器上传递数据。
2.GET将表单的数据按照variable=value的形式,添加到action所指向的 URL后面,并且两者使用“?”连接,而各个变量之间使用“&”连接;POST是将表单中的数据放在form的数据体中,按照变量和值相应的方式,传递到action所指向的URL。
3.GET是不安全的。因为自傲传输过程,数据会被放在请求的URL中,而如今现有的很多服务器、代理服务器或者用户代理都会请求URL记录到日志文件中,然后放在某个地方,这样就可能有一些隐私被第三方看到。另外,用户也可以在浏览器上直接看到提交的数据,一些系统内部信息将会一同显示在用户面前。POST的所有操作对用户来都是不可见得。
4.GET传输的数据量小,这主要是因为受URL长度限制;而POST可以传输大量的数据,所以在上次文件只能使用POST.
5.GET限制Form表单的数据集的必须为ASCII字符;POST支持整个ISO10646字符集。
6.GET是 form的默认方法。
我们利用上面提到的 post.html 文件来比较它与 get.html 产生的结果的不同之处。
post.html
- <html>
-
<head><title>test of "POST"</title></head>
-
<body>
-
<h1>Test POST Form</h1>
-
<form method="POST" action="/cgi-bin/test_post">
-
<h2>Input your test strings:</h2>
-
ID:<input type=text name=id><br>
-
Name:<input type=text name=name><br>
-
<input type=submit value="Test the Form">
-
</form>
-
</body>
-
</html>
为了便于对比 post.html 与 get.html 几乎一摸一样,主要不同之处在粗体字部分,我们把method设为了“POST”。同样我们在 ID和Name栏中分别输入“111”和“scrum”,此时浏览器发送给服务器的HTTP请求行中,uri对应的数据不再是“/cgi-bin/test_get?id=111&name=scrum”,而是变成了“/cgi-bin/test-post”,如上面所述,参数的内容不再是通过HTTP请求行来传递,而是通过表单的数据内容来传递。
根据 CGI的规范,对于POST方法,我们在WEB服务器中需要根据表单所提交的数据的长度content_length,将其重定向为CGI程序的标准输入 stdin,这样CGI程序就可以通过stdin来得到客户端所提交的数据。
我们通过UNIX的管道机制 PIPE 来实现这种重定向的要求。对POST方法的具体逻辑处理如下:
- void exec_cgi(int fd, char *method, int content_length, char *filename, char *cgiargs)
-
{
-
char buf[MAXLINE], *emptylist[] = { NULL };
-
-
/* Return first part of HTTP response */
-
sprintf(buf, "HTTP/1.1 200 OK\r\n");
-
write(fd, buf, strlen(buf));
-
sprintf(buf, "Server: Mini Web Server\r\n");
-
write(fd, buf, strlen(buf));
-
-
if (fork() == 0) { /* child */
-
/*handle POST method*/
-
if (strcasecmp(method, "POST") == 0) {
-
int pfd[2];
-
int rc = pipe(pfd);
-
if (rc < 0) {
-
perror("pipe in POST failed");
-
exit(1);
-
}
-
int post_pid = fork();
-
if (post_pid == 0) {
-
close(pfd[0]);
-
int n = 0, bytes_read = 0;
-
/*only read length of "content_length"*/
-
while (n < content_length) {
-
bytes_read = read(fd, buf, sizeof(buf)-1);
-
printf("content read: %s \n", buf);
-
if (bytes_read > 0) {
-
write(pfd[1], buf, bytes_read);
-
n += bytes_read;
-
}
-
}
-
exit(0);
-
}
-
-
close(pfd[1]);
-
/*redirect to STDIN*/
-
dup2(pfd[0],STDIN_FILENO);
-
}
-
-
/* set CGI vars, only support "QUERY_STRING" and "CONTENT_LENGTH" */
-
setenv("QUERY_STRING", cgiargs, 1);
-
sprintf(buf, "%d", content_length);
-
setenv("CONTENT_LENGTH", buf);
-
dup2(fd, STDOUT_FILENO); /* Redirect stdout to client */
-
execve(filename, emptylist, environ); /* Run CGI program */
-
}
-
wait(NULL); /* Parent waits for and reaps child */
-
}
阅读(964) | 评论(0) | 转发(0) |