基于多反应堆的高并发服务器【C/C++/Reactor】(中)HttpRequest模块 解析http请求协议

一、HTTP响应报文格式

HTTP/1.1 200 OK
Bdpagetype: 1
Bdqid: 0xf3c9743300024ee4
Cache-Control: private
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html;charset=utf-8
Date: Fri, 26 Feb 2021 08:44:35 GMT
Expires: Fri, 26 Feb 2021 08:44:35 GMT
Server: BWS/1.1
Set-Cookie: BDSVRTM=13; path=/
Set-Cookie: BD_HOME=1; path=/
Set-Cookie: H_PS_PSSID=33514_33257_33273_31660_33570_26350; path=/; domain=.baidu.com
Strict-Transport-Security: max-age=172800
Traceid: 1614329075128412289017566699583927635684
X-Ua-Compatible: IE=Edge,chrome=1
Transfer-Encoding: chunked

二、根据解析出的原始数据,对客户端的请求做出处理 processHttpRequest 

// 处理http请求协议
bool processHttpRequest(struct HttpRequest* req,struct HttpResponse* response);
// 处理基于get的http请求
bool processHttpRequest(struct HttpRequest* req,struct HttpResponse* response) {if(strcasecmp(req->method,"get") != 0) {return -1;}decodeMsg(req->url,req->url); // 解码字符串// 处理客户端请求的静态资源(目录或者文件)char* file = NULL;if(strcmp(req->url,"/") == 0) {file = "./";}else {file = req->url + 1;}// 获取文件属性struct stat st;int ret = stat(file,&st);if(ret == -1) {// 文件不存在 -- 回复404// sendHeadMsg(cfd,404,"Not Found",getFileType(".html"),-1);// sendFile("404.html",cfd);strcpy(response->fileName,"404.html");response->statusCode = NotFound;strcpy(response->statusMsg,"Not Found");// 响应头httpResponseAddHeader(response,"Content-Type",getFileType(".html"));response->sendDataFunc = sendFile;return 0;}strcpy(response->fileName,file);response->statusCode = OK;strcpy(response->statusMsg,"OK!");// 判断文件类型if(S_ISDIR(st.st_mode)) {// 把这个目录中的内容发送给客户端// sendHeadMsg(cfd,200,"OK",getFileType(".html"),-1);// sendDir(file,cfd);// 响应头httpResponseAddHeader(response,"Content-Type",getFileType(".html"));response->sendDataFunc = sendDir;}else {// 把文件的内容发送给客户端// sendHeadMsg(cfd,200,"OK",getFileType(file),st.st_size);// sendFile(file,cfd);// 响应头char tmp[12] = {0};sprintf(tmp,"%ld",st.st_size);httpResponseAddHeader(response,"content-type",getFileType(file));httpResponseAddHeader(response,"content-length",tmp);response->sendDataFunc = sendFile;}return 0;
}

1.解码字符串  

  • 解决浏览器无法访问带特殊字符的文件得到问题
