zoukankan      html  css  js  c++  java
  • 一个简单的wed服务器SHTTPD(2)———— 客户端请求分析

    //start from the very beginning,and to create greatness
    //@author: Chuangwei Lin
    //@E-mail:979951191@qq.com
    //@brief:客户端请求分析
    #include "lcw_shttpd.h"
    extern void Error_400(struct worker_ctl* wctl);
    extern void Error_403(struct worker_ctl* wctl);
    extern void Error_404(struct worker_ctl* wctl);
    extern void Error_505(struct worker_ctl* wctl);
    
    static struct http_header http_headers[] =
    {
        {16,    HDR_INT,    OFFSET(cl),            "Content-Length: "        },
        {14,    HDR_STRING,    OFFSET(ct),            "Content-Type: "        },
        {12,    HDR_STRING,    OFFSET(useragent),    "User-Agent: "            },
        {19,    HDR_DATE,    OFFSET(ims),        "If-Modified-Since: "    },
        {15,    HDR_STRING,    OFFSET(auth),        "Authorization: "        },
        {9,        HDR_STRING,    OFFSET(referer),    "Referer: "                },
        {8,        HDR_STRING,    OFFSET(cookie),        "Cookie: "                },
        {10,    HDR_STRING,    OFFSET(location),    "Location: "            },
        {8,        HDR_INT,    OFFSET(status),        "Status: "                },
        {7,        HDR_STRING,    OFFSET(range),        "Range: "                },
        {12,    HDR_STRING,    OFFSET(connection),    "Connection: "            },
        {19,    HDR_STRING,    OFFSET(transenc),    "Transfer-Encoding: "    },
        {0,        HDR_INT,    0,                    NULL                    }
    };
    extern struct vec _shttpd_methods[];
    struct conf_opts conf_para;
    /******************************************************
    函数名:montoi(char *s)
    参数:
    功能:将月份转化为数字
    *******************************************************/
    static int montoi(char *s)
    {
        DBGPRINT("LCW==>montoi
    ");
        int retval = -1;
        static char *ar[] =
         { //月份数组
            "Jan", "Feb", "Mar", "Apr", "May", "Jun",
            "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
        };
        size_t i;
        for (i = 0; i < sizeof(ar) / sizeof(ar[0]); i++)
        {
            if (!strcmp(s, ar[i]))
            {//遍历查找
                retval = i;
                goto EXITmontoi;
            }
        }    
        DBGPRINT("LCW<==montoi
    ");
    EXITmontoi:
        return retval;
    }
    /******************************************************
    函数名:date_to_epoch(char *s)
    参数:
    功能:Parse date-time string, and return the corresponding time_t value
    *******************************************************/
    static time_t date_to_epoch(char *s)
    {
        DBGPRINT("LCW==>date_to_epoch
    ");
        struct tm    tm;
        char mon[32];
        int    sec, min, hour, mday, month, year;
    
        (void) memset(&tm, 0, sizeof(tm));
        sec = min = hour = mday = month = year = 0;
    
        if (((sscanf(s, "%d/%3s/%d %d:%d:%d",&mday, mon, &year, &hour, &min, &sec) == 6) ||
         (sscanf(s, "%d %3s %d %d:%d:%d",&mday, mon, &year, &hour, &min, &sec) == 6) ||
         (sscanf(s, "%*3s, %d %3s %d %d:%d:%d", &mday, mon, &year, &hour, &min, &sec) == 6) ||
         (sscanf(s, "%d-%3s-%d %d:%d:%d",&mday, mon, &year, &hour, &min, &sec) == 6)) && (month = montoi(mon)) != -1)
        {
            tm.tm_mday    = mday;
            tm.tm_mon    = month;
            tm.tm_year    = year;
            tm.tm_hour    = hour;
            tm.tm_min    = min;
            tm.tm_sec    = sec;
        }
    
        if (tm.tm_year > 1900)
            tm.tm_year -= 1900;
        else if (tm.tm_year < 70)
            tm.tm_year += 100;
    
        DBGPRINT("LCW<==date_to_epoch
    ");
        return (mktime(&tm));
    }
    /******************************************************
    函数名:Request_HeaderParse(char *s, int len, struct headers *parsed)
    参数:
    功能:
    *******************************************************/
    void Request_HeaderParse(char *s, int len, struct headers *parsed)
    {
        DBGPRINT("LCW==>Request_HeaderParse
    ");
        struct http_header *h;//结构struct http_header指针
        union variant *v;//通用参数
        char *p,*e = s + len;//p当前位置,e尾部
        // 查找请求字符串中的头部关键字
        while (s < e) 
        {
            for (p = s; p < e && *p != '
    '; ) //查找一行末尾
            {
                p++;
            }
            for (h = http_headers; h->len != 0; h++)//已知方法
            { //最上面定义的那个结构体数组
                if (e - s > h->len && !strncasecmp(s, h->name, h->len))//字符串匹配
                {
                    break;
                }
            }
            if (h->len != 0) //将此方法放入
            {
                s += h->len;//请求字符串中值的位置
                v = (union variant *) ((char *) parsed + h->offset);//将值存放到参数parsed中
                // 根据头部选项不同,计算不同的值*/
                if (h->type == HDR_STRING) //字符串类型
                {
                    v->v_vec.ptr = s;//字符串开始
                    v->v_vec.len = p - s;//字符串长度
                    if (p[-1] == '
    ' && v->v_vec.len > 0)
                    {
                        v->v_vec.len--;
                    }
                } 
                else if (h->type == HDR_INT) //INT类型
                {
                    v->v_big_int = strtoul(s, NULL, 10);
                } 
                else if (h->type == HDR_DATE) //时间格式
                {
                    v->v_time = date_to_epoch(s);
                }
            }
    
            s = p + 1;//转到下一个头部
        }
        DBGPRINT("LCW<==Request_HeaderParse
    ");
    }
    #define JUMPOVER_CHAR(p,over) do{for(;*p== over;p++);}while(0);
    #define JUMPTO_CHAR(p,to) do{for(;* to;p++);}while(0);
    /******************************************************
    函数名:Request_Parse(struct worker_ctl *wctl)
    参数:
    功能:分析获得的请求
    *******************************************************/
    int Request_Parse(struct worker_ctl *wctl)
    {
        DBGPRINT("LCW==>Request_Parse
    ");
        struct worker_conn *c = &wctl->conn;
        struct conn_request *req = &c->con_req;
        struct conn_response *res = &c->con_res;
        int retval = 200;
        char *p = req->req.ptr;
        int len = req->req.len;
        char *pos = NULL;
        //处理第一行
        //[GET /root/default.html HTTP/1.1
    ]*/
        //查找一行末尾
        pos = memchr(p, '
    ', len);
        if(*(pos-1) == '
    ')
        {
            *(pos-1) = '';
        }
        *pos = '';
        pos = p;
        //方法    
        int found = 0;
        JUMPOVER_CHAR(pos,' ');//跳过空格
        struct vec *m= NULL;
        //查找比较方法字符串
        for(m = &_shttpd_methods[0];m->ptr!=NULL;m++)
        {
            if(!strncmp(m->ptr, pos, m->len))//比较字符串
            {
                req->method = m->type;//更新头部方法
                found = 1;
                break;
            }
        }
        if(!found)
        {
            retval = 400;
            goto EXITRequest_Parse;
        }
    
        //URI分析*/
        pos += m->len;//跳过方法
        JUMPOVER_CHAR(pos,' ');//跳过空格
        len -= pos -p;
        p = pos;
        JUMPTO_CHAR(pos, ' ');//跳到空格
        *pos = '';
        req->uri = (char*)p;
        //文件
        snprintf(req->rpath, URI_MAX, "%s/%s",conf_para.DocumentRoot, req->uri);
        res->fd = open(req->rpath, O_RDONLY , 0644);
        if(res->fd != -1)
        {
            fstat(res->fd, &res->fsate);    
            if(S_ISDIR(res->fsate.st_mode))
            {
                retval = 403;
                goto EXITRequest_Parse;
            }
        }
        else
        {
    
            retval = 404;
            goto EXITRequest_Parse;
        }
    
        //HTTP版本:
        //    HTTP/[1|0].[1|0|9]
        pos += 1;
        JUMPOVER_CHAR(pos,' ');//跳过空格
        len -= pos -p;
        p = pos;
        sscanf(p,"HTTP/%lu.%lu",&req->major, &req->minor);
        if(!((req->major == 0 && req->minor == 9)||(req->major == 1 && req->minor == 0)||(req->major == 1 && req->minor == 1)))
        {
            retval = 505;
            goto EXITRequest_Parse;
        }
        //其他头部信息
        JUMPTO_CHAR(pos, '');
        JUMPOVER_CHAR(pos,'');//跳过空字符
        len -= pos - p;
        p = pos;
        Request_HeaderParse(p, len, & req->ch);    
        DBGPRINT("URI:'%s',patch:'%s'
    ",req->uri,req->rpath);
    EXITRequest_Parse:
        DBGPRINT("LCW<==Request_Parse
    ");
        return retval;
    }
    /******************************************************
    函数名:Request_Handle(struct worker_ctl* wctl)
    参数:
    功能:处理并响应客户端请求
    *******************************************************/
    int Request_Handle(struct worker_ctl* wctl)
    {
        DBGPRINT("LCW==>Request_Handle
    ");
        int err = wctl->conn.con_req.err;        
        int cs = wctl->conn.cs;
        int cl = -1;
        char *ptr = wctl->conn.con_res.res.ptr;
        int len = -1;
        int n = -1;
        switch(err)
        {
            case 200:
                Method_Do(wctl);
                int fd = wctl->conn.con_res.fd;
                cl = wctl->conn.con_res.cl;
                len = strlen(wctl->conn.con_res.res.ptr);
                n = write(cs, ptr, len);
                printf("echo header:%s, write to client %d bytes, status:%d
    ",ptr,n,wctl->conn.con_res.status);
                if(fd != -1)
                {        
                    lseek(fd, 0, SEEK_SET);
                    len = sizeof(wctl->conn.dres);
                    printf("response len:%d, content length:%d
    ",len,wctl->conn.con_res.cl);
                    for(n = 0; cl>0; cl -= n)
                    {
                        n = read(fd,ptr,len>cl?cl:sizeof(wctl->conn.dres));
                        printf("read %d bytes,",n);
                        if(n > 0)
                        {
                            n =write(cs, ptr, n);
                            printf("write %d bytes
    ",n);
                        }
                    }
                    close(fd);
                    wctl->conn.con_res.fd = -1;
                }
    
                break;
            default:
            case 400:
                Error_400(wctl);
                cl = wctl->conn.con_res.cl;
                len = strlen(wctl->conn.con_res.res.ptr);        
                n = write(cs, ptr, len);            
                break;    
            case 403:
                Error_403(wctl);
                cl = wctl->conn.con_res.cl;
                len = strlen(wctl->conn.con_res.res.ptr);        
                n = write(cs, ptr, len);            
                break;    
            case 404:
                Error_404(wctl);
                cl = wctl->conn.con_res.cl;
                len = strlen(wctl->conn.con_res.res.ptr);    
                n = write(cs, ptr, len);            
                break;    
            case 505:
                Error_505(wctl);
                cl = wctl->conn.con_res.cl;
                len = strlen(wctl->conn.con_res.res.ptr);        
                n = write(cs, ptr, len);            
                break;            
        }
        DBGPRINT("LCW<==Request_Handle
    ");
        return 0;
    }
  • 相关阅读:
    Ubuntu设置文件默认打开方式
    车险与费用计算(仅做参考)
    房贷计算
    PHP敏感词处理
    记一次,接口pending
    layer confirm确认框,多个按钮
    crontab vim 模式
    git指定迁出目录
    mysql树形结构
    Kubeflow实战: 入门介绍与部署实践
  • 原文地址:https://www.cnblogs.com/sigma0-/p/12630525.html
Copyright © 2011-2022 走看看