这一小节我们将实现服务器对get和post的请求进行对cgi程序的调用。对于web服务器以前的章节已经实现了对get和post请求的调用接口,接下来给出对应接口的实现。
1 int WebServer::ServerGetFunction(int cli_fd,char *path,char *args) 2 { 3 ServerExecuteCGI(cli_fd,path,args); 4 return 0; 5 } 6 int WebServer::ServerPostFunction(int cli_fd,char *path,char *args) 7 { 8 ServerExecuteCGI(cli_fd,path,args); 9 return 0; 10 } 11 12 int WebServer::ServerExecuteCGI(int cli_fd,char *path,char *args) 13 { 14 char query_env[1024]; 15 char type[16]="text/html"; 16 pid_t pid; 17 int status; 18 int cgi_output[2]; 19 int cgi_input[2]; 20 21 if(pipe(cgi_output)<0) 22 { 23 Page_500(cli_fd); 24 return 0; 25 } 26 if(pipe(cgi_input)<0) 27 { 28 Page_500(cli_fd); 29 return 0; 30 } 31 32 if((pid=fork())<0) 33 { 34 Page_500(cli_fd); 35 return 0; 36 } 37 if(pid==0)//child 38 { 39 dup2(cgi_output[1],1);//cgi的输出端绑定文件描述符为1的输出端 40 dup2(cgi_input[0],0); 41 close(cgi_output[0]); 42 close(cgi_input[1]); 43 sprintf(query_env,"QUERY_STRING=%s",args); 44 putenv(query_env); 45 execl(path,path,args); 46 exit(0); 47 } 48 else //parent 49 { 50 char c; 51 close(cgi_output[1]);//取消绑定 52 close(cgi_input[0]); 53 Page_Headers(cli_fd,type,0); 54 while(read(cgi_output[0],&c,1)>0) 55 send(cli_fd,&c,1,0); 56 close(cgi_output[0]); 57 close(cgi_input[1]); 58 } 59 waitpid(pid,&status,0); 60 return 0; 61 }
然后我们写一个hello.c的文件然后编译成hello可执行文件(要保证权限是可执行的)
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 int main(int argc,char **args) 5 { 6 char *data; 7 printf("Hello "); 8 printf("%s:%s ",args[0],args[1]); 9 data=getenv("QUERY_STRING"); 10 printf("query_string::%s ",data); 11 return 0; 12 }
然后在浏览器输入以下网址,然后查看执行结果
成功的执行c程序了。下面就做一个完整的例子,做一个用于登录的例子。
1 <html> 2 <head> 3 <title>Test</title> 4 <meta http-equiv="Content-Type" content="text/html ; charset=utf-8"> 5 <link rel="stylesheet" href="style.css" type="text/css"/> 6 <script language="javascript" src="javascript.js"></script> 7 </head> 8 9 <body> 10 <div class="ceshi">图片</div><img src="ab.jpg"></img> 11 <input name="button" type="button" value="Click!" onclick=hi();></input> 12 13 <hr> 14 <br>使用post方式<br> 15 <form method="post" name="frm1" action="hello"> 16 <label>用户名:</label> 17 <input type="text" name="username" /> 18 <br> 19 <label>密码:</label> 20 <input type="password" name="password" /> 21 <br> 22 <input type="submit" name="commit" value="登陆"/> 23 <br> 24 </form> 25 <hr> 26 <br>使用get方式<br> 27 <form method="get" name="frm1" action="hello"> 28 <label>用户名:</label> 29 <input type="text" name="username" /> 30 <br> 31 <label>密码:</label> 32 <input type="password" name="password" /> 33 <br> 34 <input type="submit" name="commit" value="登陆"/> 35 <br> 36 </form> 37 </body> 38 </html>
然后在当前目录下有个hello.c程序
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 5 int split(char **arr,char *str,const char*del) 6 { 7 char *s=NULL; 8 int i=0; 9 s=strtok(str,del); 10 while(s!=NULL) 11 { 12 *arr++=s; 13 s=strtok(NULL,del); 14 i++; 15 } 16 return i; 17 } 18 19 void split_key(char *ch,char *key,char *value) 20 { 21 int len; 22 int i; 23 int j; 24 len=strlen(ch); 25 j=0; 26 for(i=0;i<len;i++) 27 { 28 if(ch[i]=='=') 29 { 30 i++; 31 break; 32 } 33 key[j]=ch[i]; 34 j++; 35 } 36 key[j]=0; 37 j=0; 38 for(;i<len;i++) 39 { 40 value[j]=ch[i]; 41 j++; 42 } 43 value[j]=0; 44 return ; 45 } 46 47 int main(int argc,char **args) 48 { 49 char *data; 50 char *myargs[32]; 51 int cnt=0; 52 int i; 53 char key[32],value[32]; 54 char username[32],password[32]; 55 memset(myargs,0,sizeof(myargs)); 56 cnt=split(myargs,args[1],"&"); 57 58 for(i=0;i<cnt;i++) 59 { 60 split_key(myargs[i],key,value); 61 if(strcmp(key,"username")==0) 62 strcpy(username,value); 63 if(strcmp(key,"password")==0) 64 strcpy(password,value); 65 } 66 67 //这里可以写上完整的网页 68 if(strcmp(username,"admin")==0 && strcmp(password,"123456")==0) 69 { 70 printf("<p>登陆成功</p>"); 71 } 72 else 73 { 74 printf("<p>登陆失败</p>"); 75 } 76 return 0; 77 }
ServerRequest函数修改了一些BUG后的代码

1 int WebServer::ServerRequest(int cli_fd) 2 { 3 char buf[1024]; 4 int size=1024; 5 int i,j; 6 char method[255];//用于保存请求方式 7 char url[512]; 8 char path[1024]; 9 char args[1024]; 10 struct stat st; 11 int cgi;//cgi 为0 表示get普通方法 1表示get带参方法 2表示post方法 12 pid_t pid; 13 memset(buf,0,sizeof(buf)); 14 cgi=0; 15 //获取第一行请求信息 一般格式为: GET / HTTP/1.1 16 // POST / HTTP/1.1 17 size=get_line(cli_fd,buf,sizeof(buf)); 18 //cout<<" "<<buf<<endl; 19 i=0,j=0; 20 //截取第一个单词 21 while(!isspace(buf[j]) && (i<sizeof(method)-1)) 22 { 23 method[i]=buf[j]; 24 i++;j++; 25 } 26 method[i]='