18.3.6 SHTTPD响应方法的实现

18.3.6  SHTTPD响应方法的实现

服务器SHTTPD可以识别的方法为GETPUTPOSTDELETEHEAD等,但仅实现了GET方法。在请求方法分析中已经可以获得客户端请求的方法,在响应中,只要匹配其方法就可以了。

1)方法的总函数为Method_Do(),实现如下:

 

void Method_Do(struct worker_ctl *wctl)

{

    DBGPRINT("==>Method_Do/n");

    if(0)

        Method_DoCGI(wctl);

    switch(wctl->conn.con_req.method)

    {

        case METHOD_PUT:

            Method_DoPut(wctl);

            break;

        case METHOD_DELETE:

            Method_DoDelete(wctl);

            break;

        case METHOD_GET:

            Method_DoGet(wctl);

            break;

        case METHOD_POST:

            Method_DoPost(wctl);

            break;

        case METHOD_HEAD:

            Method_DoHead(wctl);

            break;

        default:

            Method_DoList(wctl);

    }

    DBGPRINT("<==Method_Do/n");

}

 

2)请求结构的原型如下。主要用于解析客户端的请求,包括头部指针、uri指针、生成的真实地址、请求的类型、HTTP的主版本和副版本、头部结构等参数。代码如下:

 

struct conn_request{                /*请求结构*/

    struct vec    req;                /*请求向量*/

    char *head;                      /*请求头部'0'结尾*/

    char *uri;                       /*请求URI,'0'结尾*/

    char rpath[URI_MAX];          /*请求文件的真实地址'0'结尾*/

    int     method;                      /*请求类型*/

    /*HTTP的版本信息*/

    unsigned long major;          /*主版本*/

    unsigned long minor;          /*副版本*/

    struct headers ch;             /*头部结构*/

    struct worker_conn *conn;        /*连接结构指针*/

    int err;                        /*错误代码*/

};

 

3)其中的头部结构表示不含第一行的其他客户端请求信息。包含常用的头部信息,例如内容长度、内容类型、连接状态、最后修改时间、用户名称、用户代理、参考、Cookie、位置、请求的内容范围、状态值、编码类型等,其中每个成员均为向量型变量,包含表达的字符串和长度。原型如下:

 

struct headers {

    union variant    cl;             /*内容长度*/

    union variant    ct;             /*内容类型*/

    union variant    connection;      /*连接状态*/

    union variant    ims;            /*最后修改时间*/

    union variant    user;            /*用户名称*/

    union variant    auth;            /*权限*/

    union variant    useragent;       /*用户代理*/

    union variant    referer;     /*参考*/

    union variant    cookie;          /*Cookie*/

    union variant    location;        /*位置*/

    union variant    range;            /*范围*/

    union variant    status;          /*状态值*/

    union variant    transenc;        /*编码类型*/

};

 

4)响应结构,主要包含由服务器发往客户端时用到的部分参数,例如建立时间、超时时间、响应的状态值、响应的内容长度、请求文件描述符、请求文件的状态等。原型       如下:

 

struct conn_response{                           /*响应结构*/

    struct vec    res;                            /*响应向量*/

    time_t    birth_time;                          /*建立时间*/

    time_t    expire_time;                     /*超时时间*/

    int     status;                              /*响应状态值*/

    int     cl;                                 /*响应内容长度*/

    int         fd;                                 /*请求文件描述符*/

    struct stat fsate;                          /*请求文件状态*/

    struct worker_conn *conn;                    /*连接结构指针*/   

};

 

其中Method_DoGet()函数整理得到响应的头部,并将客户端申请资源的内容长度放到成员变量cl中,便于之后的使用。Method_DoGet()函数的头部数据信息为如下形式的字       符串。

 

[HTTP/1.1 200 OK                              /*第一行*/

Date: Thu, 11 Dec 2008 11:25:33 GMT         /*时间*/

Last-Modified: Wed, 12 Nov 2008 09:00:01 GMT /*修改时间*/

Etag: "491a2a91.2afe"                          /*Web资源标记号*/

Content-Type: text/plain                       /*文件类型*/

Content-Length: 11006                           /*内容长度*/

Accept-Ranges: bytes]                          /*接收范围*/

 

