zoukankan      html  css  js  c++  java
  • 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<<"		"<<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]='';
     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]='';
     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]='';
     75     else
     76         args[i]='';
     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("
    ",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("
    ",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("
    ",buf))//去除掉多余的请求头信息
    127                 {
    128                     size=get_line(cli_fd,buf,sizeof(buf));
    129                     buf[15]='';
    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 = '';
    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

  • 相关阅读:
    大工程(bzoj 3611)
    消耗战(bzoj 2286)
    Computer(hdu 2196)
    文件排版(codevs 1300)
    洛谷 P2015 二叉苹果树
    洛谷 P2014 选课
    洛谷 P1352 没有上司的舞会
    COGS 505. 城市
    洛谷 P1306 斐波那契公约数
    洛谷 P1962 斐波那契数列
  • 原文地址:https://www.cnblogs.com/wunaozai/p/3945218.html
Copyright © 2011-2022 走看看