Socket网络编程--简单Web服务器(4)

  上一小节已经实现了对图片的传输,接下来就是判断文件是否为js,css,png等格式。我们增加一个函数用于判断格式

 1 int WebServer::get_filetype(char *type,char *path)//用于判断该url指向文件的后缀
 2 {
 3     if(strstr(path,".html"))
 4         strcpy(type,"text/html");
 5     else if(strstr(path,".gif"))
 6         strcpy(type,"image/gif");
 7     else if(strstr(path,".jpg"))
 8         strcpy(type,"image/jpeg");
 9     else if(strstr(path,".png"))
10         strcpy(type,"image/png");
11     else if(strstr(path,".ico"))
12         strcpy(type,"image/x-icon");
13     else if(strstr(path,".js"))
14         strcpy(type,"text/javascript");
15     else if(strstr(path,".json"))
16         strcpy(type,"application/json");
17     else if(strstr(path,".css"))
18         strcpy(type,"text/css");
19     else
20         strcpy(type,"text/plain");
21     return 0;
22 }

  然后修改一下主页index.html的文件

 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     </body>
13 </html>

  两个外部文件如下

1 [myuser@bogon www]$ cat style.css
2 .ceshi {font-size:20px; color:#ff0000;}
3 [myuser@bogon www]$ cat javascript.js
4 function hi()
5 {
6     alert("js 调用,你单机了按钮");
7 }
8 [myuser@bogon www]$

  下面这个是运行的结果图

  用chrome浏览器的F12调试工具获取到的状态,可以看到,该网页可以获取到index.html,然后浏览器会根据这个页面再发送index.html文件所需要的外部文件的请求,从上面可以看出请求了style.css,javascript.js和ab.jpg图片。然后显示网页,我单击了那个button也是可以调用js脚本的。

  接下来就是判断一个提交是get还是post,网页index.html的源代码

 1     <body>
 2         <div class="ceshi">图片</div><img src="ab.jpg"></img>
 3         <input name="button" type="button" value="Click!" onclick=hi();></input>
 4 
 5         <hr>
 6         <br>使用post方式<br>
 7         <form method="post" name="frm1">
 8             <label>用户名:</label>
 9             <input type="text" name="username" />
10             <br>
11             <label>密码:</label>
12             <input type="password" name="password" />
13             <br>
14             <input type="submit" name="commit" value="登陆"/>
15             <br>
16         </form>
17         <hr>
18         <br>使用get方式<br>
19         <form method="get" name="frm1" action="index.html">
20             <label>用户名:</label>
21             <input type="text" name="username" />
22             <br>
23             <label>密码:</label>
24             <input type="password" name="password" />
25             <br>
26             <input type="submit" name="commit" value="登陆"/>
27             <br>
28         </form>
29     </body>

  修改后的ServerRequest函数

  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<<"\t\t"<<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]='\0';
 27     //取第一个与第二个单词之间的空格
 28     while(isspace(buf[j]) && (j<sizeof(buf)))
 29         j++;
 30 
 31     if(strcasecmp(method,"GET") && strcasecmp(method,"POST"))
 32     {
 33         Page_501(cli_fd);
 34         return -1;
 35     }
 36 
 37     if(strcasecmp(method,"GET")==0)
 38     {
 39         cout<<"此次请求的方式是GET方法"<<endl;
 40         cgi=0;
 41     }
 42     else if(strcasecmp(method,"POST")==0)
 43     {
 44         cout<<"此次请求的方式是POST方法"<<endl;
 45         cgi=2;
 46     }
 47 
 48     //截取第二个单词
 49     i=0;
 50     int flag=0;
 51     while(!isspace(buf[j]) && (i<sizeof(url)-1) && (j<sizeof(buf)))
 52     {
 53         if(buf[j]=='?')
 54         {
 55             flag=1;
 56             j++;
 57             i=0;
 58             url[i]='\0';
 59             cgi=(cgi==0?1:2);
 60             continue;
 61         }
 62         if(flag==0)
 63         {
 64             url[i]=buf[j];
 65             i++;j++;
 66         }
 67         else if(flag==1)
 68         {
 69             args[i]=buf[j];
 70             i++;j++;
 71         }
 72     }
 73     if(flag==0)
 74         url[i]='\0';
 75     else
 76         args[i]='\0';
 77 
 78     sprintf(path,"www%s",url);//这个是web服务器的主目录,这个以后可以处理成读取配置文件,这里就先写固定的www目录
 79     if(path[strlen(path)-1]=='/')
 80         strcat(path,"index.html");//同上
 81 
 82     //cout<<"============>此次请求的地址为:"<<path<<":"<<args<<endl;
 83 
 84     //根据文件名,获取该文件的文件信息。如果为-1,表示获取该文件失败
 85     if(stat(path,&st)==-1)
 86     {
 87         while((size>0) && strcmp("\n",buf))//去除掉多余的请求头信息
 88             size=get_line(cli_fd,buf,sizeof(buf));
 89         Page_404(cli_fd);
 90     }
 91     else
 92     {
 93         if(S_ISDIR(st.st_mode))//判断url地址,如果是个目录,那么就访问该目录的index.html
 94         {
 95             strcat(path,"/index.html");
 96             //cout<<"此次请求的地址为:"<<path<<endl;
 97         }
 98         if(!S_ISDIR(st.st_mode)&&((st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH)))//判断该url地址所对应的文件是否是可执行,并且是否有权限
 99         {
100             cgi=2;//是一个cgi程序
101         }
102         if(cgi==0)//如果cgi为0,那么就表示该url所对应的文件不是cgi程序,而是一个简单的静态页面
103         {
104             pid = fork();
105             if(pid==0)
106             {
107                 ServerCatHttpPage(cli_fd,path,st.st_size);
108             }
109         }
110         else if(cgi==1)//get方法带参数
111         {
112             pid=fork();
113             if(pid==0)
114             {
115                 while((size>0) && strcmp("\n",buf))//去除掉多余的请求头信息
116                     size=get_line(cli_fd,buf,sizeof(buf));
117                 ServerGetFunction(cli_fd,path,args);
118             }
119         }
120         else if(cgi==2)//post方法
121         {
122             pid=fork();
123             if(pid==0)
124             {
125                 int content_length=0;
126                 while((size>0) && strcmp("\n",buf))//去除掉多余的请求头信息
127                 {
128                     size=get_line(cli_fd,buf,sizeof(buf));
129                     buf[15]='\0';
130                     if(strcasecmp(buf,"Content-Length:")==0)
131                     {
132                         content_length=atoi(&(buf[16]));
133                     }
134                 }
135                 if(content_length==0)
136                 {
137                     Page_400(cli_fd);
138                     return 0;
139                 }
140                 char c;
141                 j=0;
142                 for(int i=0;i<content_length;i++)
143                 {
144                     recv(cli_fd,&c,1,0);
145                     args[j]=c;
146                     j++;
147                 }
148                 args[j]=0;
149                 ServerPostFunction(cli_fd,path,args);
150             }
151         }
152     }
153     close(cli_fd);
154     return 0;
155 }

  增加的两个处理cgi程序的函数(下小节实现)

 1 int WebServer::ServerGetFunction(int cli_fd,char *path,char *args)
 2 {
 3     cout<<"cli_fd:"<<cli_fd<<"  path:"<<path<<"  args:"<<args<<endl;
 4     Page_200(cli_fd);
 5     return 0;
 6 }
 7 int WebServer::ServerPostFunction(int cli_fd,char *path,char *args)
 8 {
 9     cout<<"cli_fd:"<<cli_fd<<"  path:"<<path<<"  args:"<<args<<endl;
10     Page_200(cli_fd);
11     return 0;
12 }

  下面这个是运行的结果

   从上图可以看出通过GET方法和POST方法都可以正常的获取到从表单那里传过去的参数。我们知道中文在url地址中的显示是显示成16进制的。这个是URL编码。接下来要实现对这个URL编码进行转换,这里使用网上别人提供的代码。

 1 #include <ctype.h>
 2 #include <string>
 3 #include <string.h>
 4 #include <stdio.h>
 5 #include <iostream>
 6 #include <stdlib.h>
 7 using namespace std;
 8 static int php_htoi(char *s)
 9 {
10     int value;
11     int c;
12 
13     c = ((unsigned char *)s)[0];
14     if (isupper(c))
15         c = tolower(c);
16     value = (c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10) * 16;
17 
18     c = ((unsigned char *)s)[1];
19     if (isupper(c))
20         c = tolower(c);
21     value += c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10;
22 
23     return (value);
24 }
25 /*
26  *URL解码,提取自PHP 5.2.17
27  *用法:string urldecode(string str_source)
28  *时间:2012-8-14 By Dewei
29  * */
30 string urldecode(string &str_source)
31 {
32     char const *in_str = str_source.c_str();
33     int in_str_len = strlen(in_str);
34     int out_str_len = 0;
35     string out_str;
36     char *str;
37 
38     str = strdup(in_str);
39     char *dest = str;
40     char *data = str;
41 
42     while (in_str_len--) {
43         if (*data == '+') {
44             *dest = ' ';
45         }
46         else if (*data == '%' && in_str_len >= 2 && isxdigit((int) *(data + 1))
47                 && isxdigit((int) *(data + 2))) {
48             *dest = (char) php_htoi(data + 1);
49             data += 2;
50             in_str_len -= 2;
51         } else {
52             *dest = *data;
53         }
54         data++;
55         dest++;
56     }
57     *dest = '\0';
58     out_str_len =  dest - str;
59     out_str = str;
60     free(str);
61     return out_str;
62 }
63 
64 int main()
65 {
66     string str="username=%E7%99%BB%E5%BD%95";
67     string out=urldecode(str);
68     cout<<out<<endl;
69     return 0;
70 }

  我们通过在传参的时候调用urldecode进行解码就可以实现中文显示了。

  这一节就到这里,下一小节将实现对cgi的支持。 

 

  参考资料: http://blog.csdn.net/xiaojianpitt/article/details/4389247

      : http://dewei.iteye.com/blog/1630969 (关于URL编码解码代码)

  本文地址: http://www.cnblogs.com/wunaozai/p/3945218.html

posted @ 2014-08-30 02:23  无脑仔的小明  阅读(1662)  评论(0编辑  收藏  举报