5Method_DoGet()函数先初始化一些参数,例如状态值,状态信息等。

 

static int Method_DoGet(struct worker_ctl *wctl)

{

    DBGPRINT("==>Method_DoGet/n");

    struct conn_response *res = &wctl->conn.con_res;

    struct conn_request *req = &wctl->conn.con_req;

    char path[URI_MAX];

    memset(path, 0, URI_MAX);

    size_t       n;

    unsigned long    r1, r2;

    char    *fmt = "%a, %d %b %Y %H:%M:%S GMT";

    /*需要确定的参数*/

    size_t status = 200;                        /*状态值,已确定*/

    char *msg = "OK";                            /*状态信息,已确定*/

    char  date[64] = "";                     /*时间*/

    char  lm[64] = "";                         /*请求文件最后修改信息*/

    char  etag[64] = "";                     /*etag信息*/

    big_int_t cl;                                /*内容长度*/

    char  range[64] = "";                       /*范围*/ 

    struct mine_type *mine = NULL;

 

6)之后获得构建头部需要的数据,例如当前时间、最后修改时间、ETAG、内容类型、内容长度及范围等数据。

 

/*当前时间*/

time_t t = time(NULL); 

(void) strftime(date,

            sizeof(date),

            fmt,

            localtime(&t));

/*最后修改时间*/

(void) strftime(lm,

            sizeof(lm),

            fmt,

            localtime(&res->fsate.st_mtime));

/*ETAG*/

(void) snprintf(etag,

            sizeof(etag),

            "%lx.%lx",

            (unsigned long) res->fsate.st_mtime,

            (unsigned long) res->fsate.st_size);

 

/*发送的MIME类型*/

mine = Mine_Type(req->uri, strlen(req->uri), wctl);

/*内容长度*/

cl = (big_int_t) res->fsate.st_size;

/*范围range*/

memset(range, 0, sizeof(range));

n = -1;

if (req->ch.range.v_vec.len > 0 )        /*取出请求范围*/

{

    printf("request range:%d/n",req->ch.range.v_vec.len);

    n = sscanf(req->ch.range.v_vec.ptr,"bytes=%lu-%lu",&r1, &r2);

}

printf("n:%d/n",n);

if(n   > 0)

{

status = 206;

    (void) fseek(res->fd, r1, SEEK_SET);

    cl = n == 2 ? r2 - r1 + 1: cl - r1;

    (void) snprintf(range,

                sizeof(range),

                "Content-Range: bytes %lu-%lu/%lu/r/n",

                r1,

                r1 + cl - 1,

                (unsigned long) res->fsate.st_size);

    msg = "Partial Content";

}

 

7)最后根据各种数据构建输出的头部数据。

 

    /*构建输出的头部*/

    memset(res->res.ptr, 0, sizeof(wctl->conn.dres));

    snprintf(

        res->res.ptr,                    /*缓冲区*/

        sizeof(wctl->conn.dres),        /*缓冲区长度*/

        "HTTP/1.1 %d %s/r/n"             /*状态和状态信息*/

        "Date: %s/r/n"                 /*日期*/

        "Last-Modified: %s/r/n"         /*最后修改时间*/

        "Etag: /"%s/"/r/n"              /*Web资源标记号*/

        "Content-Type: %.*s/r/n"        /*内容类型*/

        "Content-Length: %lu/r/n"        /*内容长度*/

        "Accept-Ranges: bytes/r/n"       /*发送范围*/

        "%s/r/n",                        /*范围起始*/

        status,                          /*状态值*/

        msg,                            /*状态信息*/

        date,                            /*日期*/

        lm,                             /*最后修改时间*/

        etag,                            /*Web资源标记号*/

        strlen(mine->mime_type),        /*内容类型长度*/

        mine->mime_type,              /*内容类型*/

        cl,                             /*内容长度*/

        range);                          /*范围*/

    res->cl = cl;

    res->status = status;

    DBGPRINT("<==Method_DoGet/n");

    return 0;

}

你可能感兴趣的:(Date,struct,服务器,delete,Path,etag)