TKeed源码解析之几种头部字段的处理

前面已经对请求行和请求头进行了处理,还有对URI也进行了处理,也处理了资源找不到和资源不允许访问的情况。下面讲一下,对于请求头几种头部字段的处理,头部字段名有这几个类型:Host,Connection,If-Modified-Since和什么都没有;它们都有各自的处理函数。

Host:初始URL中的主机和端口。
Connection:表示是否需要持久连接。如果Servlet看到这里的值为“Keep-Alive”,或者看到请求使用的是HTTP 1.1(HTTP 1.1默认进行持久连接),它就可以利用持久连接的优点,当页面包含多个元素时(例如Applet,图片),显著地减少下载所需要的时间。要实现这一点,Servlet需要在应答中发送一个Content-Length头,最简单的实现方法是:先把内容写入ByteArrayOutputStream,然后在正式写出内容之前计算它的大小。

If-Modified-Since:只有当所请求的内容在指定的日期之后又经过修改才返回它,否则返回304“Not Modified”应答。

举例看下一个http请求行和请求头,如下:

GET /home.html HTTP/1.1
Host: developer.mozilla.org
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0) Gecko/20100101 Firefox/50.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://developer.mozilla.org/testpage.html
Connection: keep-alive
Upgrade-Insecure-Requests: 1
If-Modified-Since: Mon, 18 Jul 2016 02:36:04 GMT
If-None-Match: "c561c68d0ba92bbeb8b0fff2a9199f722e3a621a"
Cache-Control: max-age=0
tk_http_handle_header(request, out);
void tk_http_handle_header(tk_http_request_t* request, tk_http_out_t* out){
//将处理结果存储在out当中
    list_head* pos;//链表,存储一个请求的请求头中的头部字段名和值
    tk_http_header_t* hd;//是链表里面的节点,结点存储关键字起始位置和值起始位置,还有指向链表的指针
    tk_http_header_handle_t* header_in;//
    int len;
    list_for_each(pos, &(request->list)){
        hd = list_entry(pos, tk_http_header_t, list);//获取链表入口位置
        for(header_in = tk_http_headers_in; strlen(header_in->name) > 0; header_in++){
//将关键字依次与各种情况做比较,确定是哪个头部字段名,然后调用对应的处理函数。
            if(strncmp(hd->key_start, header_in->name, hd->key_end - hd->key_start) == 0){
                len = hd->value_end - hd->value_start;
                (*(header_in->handler))(request, out, hd->value_start, len);
                break;
            }    
        }
        list_del(pos);
        free(hd);
    }
}

上面用到了一个结构体,定义如下:

typedef struct tk_http_header_handle{
    char* name;
    tk_http_header_handler_pt handler;    // 函数指针
}tk_http_header_handle_t;

也用到了逐个访问链表节点的函数。

#define list_for_each(pos, head) \
    for (pos = (head)->next; pos != (head); pos = pos->next)

也用到了

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

#define container_of(ptr, type, member) ({                      \
        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
        (type *)( (char *)__mptr - offsetof(type,member) );     \
})

#define list_entry(ptr, type, member) \
    container_of(ptr, type, member)

还用到了一个其他文件里的数组,通过extern加载。

typedef int (*tk_http_header_handler_pt)(tk_http_request_t* request, tk_http_out_t* out, char* data, int len);
//定义了一个函数指针,指向的函数,返回值是int,输入参数:tk_http_request_t指针,tk_http_out_t指针,char指针,整型变量
typedef struct tk_http_header_handle{
    char* name;
    tk_http_header_handler_pt handler;    // 函数指针
}tk_http_header_handle_t;

tk_http_header_handle_t tk_http_headers_in[] = {
    {"Host", tk_http_process_ignore},
    {"Connection", tk_http_process_connection},
    {"If-Modified-Since", tk_http_process_if_modified_since},//判断文件是否修改过
    {"", tk_http_process_ignore}//什么都不做,返回0
};

typedef struct tk_http_out{
    int fd;
    int keep_alive;
    time_t mtime;
    int modified;
    int status;
}tk_http_out_t;

对应的几种处理函数。

static int tk_http_process_ignore(tk_http_request_t* request, tk_http_out_t* out, char* data, int len){
    (void) request;
    (void) out;
    (void) data;
    (void) len;
    return 0;
}


// 处理连接方式
static int tk_http_process_connection(tk_http_request_t* request, tk_http_out_t* out, char* data, int len){
    (void) request;
    // 记录请求是否为keep-alive
    if (strncasecmp("keep-alive", data, len) == 0) {
        out->keep_alive = 1;
    }
    return 0;
}

// 判断文件是否修改
static int tk_http_process_if_modified_since(tk_http_request_t* request, tk_http_out_t* out, char *data, int len){
    (void) request;
    (void) len;
    struct tm tm;
    // 转换data格式为GMT格式
    if(strptime(data, "%a, %d %b %Y %H:%M:%S GMT", &tm) == (char*)NULL){
        return 0;
    }
    // 将时间转换为自1970年1月1日以来持续时间的秒数
    time_t client_time = mktime(&tm);
    // 计算两个时刻之间的时间差
    double time_diff = difftime(out->mtime, client_time);
    // 微秒时间内未修改status显示未修改,modify字段置为1
    if(fabs(time_diff) < 1e-6){
        out->modified = 0;
        out->status = TK_HTTP_NOT_MODIFIED;
    }
    return 0;
}

根据时间判断文件是否修改,使用了strptime函数,它是linux系统函数,将一个字符串表示的时间,转换成time时间。

       #include <time.h>

       char *strptime(const char *s, const char *format, struct tm *tm);

其中tm结构体如下。

struct tm {
               int tm_sec;    /* Seconds (0-60) */
               int tm_min;    /* Minutes (0-59) */
               int tm_hour;   /* Hours (0-23) */
               int tm_mday;   /* Day of the month (1-31) */
               int tm_mon;    /* Month (0-11) */
               int tm_year;   /* Year - 1900 */
               int tm_wday;   /* Day of the week (0-6, Sunday = 0) */
               int tm_yday;   /* Day in the year (0-365, 1 Jan = 0) */
               int tm_isdst;  /* Daylight saving time */
           };

然后用到了

double difftime(time_t time1, time_t time2)
返回 time1 和 time2 之间相差的秒数 (time1 - time2)。这两个时间是在日历时间中指定的,表示了自纪元 Epoch(协调世界时 UTC:1970-01-01 00:00:00)起经过的时间。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值