一个简单的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\n");
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\n");
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\n");
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\n");
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\n");
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 != '\n'; ) //查找一行末尾
{
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] == '\r' && 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\n");
}
#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\n");
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\r\n]*/
//查找一行末尾
pos = memchr(p, '\n', len);
if(*(pos-1) == '\r')
{
*(pos-1) = '\0';
}
*pos = '\0';
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 = '\0';
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, '\0');
JUMPOVER_CHAR(pos,'\0');//跳过空字符
len -= pos - p;
p = pos;
Request_HeaderParse(p, len, & req->ch);
DBGPRINT("URI:'%s',patch:'%s'\n",req->uri,req->rpath);
EXITRequest_Parse:
DBGPRINT("LCW<==Request_Parse\n");
return retval;
}
/******************************************************
函数名:Request_Handle(struct worker_ctl* wctl)
参数:
功能:处理并响应客户端请求
*******************************************************/
int Request_Handle(struct worker_ctl* wctl)
{
DBGPRINT("LCW==>Request_Handle\n");
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\n",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\n",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",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\n");
return 0;
}
一个简单的wed服务器SHTTPD(2)———— 客户端请求分析的更多相关文章
- 一个简单的wed服务器SHTTPD(3)————SHTTPD多客户端支持的实现
//start from the very beginning,and to create greatness //@author: Chuangwei Lin //@E-mail:979951191 ...
- 一个简单的wed服务器SHTTPD(9)————main函数文件,Makefile,头文件
主函数: #include "lcw_shttpd.h" //初始化时服务器的默认配置 extern struct conf_opts conf_para= { "/us ...
- 一个简单的wed服务器SHTTPD(5)————服务器SHTTPD请求方法解析
//start from the very beginning,and to create greatness //@author: Chuangwei Lin //@E-mail:979951191 ...
- 一个简单的wed服务器SHTTPD(1)————命令行和文件配置解析
开始学习<LInux网络编程>中的综合案例,虽然代码书上有,还是自己打一下加深理解和印象. 主要有两个函数,完成命令行的解析,另一个实现配置文件的解析,注释还是比较丰富的哦. //star ...
- 一个简单的wed服务器SHTTPD(4)————SHTTPD支持CGI的实现
//start from the very beginning,and to create greatness //@author: Chuangwei Lin //@E-mail:979951191 ...
- 一个简单的wed服务器SHTTPD(6)———— SHTTPD错误处理的实现
//start from the very beginning,and to create greatness //@author: Chuangwei Lin //@E-mail:979951191 ...
- 一个简单的wed服务器SHTTPD(8)———— URI分析
//start from the very beginning,and to create greatness //@author: Chuangwei Lin //@E-mail:979951191 ...
- 一个简单的wed服务器SHTTPD(7)———— SHTTPD内容类型的实现
//start from the very beginning,and to create greatness //@author: Chuangwei Lin //@E-mail:979951191 ...
- 一个简单的Web服务器-支持静态资源请求
目标 实现一个简单的Web服务器,能够根据HTTP请求的URL响应对应的静态资源,如果静态资源不存在则响应404. HttpServer 使用ServerSocket实现的一个服务器,request根 ...
随机推荐
- Alpha测试与Beta测试
粗略说一下Alpha测试与beta测试 1.Alpha测试 α测试是由一个用户在开发环境下进行的测试,也可以是公司内部的用户在模拟实际操作环境下进行的测试.α测试的目的是评价软件产品的功能.局域化.可 ...
- Mysql 临时表+视图
原文地址:http://www.cnblogs.com/mrdz/p/6195878.html 学习内容: 临时表和视图的基本操作... 临时表与视图的使用范围... 1.临时表 临时表:临时表, ...
- tf.nn.conv2d 卷积
tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, name=None) 第一个参数input:指需要做卷积的输入 ...
- web 应用 为啥 需要用到 tomcat 之类的 部署
首先了解C/s架构 比如我们常见的QQ,魔兽世界等 这种结构的程序是有服务器来提供服务的,客户端来使用服务 而B/S架构是这样的 它不需要安装客户端,只需要浏览器就可以了 例如QQ农场,这样对客户端的 ...
- AJ学IOS 之微博项目实战(13)发送微博调用相机里面的图片以及调用相机
AJ分享,必须精品 一:效果 二:代码 相机部分就简单多了,几行代码调用而已,但是如果你要是想实现更多丰富的功能,需要自己写.利用AssetsLibrary.framework,利用这个框架可以获得手 ...
- android学习笔记——使用QuickContactBadge关联联系人
本文大部分内容来自<疯狂android讲义>. QuickContactBadge继承了ImageView,因此它的本质也是图片,也可以通过android:src属性指定它显示的图片.Qu ...
- Laravel项目Linux服务器部署
laravel项目本地开发,一切正常.部署到服务器,首页都加载不出来,查了n多教程,各种方法姿势都试过了,还是不行. 功夫不负有心人,最后终于找到了问题所在,在此做个记录,铭记教训. 排查错误一定要: ...
- CVE-2019-0193 Apache solr velocity模块漏洞
Solr简单介绍 Solr是建立在Apache Lucene ™之上的一个流行.快速.开放源代码的企业搜索平台. Solr具有高度的可靠性,可伸缩性和容错能力,可提供分布式索引,复制和负载平衡查询,自 ...
- Laravel 5.8 RCE 分析
原帖地址 : https://xz.aliyun.com/t/6059 Laravel 代码审计 环境搭建 composer create-project --prefer-dist laravel/ ...
- HBase Filter 过滤器概述
abc 过滤器介绍 HBase过滤器是一套为完成一些较高级的需求所提供的API接口. 过滤器也被称为下推判断器(push-down predicates),支持把数据过滤标准从客户端下推到服务器,带有 ...