// 将字符转换为整型数
int hexToDec(char c){if (c >= '0' && c <= '9')return c - '0';if (c >= 'a' && c <= 'f')return c - 'a' + 10;if (c >= 'A' && c <= 'F')return c - 'A' + 10;return 0;
}// 解码字符串
// to 存储解码之后的数据, 传出参数, from被解码的数据, 传入参数
void decodeMsg(char* to,char* from) {for(;*from!='\0';++to,++from) {// isxdigit -> 判断字符是不是16进制格式, 取值在 0-f// Linux%E5%86%85%E6%A0%B8.jpgif(from[0] == '%' && isxdigit(from[1]) && isxdigit(from[2])){// 将16进制的数 -> 十进制 将这个数值赋值给了字符 int -> char// B2 == 178// 将3个字符, 变成了一个字符, 这个字符就是原始数据// *to = (hexToDec(from[1]) * 16) + hexToDec(from[2]);*to = (hexToDec(from[1]) << 4) + hexToDec(from[2]);// 跳过 from[1] 和 from[2] ,因此在当前循环中已经处理过了from += 2;}else{// 字符拷贝,赋值*to = *from;}}*to = '\0';
}

2.判断文件扩展名,返回对应的 Content-Type(Mime-Type)

const char* getFileType(const char* name);
const char* getFileType(const char* name) {// a.jpg a.mp4 a.html// 自右向左查找 '.' 字符,如不存在返回NULLconst char* dot = strrchr(name,'.');if(dot == NULL) return "text/plain; charset=utf-8";//纯文本if(strcmp(dot,".html") == 0 || strcmp(dot,".htm") == 0) return "text/html; charset=utf-8";if(strcmp(dot,".jpg")==0 || strcmp(dot,".jpeg")==0) return "image/jpeg";if(strcmp(dot,".gif")==0)return "image/gif";if(strcmp(dot,".png")==0)return "image/png";if(strcmp(dot,".css")==0) return "text/css";if(strcmp(dot,".au")==0)return "audio/basic";if(strcmp(dot,".wav")==0)return "audio/wav";if(strcmp(dot,".avi")==0)return "video/x-msvideo";if(strcmp(dot,".mov")==0 || strcmp(dot,".qt")==0)return "video/quicktime";if(strcmp(dot,".mpeg")==0 || strcmp(dot,".mpe")==0)return "video/mpeg";if(strcmp(dot,".vrml")==0 || strcmp(dot,".wrl")==0)return "model/vrml";if(strcmp(dot,".midi")==0 || strcmp(dot,".mid")==0)return "audio/midi";if(strcmp(dot,".mp3")==0)return "audio/mpeg";if(strcmp(dot,".ogg") == 0) return "application/ogg";if(strcmp(dot,".pac") == 0)return "application/x-ns-proxy-autoconfig";if(strcmp(dot,".pdf") == 0)return "application/pdf";return "text/plain; charset=utf-8";//纯文本
}

3.发送文件  sendFile

// 发送文件
void sendFile(const char* fileName,struct Buffer* sendBuf,int cfd);
void sendFile(const char* fileName,struct Buffer* sendBuf,int cfd) {// 打开文件int fd = open(fileName,O_RDONLY);assert(fd > 0); 
#if 1while (1) {char buf[1024];int len = read(fd,buf,sizeof(buf));if(len > 0) {// send(cfd,buf,len,0);bufferAppendData(sendBuf,buf,len);}else if(len == 0) {break;}else{close(fd);perror("read");}}
#else// 把文件内容发送给客户端off_t offset = 0;int size = lseek(fd,0,SEEK_END);// 文件指针移动到了尾部lseek(fd,0,SEEK_SET);// 移动到文件头部while (offset < size){int ret = sendfile(cfd,fd,&offset,size - offset);printf("ret value: %d\n",ret);if (ret == -1 && errno == EAGAIN) {printf("没数据...\n");}}
#endifclose(fd);
}

4.发送目录

// 发送目录
void sendDir(const char* dirName,struct Buffer* sendBuf,int cfd); 
void sendDir(const char* dirName,struct Buffer* sendBuf,int cfd) {char buf[4096] = {0};sprintf(buf,"<html><head><title>%s</title></head><body><table>",dirName);struct dirent** nameList;int num = scandir(dirName,&nameList,NULL,alphasort);for(int i=0;i<num;i++) {// 取出文件名 nameList 指向的是一个指针数组 struct dirent* tmp[]char* name = nameList[i]->d_name;struct stat st;char subPath[1024] = {0};sprintf(subPath,"%s/%s",dirName,name);stat(subPath,&st);if(S_ISDIR(st.st_mode)) {// 从当前目录跳到子目录里边,/sprintf(buf+strlen(buf),"<tr><td><a href=\"%s/\">%s</a></td><td>%ld</td></tr>",name,name,st.st_size);}else{sprintf(buf+strlen(buf),"<tr><td><a href=\"%s\">%s</a></td><td>%ld</td></tr>",name,name,st.st_size);}// send(cfd,buf,strlen(buf),0);bufferAppendString(sendBuf,buf);memset(buf,0,sizeof(buf));free(nameList[i]); } sprintf(buf,"</table></body></html>");// send(cfd,buf,strlen(buf),0);bufferAppendString(sendBuf,buf);free(nameList);
}

三、解析http请求协议 parseHttpRequest  

可以看这篇关于httpResponsePrepareMsg函数具体是如何组织响应数据的:HttpResponse的定义和初始化 以及组织 HttpResponse 响应消息icon-default.png?t=N7T8https://blog.csdn.net/weixin_41987016/article/details/135464760

// 解析http请求协议
bool parseHttpRequest(struct HttpRequest* req,struct Buffer* readBuf,struct HttpResponse* response,struct Buffer* sendBuf,int socket);
// 解析http请求协议
bool parseHttpRequest(struct HttpRequest* req,struct Buffer* readBuf,struct HttpResponse* response,struct Buffer* sendBuf,int socket) {bool flag = true;while(req->curState!=ParseReqDone) {switch(req->curState) {case ParseReqLine:// 解析请求行flag = parseHttpRequestLine(req,readBuf);break;case ParseReqHeaders:// 解析请求头flag = parseHttpRequestHeader(req,readBuf);break;case ParseReqBody:break;default:break;}if(!flag) {return flag;}// 判断是否解析完毕了,如果完毕了,需要准备回复的数据if(req->curState==ParseReqDone) {// 1.根据解析出的原始数据,对客户端的请求做出处理processHttpRequest(req,response);// 2.组织响应数据并发送给客户端httpResponsePrepareMsg(response,sendBuf,socket);}}req->curState = ParseReqLine;// 状态还原,保证还能继续处理第二条及以后的请求return flag;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/607014.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

今日实践 — 附加数据库/重定向失败如何解决?

WMS数据库与重定向 前言正文如何建立数据库连接&#xff1f;第一步&#xff1a;打开SSMS&#xff0c;右击数据库&#xff0c;点击附加第二步&#xff1a;点击添加第三步&#xff1a;找到自己的数据库文件&#xff0c;点击确定按钮第四步&#xff1a;若有多个数据库&#xff0c;…

如何使用静态IP代理解决Facebook多账号注册并进行网络推广业务?

在当今的数字时代&#xff0c;社交媒体成为了企业进行网络推广的一个重要途径&#xff0c;其中&#xff0c;Facebook是最受欢迎的社交媒体之一&#xff0c;因为它可以让企业通过创建广告和页面来推广他们的产品或服务。 但是&#xff0c;使用Facebook进行网络推广时&#xff0…

【代码复现系列】paper:CycleGAN and pix2pix in PyTorch

或许有冗余步骤、之后再优化。 1.桌面右键-git bash-输入命令如下【git clone https://github.com/junyanz/pytorch-CycleGAN-and-pix2pix】 2.打开anaconda的prompt&#xff0c;cd到pytorch-CycleGAN-and-pix2pix路径 3.在prompt里输入【conda env create -f environment.y…

基于YOLOv7开发构建道路交通场景下CCTSDB2021交通标识检测识别系统

交通标志检测是交通标志识别系统中的一项重要任务。与其他国家的交通标志相比&#xff0c;中国的交通标志有其独特的特点。卷积神经网络&#xff08;CNN&#xff09;在计算机视觉任务中取得了突破性进展&#xff0c;在交通标志分类方面取得了巨大的成功。CCTSDB 数据集是由长沙…

OpenFeign超时控制

OpenFeign超时控制 前面简单介绍了Feign和OpenFeign的关系&#xff0c;言归正传&#xff0c;接下来我们看看OpenFeign如何设置调用超时&#xff0c;openFeign其实是有默认的超时时间的&#xff0c;默认分别是连接超时时间10秒、读超时时间60秒&#xff0c;源码在feign.Request…

十九:爬虫最终篇-平安银行商城实战

平安银行商场实战 需求 获取该商城商品信息 目标网址 https://m.yqb.com/bank/product-item-50301196.html?mcId1583912328849970&loginModepab&historyy&sceneModem&traceid30187_4dXJVel1iop详细步骤 1、寻找数据接口 2、对比payload寻找可疑参数 3、多…

图像融合论文阅读:CrossFuse: 一种基于交叉注意机制的红外与可见光图像融合方法

article{li2024crossfuse, title{CrossFuse: A novel cross attention mechanism based infrared and visible image fusion approach}, author{Li, Hui and Wu, Xiao-Jun}, journal{Information Fusion}, volume{103}, pages{102147}, year{2024}, publisher{Elsevier} } 论文…

当试图回复传入消息时,消息应用程序会闪烁

问题描述&#xff1a; Actual Results: Unable to reply for incoming message as Messaging app flickers and closes. Expected Results: User should be able to send reply for incoming messages. Reproduction Steps: Stay in home screen. Receive an incoming mes…

如何在 Ubuntu 20.04 上安装和使用 Docker

前些天发现了一个人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;最重要的屌图甚多&#xff0c;忍不住分享一下给大家。点击跳转到网站。 如何在 Ubuntu 20.04 上安装和使用 Docker 介绍 Docker是一个可以简化容器中应用程序进程管理过程的应用程序。…

拦截器HandlerInterceptor | springmvc系列

拦截器&#xff0c;通俗来来将&#xff0c;就是我们将访问某个路径的请求给拦截下来&#xff0c;然后可以对这个请求做一些操作 基本使用 创建拦截器类 让类实现HandlerInterceptor接口&#xff0c;重写接口中的三个方法。 Component //定义拦截器类&#xff0c;实现Handle…

Python实现PowerPoint(PPT/PPTX)到PDF的批量转换

演示文稿是一种常见传达信息、展示观点和分享内容的形式&#xff0c;特别是PowerPoint演示文稿&#xff0c;广泛应用于各行各业&#xff0c;几乎是演讲等场合的必备工具。然而&#xff0c;演示文稿也有其限制&#xff0c;对设备的要求较高&#xff0c;且使用不同的软件或设备演…

Ubuntu下AI4Green开源ELN服务的简单部署

主部署程序&#xff1a;AI4Green 配置参考这篇文档&#xff1a;AI4Green开源ELN&#xff08;电子实验记录本&#xff09;-CSDN博客 流量转发和负载均衡&#xff1a;使用Nginx 配置参考这篇文档&#xff1a;Nginx负载均衡-CSDN博客 SSL配置部分参考这篇文档&#xff1a; 设置…

SpringBoot-开启Actuator监控

Spring Boot Actuator是Spring Boot提供的一种管理和监控应用程序的框架&#xff0c;可以帮助我们了解应用程序的运行状况&#xff0c;提供HTTP端点来暴露应用程序的不同方面&#xff0c;如健康状况、指标、日志和运行时信息等。 开启Actuator监控&#xff0c;我们可以通过HTT…

Hyperledger Fabric 核心概念与组件

要理解超级账本 Fabric 的设计&#xff0c;首先要掌握其最基本的核心概念与组件&#xff0c;如节点、交易、排序、共识、通道等。 弄清楚这些核心组件的功能&#xff0c;就可以准确把握 Fabric 的底层运行原理&#xff0c;深入理解其在架构上的设计初衷。知其然&#xff0c;进…

回顾2023编程之旅

一、前言 看在给了我一个博客专家的份上就继续写写博客&#xff0c;实事求是的讲如果是工作之余去总结csdn写写技术博客&#xff0c;还想混个专家什么的&#xff0c;真的是精力不够。因为里面的灌水的实在太多&#xff0c;比不过的&#xff0c;写这个玩意必须得淡泊名利才能悠然…

部署一款开源的交互审计系统—Next Terminal

博客地址 部署一款开源的交互审计系统—Next Terminal-雪饼 (xue6ing.cn)https://xue6ing.cn/archives/bu-shu-yi-kuan-kai-yuan-de-jiao-hu-shen-ji-xi-tong--next-terminal Next Terminal是什么&#xff1f; Next Terminal是一个开源的交互审计系统&#xff0c;具有以下主…

控制台console

js控制台打印 console.log()和console.group() console.group()指的是消息组的开始&#xff0c;在此之后的所有消息将写进该消息组中&#xff0c; console.groupEnd()指的是该消息组的结束&#xff0c;

SpringBoot请求参数加密、响应参数解密

SpringBoot请求参数加密、响应参数解密 1.说明 在项目开发工程中&#xff0c;有的项目可能对参数安全要求比较高&#xff0c;在整个http数据传输的过程中都需要对请求参数、响应参数进行加密&#xff0c;也就是说整个请求响应的过程都是加密处理的&#xff0c;不在浏览器上暴…

40道java集合面试题含答案(很全)

点击下载《40道java集合面试题含答案&#xff08;很全&#xff09;》 1. 什么是集合 集合就是一个放数据的容器&#xff0c;准确的说是放数据对象引用的容器集合类存放的都是对象的引用&#xff0c;而不是对象的本身集合类型主要有3种&#xff1a;set(集&#xff09;、list(列…

Unity文字转语音(使用RT-Voice PRO [2023.1.0])

参考文章Unity插件——文字转朗读语音RtVioce插件功能/用法/下载_rtvoice-CSDN博客 一、使用步骤 1.导入进Unity&#xff08;插件形式为 .unitypackage&#xff09; https://download.csdn.net/download/luckydog1120446388/88717512 2.添加所需Prefab 1&#xff09;.右键可…