目录
CGI定义
是用于WEB服务器和外部应用之间信息交换的标准接口。物理上是一段程序。
CGI功能
简单功能:计数器、生成包含日期、天气等的页面
中等难度的功能:图象映象、动画
高级任务:后端数据库操作、搜索引擎、多重动态页面
CGI编程
GET方法:
使用GET方法向CGI程序发送数据时,client端的数据是作为URL的一部分进行发送的。
WEB服务器通过QUERY_STRING将数据发送给相应的CGI程序。
REQUEST_METHOD为GET。
输入数据的长度有限制:由SERVER本身的buffer size决定 (一般用于同样输入产生同样结果的表单,如查询数据库)
POST方法
由标准输入将FORM表单数据传给CGI。
QUERY_STRING变量为空
传送数据的量由环境变量中的Content_length决定
REQUEST_METHOD为POST (POST方式用于每次请求都有不同结果输出的表单)
实战
服务器中的get响应cgi
1,将要get的数据(如url中的部分数据)放入到提前约定好的环境变量中
2,建立进程间通信,
3,调用第三方程序
服务器中的post响应cgi
1,创建一个子进程向当前进程输入信息(管道)
2,重定向(管道)到当前进程的标准输入
3,创建一个子进程,重定向这个子进程的标准输出到另一个通道
4,通过通道读取第二个子进程输出的内容
get方法服务端代码
void get_dynamic(int fd, char *filename, char *cgiargs)
{
char buf[MAXLINE], *emptylist[] = { NULL },httpsbuf[MAXLINE];
int p[2];
/* Return first part of HTTP response */
sprintf(buf, "HTTP/1.0 200 OK\r\n");
sprintf(buf, "%sServer: Tiny Web Server\r\n",buf);
#ifdef HTTPS
if(ishttps)
SSL_write(ssl,buf,strlen(buf));
else
#endif
Rio_writen(fd, buf, strlen(buf));
#ifdef HTTPS
if(ishttps)
{
Pipe(p);//进程间通信管道
if (Fork() == 0)
{ /* child */
Close(p[0]);
setenv("QUERY_STRING", cgiargs, 1); //设置内容到环境变量
Dup2(p[1], STDOUT_FILENO); /* 重定向子进程管道到标准输出 */
Execve(filename, emptylist, environ); /* 调用第三方子进程 */
}
Close(p[1]);
Read(p[0],httpsbuf,MAXLINE); /* 父进程读取管道中的内容 */
SSL_write(ssl,httpsbuf,strlen(httpsbuf));
}
else
#endif
{
if (Fork() == 0)
{ /* child */
/* Real server would set all CGI vars here */
setenv("QUERY_STRING", cgiargs, 1);
Dup2(fd, STDOUT_FILENO); /* Redirect stdout to client */
Execve(filename, emptylist, environ); /* Run CGI program */
}
}
//Wait(NULL); /* Parent waits for and reaps child */
}
get方法外部程序(c语言)例子
#include "wrap.h"
#include "parse.h"
int main(void)
{
char *buf, *p;
char name[MAXLINE], passwd[MAXLINE],content[MAXLINE];
/* 读取约定环境变量中的内容 */
if ((buf = getenv("QUERY_STRING")) != NULL) {
p = strchr(buf, '&');
*p = '\0';
strcpy(name, buf);
strcpy(passwd, p+1);
}
/* 输入内容到重定向后的标准输出 */
sprintf(content, "Welcome to auth.com:%s and %s\r\n<p>",name,passwd);
sprintf(content, "%s\r\n", content);
sprintf(content, "%sThanks for visiting!\r\n", content);
printf("Content-length: %d\r\n", strlen(content));
printf("Content-type: text/html\r\n\r\n");
printf("%s", content);
fflush(stdout);
exit(0);
}
post方法服务器端程序
static void post_dynamic(int fd, char *filename, int contentLength,rio_t *rp)
{
char buf[MAXLINE],length[32], *emptylist[] = { NULL },data[MAXLINE];
int p[2];
#ifdef HTTPS
int httpsp[2];
#endif
sprintf(length,"%d",contentLength);
memset(data,0,MAXLINE);
Pipe(p);
/* The post data is sended by client,we need to redirct the data to cgi stdin.
* so, child read contentLength bytes data from fp,and write to p[1];
* parent should redirct p[0] to stdin. As a result, the cgi script can
* read the post data from the stdin.
*/
/* 创建一个子进程向当前进程输入内容 */
if (Fork() == 0)
{ /* child */
Close(p[0]);
#ifdef HTTPS
if(ishttps)
{
Write(p[1],httpspostdata,contentLength);
}
else
#endif
{
Rio_readnb(rp,data,contentLength);
Rio_writen(p[1],data,contentLength);
}
exit(0) ;
}
/* Send response headers to client */
sprintf(buf, "HTTP/1.0 200 OK\r\n");
sprintf(buf, "%sServer: Tiny Web Server\r\n",buf);
#ifdef HTTPS
if(ishttps)
SSL_write(ssl,buf,strlen(buf));
else
#endif
Rio_writen(fd, buf, strlen(buf));
//Wait(NULL);
Dup2(p[0],STDIN_FILENO); /* 重定向管道 p[0] 到当前进程的标准输入 */
Close(p[0]);
Close(p[1]);
setenv("CONTENT-LENGTH",length , 1);
#ifdef HTTPS
if(ishttps) /* if ishttps,we couldnot redirct stdout to client,we must use SSL_write */
{
Pipe(httpsp);
if(Fork()==0)
{
Dup2(httpsp[1],STDOUT_FILENO); /* 重定向当前进程的标准输出到管道 */
Execve(filename, emptylist, environ);
}
//Wait(NULL);
Read(httpsp[0],data,MAXLINE);
SSL_write(ssl,data,strlen(data));
}
else
#endif
{
Dup2(fd,STDOUT_FILENO); /* Redirct stdout to client */
Execve(filename, emptylist, environ);
}
}
post方法外部程序(c语言)例子
#include "wrap.h"
#include "parse.h"
int main(void) {
char *buf,*p;
int length=0;
char content[MAXLINE],data[MAXLINE];
if ((buf = getenv("CONTENT-LENGTH")) != NULL)
{
length=atol(buf);
}
p=fgets(data,length+1,stdin);
if(p==NULL)
sprintf(content, "Something is wrong\r\n");
else
sprintf(content, "Info:%s\r\n",data);
printf("Content-length: %d\r\n", strlen(content));
printf("Content-type: text/html\r\n\r\n");
printf("%s", content);
fflush(stdout);
exit(0);
}