Util工具类功能设计与类设计(http模块一)

目录

类功能

类定义

类实现

编译测试

Split分割字符串测试

ReadFile读取测试

WriteFile写入测试

UrlEncode编码测试

UrlDecode编码测试

StatuDesc状态码信息获取测试

ExtMime后缀名获取文件mime测试

IsDirectory&IsRegular测试

VaildPath请求路径有效性判断测试

总编译

补充

trunc截断

编码格式的规定

md5sum校验和比较两个文件是否一致

新增gdb调试手法


类功能

类定义

#include "../server.hpp"

class Util{
    public :
        // 字符串分割函数
        size_t Split();
        // 读取文件内容
        static bool ReadFile();
        // 向文件写入数据
        static bool WriteFile();
        // URL编码
        static bool UrlEncode();
        // URL解码
        static bool UrlDecode();
        // 响应状态码的描述信息获取
        static std::string StatuDesc();
        // 根据文件后缀名获取文件mime
        static std::string ExtMime();
        // 判断一个文件是否是一个目录
        static bool IsDirectory();
        // 判断一个文件是否是一个普通文件
        static bool IsRegular();
        // http请求的资源路径有效性判断
        static bool VaildPath();
};

类实现

#include "../server.hpp"
#include <sys/stat.h>
#include <fstream>

class Util
{
public:
    // 字符串分割函数
    static size_t Split(const std::string &src, const std::string &sep, std::vector<std::string> *arry)
    {
        size_t offset = 0;
        // 有10个字符,offset是查找的起始位置,范围应该是0~9,offset==10就代表已经越界了,返回查找的位置
        while (offset < src.size())
        {
            size_t pos = src.find(sep, offset); // 在src字符串偏移量offset处,开始向后查找sep字符/子串,返回查找到的位置
            if (pos == std::string::npos)       // 没有找到特定的字符
            {
                // 将剩余的部分当做一个子串,放入arry中
                if (pos == src.size())
                    break;
                arry->push_back(src.substr(offset));
                return arry->size();
            }
            if (pos == offset)
            {
                offset = pos + sep.size();
                continue; // 当前字符串是一个空串,没有内容
            }
            arry->push_back(src.substr(offset, pos - offset));
            offset = pos + sep.size();
        }
        return arry->size();
    }
    // 读取文件的所有内容,将读取到的内容放到一个容器中
    static bool ReadFile(const std::string &filename, std::string *buf)
    {
        std::ifstream ifs(filename, std::ios::binary); // 以二进制的方式读取
        if (ifs.is_open() == false)
        {
            printf("OPEN %s FILE FAILED!!", filename.c_str());
            return false;
        }
        size_t fsize = 0;            // 偏移量
        ifs.seekg(0, ifs.end);       // 跳转读写位置到末尾
        fsize = ifs.tellg();         // 获取当前读写位置相对于起始位置的偏移量,从末尾偏移量刚好就是文件大小
        ifs.seekg(0, ifs.beg);       // 跳转到起始位置
        buf->resize(fsize);          // 开辟文件大小的空间
        ifs.read(&(*buf)[0], fsize); // c_str()返回的是一个const,所以不行
        if (ifs.good() == false)
        {
            printf("READ %s FILE FAILED!!", filename.c_str());
            ifs.close();
            return false;
        }
        ifs.close();
        return true;
    }

    // 向文件写入数据
    static bool WriteFile(const std::string &filename, const std::string &buf)
    {
        std::ofstream ofs(filename, std::ios::binary | std::ios::trunc);
        if (ofs.is_open() == false)
        {
            printf("OPEN %s FILE FAILED!!", filename.c_str());
            return false;
        }
        ofs.write(buf.c_str(), buf.size());
        if (ofs.good() == false)
        {
            ERR_LOG("WRITE %s FILE FAILED!", filename.c_str());
            ofs.close();
            return false;
        }
        ofs.close();
        return true;
    }

    // URL编码,避免URL中资源路径与查询字符串中的特殊字符与HTTP请求中特殊字符产生歧义
    // 编码格式:将特殊字符的ascii值,转换为两个16进制字符,前缀%   C++ -> C%2B%2B
    // 不编码的特殊字符: RFC3986文档规定 . - _ ~ 字母,数字属于绝对不编码字符
    // RFC3986文档规定,编码格式 %HH
    // W3C标准中规定,查询字符串中的空格,需要编码为+, 解码则是+转空格
    static std::string UrlEncode(const std::string url, bool convert_space_to_plus)
    {
        std::string res;
        for (auto &c : url)
        {
            if (c == '.' || c == '-' || c == '_' || c == '~' || isalnum(c))
            {
                res += c;
                continue;
            }
            if (c == ' ' && convert_space_to_plus == true)
            {
                res += '+';
                continue;
            }
            // 剩下的字符都是需要编码成为 %HH 格式
            char tmp[4] = {0};
            // snprintf 与 printf比较类似,都是格式化字符串,只不过一个是打印,一个是放到一块空间中
            snprintf(tmp, 4, "%%%02X", c);
            res += tmp;
        }
        return res;
    }
    static char HEXTOI(char c)
    {
        if (c >= '0' && c <= '9')
            return c - '0';
        else if (c >= 'a' && c <= 'z')
            return c - 'a' + 10; // 注意要加10,16进制中,字母a从11开始
        else if (c >= 'A' && c <= 'Z')
            return c - 'A' + 10;
        return -1;
    }
    // URL解码
    static std::string UrlDecode(const std::string url, bool convert_plus_to_space)
    {
        // 遇到了%,则将紧随其后的2个字符,转换为数字,第一个数字左移4位,然后加上第二个数字
        //  + ->2b  %2b->2 << 4 + 11
        std::string res;
        for (int i = 0; i < url.size(); i++)
        {
            if (url[i] == '+' && convert_plus_to_space == true)
            {
                res += ' ';
                continue;
            }
            if (url[i] == '%')
            {
                char v1 = HEXTOI(url[i + 1]);
                char v2 = HEXTOI(url[i + 2]);
                char v = v1 * 16 + v2;
                i += 2;
                continue;
            }
            res += url[i];
        }
        return res;
    }
    // 响应状态码的描述信息获取
    static std::string StatuDesc(int statu)
    {
        std::unordered_map<int, std::string> _statu_msg = {
            {100, "Continue"},
            {101, "Switching Protocol"},
            {102, "Processing"},
            {103, "Early Hints"},
            {200, "OK"},
            {201, "Created"},
            {202, "Accepted"},
            {203, "Non-Authoritative Information"},
            {204, "No Content"},
            {205, "Reset Content"},
            {206, "Partial Content"},
            {207, "Multi-Status"},
            {208, "Already Reported"},
            {226, "IM Used"},
            {300, "Multiple Choice"},
            {301, "Moved Permanently"},
            {302, "Found"},
            {303, "See Other"},
            {304, "Not Modified"},
            {305, "Use Proxy"},
            {306, "unused"},
            {307, "Temporary Redirect"},
            {308, "Permanent Redirect"},
            {400, "Bad Request"},
            {401, "Unauthorized"},
            {402, "Payment Required"},
            {403, "Forbidden"},
            {404, "Not Found"},
            {405, "Method Not Allowed"},
            {406, "Not Acceptable"},
            {407, "Proxy Authentication Required"},
            {408, "Request Timeout"},
            {409, "Conflict"},
            {410, "Gone"},
            {411, "Length Required"},
            {412, "Precondition Failed"},
            {413, "Payload Too Large"},
            {414, "URI Too Long"},
            {415, "Unsupported Media Type"},
            {416, "Range Not Satisfiable"},
            {417, "Expectation Failed"},
            {418, "I'm a teapot"},
            {421, "Misdirected Request"},
            {422, "Unprocessable Entity"},
            {423, "Locked"},
            {424, "Failed Dependency"},
            {425, "Too Early"},
            {426, "Upgrade Required"},
            {428, "Precondition Required"},
            {429, "Too Many Requests"},
            {431, "Request Header Fields Too Large"},
            {451, "Unavailable For Legal Reasons"},
            {501, "Not Implemented"},
            {502, "Bad Gateway"},
            {503, "Service Unavailable"},
            {504, "Gateway Timeout"},
            {505, "HTTP Version Not Supported"},
            {506, "Variant Also Negotiates"},
            {507, "Insufficient Storage"},
            {508, "Loop Detected"},
            {510, "Not Extended"},
            {511, "Network Authentication Required"}};
        auto it = _statu_msg.find(statu);
        if (it != _statu_msg.end())
        {
            return it->second;
        }
        return "Unknow";
    }
    // 根据文件后缀名获取文件mime
    static std::string ExtMime(const std::string &filename)
    {
        std::unordered_map<std::string, std::string> _mime_msg = {
            {".aac", "audio/aac"},
            {".abw", "application/x-abiword"},
            {".arc", "application/x-freearc"},
            {".avi", "video/x-msvideo"},
            {".azw", "application/vnd.amazon.ebook"},
            {".bin", "application/octet-stream"},
            {".bmp", "image/bmp"},
            {".bz", "application/x-bzip"},
            {".bz2", "application/x-bzip2"},
            {".csh", "application/x-csh"},
            {".css", "text/css"},
            {".csv", "text/csv"},
            {".doc", "application/msword"},
            {".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
            {".eot", "application/vnd.ms-fontobject"},
            {".epub", "application/epub+zip"},
            {".gif", "image/gif"},
            {".htm", "text/html"},
            {".html", "text/html"},
            {".ico", "image/vnd.microsoft.icon"},
            {".ics", "text/calendar"},
            {".jar", "application/java-archive"},
            {".jpeg", "image/jpeg"},
            {".jpg", "image/jpeg"},
            {".js", "text/javascript"},
            {".json", "application/json"},
            {".jsonld", "application/ld+json"},
            {".mid", "audio/midi"},
            {".midi", "audio/x-midi"},
            {".mjs", "text/javascript"},
            {".mp3", "audio/mpeg"},
            {".mpeg", "video/mpeg"},
            {".mpkg", "application/vnd.apple.installer+xml"},
            {".odp", "application/vnd.oasis.opendocument.presentation"},
            {".ods", "application/vnd.oasis.opendocument.spreadsheet"},
            {".odt", "application/vnd.oasis.opendocument.text"},
            {".oga", "audio/ogg"},
            {".ogv", "video/ogg"},
            {".ogx", "application/ogg"},
            {".otf", "font/otf"},
            {".png", "image/png"},
            {".pdf", "application/pdf"},
            {".ppt", "application/vnd.ms-powerpoint"},
            {".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
            {".rar", "application/x-rar-compressed"},
            {".rtf", "application/rtf"},
            {".sh", "application/x-sh"},
            {".svg", "image/svg+xml"},
            {".swf", "application/x-shockwave-flash"},
            {".tar", "application/x-tar"},
            {".tif", "image/tiff"},
            {".tiff", "image/tiff"},
            {".ttf", "font/ttf"},
            {".txt", "text/plain"},
            {".vsd", "application/vnd.visio"},
            {".wav", "audio/wav"},
            {".weba", "audio/webm"},
            {".webm", "video/webm"},
            {".webp", "image/webp"},
            {".woff", "font/woff"},
            {".woff2", "font/woff2"},
            {".xhtml", "application/xhtml+xml"},
            {".xls", "application/vnd.ms-excel"},
            {".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
            {".xml", "application/xml"},
            {".xul", "application/vnd.mozilla.xul+xml"},
            {".zip", "application/zip"},
            {".3gp", "video/3gpp"},
            {".3g2", "video/3gpp2"},
            {".7z", "application/x-7z-compressed"},
        };
        // a.b.txt 获取文件名
        size_t pos = filename.find_last_of('.');
        if (pos != std::string::npos)
            return "application/octet-stream"; // 没找着,表示文件是一个二进制文件
        // 根据扩展名,获取mime
        std::string ext = filename.substr(pos);
        auto it = _mime_msg.find(ext);
        if (it == _mime_msg.end())
            return "application/octet-stream";
        return it->second;
    }
    // 判断一个文件是否是一个目录
    static bool IsDirectory(const std::string &filename)
    {
        struct stat st;
        int ret = stat(filename.c_str(), &st);
        if (ret < 0)
            return false;
        return S_ISDIR(st.st_mode);
    }
    // 判断一个文件是否是一个普通文件
    static bool IsRegular(const std::string &filename)
    {
        struct stat st;
        int ret = stat(filename.c_str(), &st);
        if (ret < 0)
            return false;
        return S_ISREG(st.st_mode);
    }
    // http请求的资源路径有效性判断
    // /index.html  --- 前边的/叫做相对根目录  映射的是某个服务器上的子目录
    // 想表达的意思就是,客户端只能请求相对根目录中的资源,其他地方的资源都不予理会
    // /../login, 这个路径中的..会让路径的查找跑到相对根目录之外,这是不合理的,不安全的
    static bool VaildPath();
};

编译测试

各个函数依次测试功能

Split分割字符串测试

ReadFile读取测试

WriteFile写入测试

UrlEncode编码测试

UrlDecode编码测试

StatuDesc状态码信息获取测试

ExtMime后缀名获取文件mime测试

IsDirectory&IsRegular测试

VaildPath请求路径有效性判断测试

总编译

无异常,符合预期

测试案例代码

int main()
{
    std::cout << VaildPath("/html/../../index.html") << std::endl;

    /*
    测试(IsDirectory)&(IsRegular)
    std::cout << IsRegular("../regex/regex.cpp") << std::endl;
    std::cout << IsRegular("../regex") << std::endl;
    std::cout << IsDirectory("../regex/regex.cpp") << std::endl;
    std::cout << IsDirectory("../regex") << std::endl;
    */

    /*
    测试(StatuDesc)&(ExtMime)
    std::cout << StatuDesc(200) << std::endl;
    std::cout << ExtMime("a.png") << std::endl;
    */

    /*
    测试(UrlEncode)&(UrlDecode)
    std::string str = "C  ";
    std::string res = UrlEncode(str, false);
    std::string tmp = UrlDecode(res, false);
    std::cout << "[" << res << "]\n";
    std::cout << "[" << tmp << "]\n";
    */

    /*
    测试(UrlEncode)
    std::string str = "/login?user=qingfengyugu&passwwd=C++";
    std::string res = UrlEncode(str, false);
    std::cout << res << std::endl;
    */

    /*
    测试(ReadFile)&(ReadFile)
    std::string buf;
    bool ret = ReadFile("../eventfd/eventfd.c", &buf);
    if (ret == false)
        return false;

    ret = WriteFile("./ttt.c", buf);
    if (ret == false)
        return false;
    */

    /*
    测试(Split)
    std::string str = "abc,,,";
    std::vector<std::string> arry;
    Split(str, ",", &arry);
    for (auto &s : arry)
    {
        std::cout << "[" << s << "]\n";
    }
    */

    return 0;
}

补充

trunc截断

参考文献

c++ 输入输出流  ios::out 和ios::trunc有什么区别-CSDN博客

编码格式的规定

md5sum校验和比较两个文件是否一致

参考文献

Linux下使用md5sum计算和检验MD5码 - 知乎 (zhihu.com)

新增gdb调试手法

建议参考文献

GDB调试run和start的区别_gdb start-CSDN博客

gdb 的 s 和 si 指令有什么区别 - CSDN文库

详解gdb常用指令 | CS笔记 (pynote.net)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Day33-计算机基础3

Day33-计算机基础3 1.根据TCP/IP进行Linux内核参数优化1.1 例1&#xff1a;调整访问服务端的【客户端】的动态端口范围 &#xff0c;LVS&#xff08;10-50万并发&#xff09;&#xff0c;NGINX负载&#xff0c;SQUID缓存服务,1.2 企业案例&#xff1a;DOS攻击的案例&#xff1a…

工资低适合下班做的6大副业,每一个都值得尝试!

2024年是最适合发展个人副业的时候&#xff01;无论你是否有全职工作&#xff0c;如果你的主业还不能满足你的成就感&#xff0c;还不能满足你的生活需求&#xff0c;这6个下班可以做的副业都很值得尝试&#xff01; 千金宝库做简单的网络任务 近年来&#xff0c;随着互联网技…

算法详解——leetcode150(逆波兰表达式)

欢迎来看博主的算法讲解 博主ID&#xff1a;代码小豪 文章目录 逆波兰表达式逆波兰表达式的作用代码将中缀表达式转换成后缀表达式文末代码 逆波兰表达式 先来看看leetcode当中的原题 大多数人初见逆波兰表达式的时候大都一脸懵逼&#xff0c;因为与平时常见的表达式不同&am…

C语言学习笔记,学懂C语言,看这篇就够了!(中)

附上视频链接&#xff1a;X站的C语言教程 目录 第8章、函数8.1 函数是什么8.2 函数的分类8.2.1 库函数8.2.1.1 如何使用库函数 8.2.2 自定义函数 8.3 函数参数8.3.1 实际参数(实参)8.3.2 形式参数(形参) 8.4 函数调用8.4.1 传值调用8.4.2 传址调用8.4.3 练习 8.5 函数的嵌套调…

如何使用ArcGIS Pro进行坡度分析

坡度分析是地理信息系统中一种常见的空间分析方法&#xff0c;用于计算地表或地形的坡度&#xff0c;这里为大家介绍一下如何使用ArcGIS Pro进行坡度分析&#xff0c;希望能对你有所帮助。 数据来源 教程所使用的数据是从水经微图中下载的DEM数据&#xff0c;除了DEM数据&…

Python爬虫:http和https介绍及请求

HTTP和HTTPS 学习目标&#xff1a; 记忆 http、https的概念和区别记忆 浏览器发送http请求的过程记忆 http请求头的形式记忆 http响应头的形式了解 http响应状态码 1 为什么要复习http和https 在发送请求&#xff0c;获取响应的过程中 就是发送http或https的请求&#xff0c…

自然语言发展历程

一、基础知识 自然语言处理&#xff1a;能够让计算理解人类的语言。 检测计算机是否智能化的方法&#xff1a;图灵测试 自然语言处理相关基础点&#xff1a; 基础点1——词表示问题&#xff1a; 1、词表示&#xff1a;把自然语言中最基本的语言单位——词&#xff0c;将它转…

中国电子学会2021年9月份青少年软件编程Sc ratch图形化等级考试试卷四级真题

【 单选题 】 1.下面哪个选项程序可以交换下图列表中第2项和第3项的位置&#xff1f; A&#xff1a; B&#xff1a; C&#xff1a; D&#xff1a; 2.雷峰塔景区的门票价格政策是&#xff1a;成人40元/人&#xff1b;6周岁&#xff08;含6周岁&#xff09;以下的实行免票&#…

常用MII接口详解

开放式系统互连 (OSI) 模型 七层开放系统互连 (OSI) 模型中&#xff0c;以太网层 位于最底部两层 - 物理层和数据链路层。 从百兆以太网接口开始 首先是百兆以太网规定的两种接口 介质无关接口 (MII) Media Independent Interface 介质相关接口 (MDI) Medium Depen…

manjaro 安装 wps 教程

内核: Linux 6.6.16.2 wps-office版本&#xff1a; 11.10.11719-1 本文仅作为参考使用, 如果以上版本差别较大不建议参考 安装wps主体 yay -S wps-office 安装wps字体 &#xff08;如果下载未成功看下面的方法&#xff09; yay -S ttf-waps-fonts 安装wps中文语言 yay …

如何用YOLOv8实现图像分割

1. 介绍 在之前的文章中,介绍了如何使用 YOLOv8 在不同的编程语言来检测图片中的对象。然而,YOLOv8 还可以把检测到的目标图像分割出来,本篇文章将介绍如何使用YOLOv8做图片分割。 对象检测的结果是所有检测到的对象的边界框。图像分割的结果是所有检测到的对象的蒙版。它是…

一篇文章简单介绍YOLO v1到v8的演变

大家好&#xff0c;YOLO&#xff08;You Only Look Once&#xff09;是一种流行的目标检测库&#xff0c;它的第一个版本在2015年发布。YOLO工作速度很快&#xff0c;提供了良好的结果&#xff0c;而且预训练模型是公开可用的。该模型迅速变得流行&#xff0c;该项目至今仍在积…

ai学习前瞻-python环境搭建

python环境搭建 Python环境搭建1. python的安装环境2. MiniConda安装3. pycharm安装4. Jupyter 工具安装5. conda搭建虚拟环境6. 安装python模块pip安装conda安装 7. 关联虚拟环境运行项目 Python环境搭建 1. python的安装环境 ​ python环境安装有4中方式。 从上图可以了解…

python之数组,链表,栈,队列

1.数组 优点&#xff1a; 索引操作速度快&#xff1a;通过索引可以直接访问元素&#xff0c;因此索引操作的时间复杂度是 $O(1)$&#xff0c;即常数级 缺点&#xff1a; 插入、删除元素慢&#xff1a; 如果需要在中间或开始位置插入或删除元素&#xff0c;可能需要移动大量…

漫漫数学之旅036

文章目录 经典格言数学习题古今评注名人小传 - 爱因斯坦 经典格言 纯数学在其领域内是逻辑思想的诗歌。——阿尔伯特爱因斯坦 “纯数学在其领域内是逻辑思想的诗歌”这句话体现了爱因斯坦对数学的深刻理解和热爱。在这句话中&#xff0c;爱因斯坦将纯数学比作诗歌&#xff0c;…

mmdetection如何计算准确率、召回率、F1值

1、训练 python tools/train.py configs/fcos/fcosrdweed3.py 2、测试 这一步要加–outresult.pkl&#xff0c;才能计算准确率和召回率 python tools/test.py configs/fcos/fcosrddweed3.py work_dirs/fcosrddweed3/epoch_300.pth --outresultfcos.pkl3、计算准确率和召回率…

三维GIS的业务导向

的确&#xff0c;目前三维GIS以做特效居多&#xff0c;酷炫、亮眼&#xff0c;从二维转到三维&#xff0c;第一眼就给人眼前一亮的感觉&#xff0c;就凭这一项&#xff0c;很多客户就会买单&#xff0c;GIS的客户以政府、科研院所、特种行业为主&#xff0c;买过一次单后&#…

riscv简单常用汇编指令xv6

文章目录 前言entry.Smretasm volatileread csrwrite csrriscv常见csr寄存器 ecall, 系统调用指令cpu执行异常处理指令的三种事件 异常处理相关寄存器用户态trapsret指令页表切换操作用户态系统调用过程总结 内核态trap缺页异常 中断与设备驱动Locking调度文件系统操作系统拥有…

Docker完整版(一)

Docker完整版&#xff08;一&#xff09; 一、Docker概述1.1、Docker简介1.2、Docker的用途1.3、容器与虚拟机的区别1.4、Docker系统架构1.5、Docker仓库 二、Docker引擎2.1、Docker引擎架构2.2、Docker引擎分类2.3、Docker引擎的安装2.4、Docker镜像加速器 三、Docker镜像3.1、…

Android 完整SDK项目中添加对应的JNI与底层通信

安卓应用发消息给底层 近日需要写一个安卓app和底层发消息&#xff0c;这就涉及到java如何到c层的一个逻辑&#xff0c;app已经写好&#xff0c;就差发个消息了。至于如何对接底层&#xff0c;得和写底层的人进一步沟通&#xff0c;本文笔者只写从java层通信到cpp&#xff0c;…