开发环境:vs2019
系统:win10
openssl版本:Win32OpenSSL-3_0_7
访问网页:www.baidu.com
先说明以下问题:c++在发送https请求后,接收从客户端返回的数据时时,发现有时内容夹杂一些奇怪的数据(十六进制,范围从0-8000),如下图
正常应该是
两者唯一的区别是发送的http协议一个为1.0,另一个为1.2
经过检验,十六进制52f对应的值恰好52f数据之后到8000数据之前这中间内容的字节数,这里不演示(因为自己代码可能会出现问题,所以后面用fiddle抓包来验证,使用composer,下图中HTTP/2.0那边进行调整,范围为0.9、1.0、1.1、1.2、2.0,不解码)
0.9结果:500错误(应该是服务器那边不支持,忽略掉)
1.0结果
1.1结果:比1.0内容前面多出了d55
1.2结果:和1.1一致
2.0结果:与1.1和1.2一致
猜测:从1.1开始接收到的内容会分成一块一块,每块前面会包含这一块数据的大小,范围十六进制从0-8000,由后往前统计(简单说:[小于8000],[8000],[8000]….[8000],[0])
其实在这里还有一种限制是返回的数据Content-Type需要为text/html,才能满足猜测,本人在代码中曾接收过Content-Type为text/plain,试验过1.0和1.1,结果都一样(因为fiddler抓到的几乎都是text/html,就不演示),之所以写猜测,其实是本人没有进行大规模实验,除了Content-Type可能还存在其它限制,感兴趣的人可以自己去尝试一下
最后上一下代码(c++http\https发送get或post请求),代码本质来源于网上各个地方,在此是将代码进行修改、统合。(该代码是本人毕业设计的部分内容,非全部,注释可能偏少或不规范,需要的人自行复制粘贴使用,代码已自测过)
irg3_log.hpp(主要是用来打印日志)
#ifndef _IRG3_LOG_HPP_
#define _IRG3_LOG_HPP_
#include <thread>
#include <fstream>
#include "irg3_utils.hpp"
#include <mutex>
#define _DEBUG_TRACE_PRINT_ 2
#if 0 != _DEBUG_TRACE_PRINT_
#include <cstdio>
#include <thread>
#include <string>
#endif
//三个需要配合使用,否则会出问题
//获取运行时间
#define IRG3_BEGIN_CLOCK clock_t start_clock_ = clock()
#define IRG3_END_CLOCK clock_t end_clock_ = clock()
#define IRG3_GET_CLOCK static_cast<double>(end_clock_ - start_clock_) / CLOCKS_PER_SEC
class Irg3_Log {
private:
Irg3_Log() {}
public:
virtual ~Irg3_Log() {
if (out) {
out.close();
}
}
void Init(const char* path_ = "irg3.log") {
out.open(path_);
if (!out) {
return;
}
}
void UnInit() {
Close();
}
void Close() {
if (out) {
out.close();
}
}
static Irg3_Log* getInstance() {
static Irg3_Log log;
return &log;
}
void write(const char* str_) {
if (!out) {
return;
}
//1000行后从头开始写入
static int num_ = 0;
char buf_[64] = "";
time_t t = time(NULL); tm* _tm = localtime(&t);
sprintf(buf_, "%04d-%02d-%02d %02d:%02d:%02d %5d ", _tm->tm_year + 1900, _tm->tm_mon + 1, _tm->tm_mday, \
_tm->tm_hour, _tm->tm_min, _tm->tm_sec, std::this_thread::get_id());
my_mutex_.lock();
if (num_ == 1000) {
num_ = 0;
out.seekp(0);
}
num_++;
out << buf_;
out << irg3_utils_s_to_utf8(str_);
out << std::endl;
my_mutex_.unlock();
}
private:
std::ofstream out;
std::mutex my_mutex_;
};
#define IRG3_LOG_ERROR(fmt,...) {std::string file_ = __FILE__;char buf_[1024] = "";\
sprintf(buf_,"[ERROR] %s(%d): "##fmt,file_.substr(file_.rfind('\\')+1).c_str(),\
__LINE__, ##__VA_ARGS__);Irg3_Log::getInstance()->write(buf_);}
#define IRG3_LOG_INFO(fmt,...) {std::string file_ = __FILE__;char buf_[1024] = "";\
sprintf(buf_,"[INFO] %s(%d): "##fmt,file_.substr(file_.rfind('\\')+1).c_str(),\
__LINE__, ##__VA_ARGS__);Irg3_Log::getInstance()->write(buf_);}
#define IRG3_LOG_WARN(fmt,...) {std::string file_ = __FILE__;char buf_[1024] = "";\
sprintf(buf_,"[WARN] %s(%d): "##fmt,file_.substr(file_.rfind('\\')+1).c_str(),\
__LINE__, ##__VA_ARGS__);Irg3_Log::getInstance()->write(buf_);}
#endif // !_IRG3_LOG_HPP_
irg3_report.hpp(用来生成测试报告)
#ifndef _IRG3_REPORT_HPP_
#define _IRG3_REPORT_HPP_
#include <thread>
#include <fstream>
#include "irg3_utils.hpp"
#include "irg3_log.hpp"
#define IRG3_REPORT_LOG_FILE_PATH "report\\irg3_report.log"
#define IRG3_REPORT_HTML_FILE_PATH "report\\irg3_report.html"
//==========================================================================
// LOG
//==========================================================================
class Irg3_ReportLog {
private:
Irg3_ReportLog() {}
public:
virtual ~Irg3_ReportLog() {}
void Init() {
out.open(IRG3_REPORT_LOG_FILE_PATH);
}
void UnInit() {
out.close();
}
static Irg3_ReportLog* getInstance() {
static Irg3_ReportLog log;
return &log;
}
void report(const char* str_) {
if (!out) {
return;
}
char buf_[64] = "";
time_t t = time(NULL); tm* _tm = localtime(&t);
sprintf(buf_, "%04d-%02d-%02d %02d:%02d:%02d %5d ", _tm->tm_year + 1900, _tm->tm_mon + 1, _tm->tm_mday, \
_tm->tm_hour, _tm->tm_min, _tm->tm_sec, std::this_thread::get_id());
my_mutex_.lock();
out << buf_;
out << irg3_utils_s_to_utf8(str_);
out << std::endl;
my_mutex_.unlock();
}
int get_cur_position() {
return out.tellp();
}
//纯文本
void report_text(const char* str_) {
if (!out) {
return;
}
out << irg3_utils_s_to_utf8(str_);
}
void lock() {
my_mutex_.lock();
}
void unlock() {
my_mutex_.unlock();
}
private:
std::ofstream out;
std::mutex my_mutex_;
};
#define IRG3_REPORT_INIT Irg3_ReportLog::getInstance()->Init();
#define IRG3_REPORT_UNINIT Irg3_ReportLog::getInstance()->UnInit();
#define IRG3_REPORT_ERROR(fmt,...) {std::string file_ = __FILE__;char irg3_report_buf_[1024] = "";\
sprintf(irg3_report_buf_,"[ERROR] %s(%d): "##fmt,file_.substr(file_.rfind('\\')+1).c_str(),\
__LINE__, ##__VA_ARGS__);Irg3_ReportLog::getInstance()->report(irg3_report_buf_);}
#define IRG3_REPORT_INFO(fmt,...) {std::string file_ = __FILE__;char irg3_report_buf_[1024] = "";\
sprintf(irg3_report_buf_,"[INFO] %s(%d): "##fmt,file_.substr(file_.rfind('\\')+1).c_str(),\
__LINE__, ##__VA_ARGS__);Irg3_ReportLog::getInstance()->report(irg3_report_buf_);}
#define IRG3_REPORT_WARN(fmt,...) {std::string file_ = __FILE__;char irg3_report_buf_[1024] = "";\
sprintf(irg3_report_buf_,"[WARN] %s(%d): "##fmt,file_.substr(file_.rfind('\\')+1).c_str(),\
__LINE__, ##__VA_ARGS__);Irg3_ReportLog::getInstance()->report(irg3_report_buf_);}
//自定义格式,但最大不超过1024
#define IRG3_REPORT_TEXT(fmt,...) {char irg3_report_buf_[1024] = "";\
sprintf(irg3_report_buf_,##fmt,##__VA_ARGS__);Irg3_ReportLog::getInstance()->report_text(irg3_report_buf_);}
//不提供定义格式,专门传输数据量大的
#define IRG3_REPORT_TEXT_EX(fmt) Irg3_ReportLog::getInstance()->report_text(fmt)
#define IRG3_REPORT_TEXT_LOCK Irg3_ReportLog::getInstance()->lock()
#define IRG3_REPORT_TEXT_UNLOCK Irg3_ReportLog::getInstance()->unlock()
#define IRG3_REPORT_CUR_POSITION Irg3_ReportLog::getInstance()->get_cur_position()
//==========================================================================
// HTML
//==========================================================================
typedef struct Irg3_Report_File {
fpos_t beg_position_ = -1;
fpos_t end_position_ = -1;
int pass_ = 0;
int fail_ = 0;
int error_ = 0;
int skip_ = 0;
}irg3_report_file;
typedef struct Irg3_Report_Node {
std::string name_; //文件名
std::vector<irg3_report_file> vecs_; //执行次数
}irg3_report_node;
typedef struct Irg3_Report_Script {
std::string type_; //脚本类型
std::string content_;
std::vector<irg3_report_node> vecs_;
}irg3_report_script;
typedef struct Irg3_Report_Message {
std::string beg_time_;
std::string end_time_;
std::string time_;
}irg3_report_message;
class Irg3_ReportHtml {
private:
Irg3_ReportHtml() {};
typedef struct Node {
int pass_ = 0; //通过数量
int fail_ = 0; //失败数量
int error_ = 0; //错误数量
int skip_ = 0; //跳过数量
int scripts_ = 0; //脚本数量
int all_ = 0;
}inline_node;
public:
virtual ~Irg3_ReportHtml() {};
static Irg3_ReportHtml* getInstance() {
static Irg3_ReportHtml report_;
return &report_;
}
bool report(irg3_report_message& mes_, std::vector<irg3_report_script>& vecs_) {
out.open(IRG3_REPORT_HTML_FILE_PATH);
if (!out) {
return false;
}
report_report(out, "IRG3测试报告", vecs_, mes_);
out.close();
return true;
}
private:
std::ofstream out;
private:
//内容
void report_content(std::ofstream& out, std::string& name_, int id_, irg3_report_file& file_) {
char temp[64] = "";
sprintf(temp, "%s.%d", name_.c_str(), id_);
std::string str_ = temp;
out << "<tr id='div_" << str_ << "' name='div_" << name_ << "' class=\"hiddenRow\">";
out << "<td>" << str_ << "</td>";
out << "<td colspan='7' class='errorCase'><div class='popup_retry_window'>";
out << "<span class=\"lang-cn\">" << irg3_utils_s_to_utf8(" 第 ") << id_ << irg3_utils_s_to_utf8(" 次循环 ") << "</span>";
out << "<span class=\"lang-en\"> Try 1 </span></div></td>";
out << "<td class='errorCase' align='center'><a class=\"popup_link\" onfocus='this.blur();'href=\"javascript:showTestDetail('div_" << str_ << "',0, true)\">";
out << "<span class=\"lang-cn\">" << irg3_utils_s_to_utf8("细节") << "</span>";
out << "<span class=\"lang-en\">error</span></a></td></tr>";
out << "<tr id='div_S_" << str_ << "' name='div_" << str_ << "' class=\"hiddenRow\"><td colspan='10'><div class=\"popup_window\">";
out << "<div style='text-align: right; color:red;cursor:pointer'onclick=\"document.getElementById('div_S_" << str_ << "').className = 'hiddenRow'\"><a onfocus='this.blur();'>[x]</a></div><pre>";
//具体内容
FILE* fp = nullptr;
fp = fopen(IRG3_REPORT_LOG_FILE_PATH, "rb");
if (fp == nullptr) {
IRG3_LOG_ERROR("打开报告日志失败");
}
else {
char buf_[1025];
fseek(fp, file_.beg_position_, SEEK_SET);
fpos_t position;
fgetpos(fp, &position);
while (position < file_.end_position_) {
fread(buf_, sizeof(char), min((sizeof(buf_) - 1), file_.end_position_ - position), fp);
out << irg3_utils_s_to_utf8(irg3_utils_utf8_to_gb(buf_)) << std::endl;
fgetpos(fp, &position);
}
}
if (fp) {
fclose(fp);
}
out << "";
out << "</pre><div><ul class='figure_ul'><ul></div></div></td></tr>";
}
//脚本
void report_script(std::ofstream& out, irg3_report_node& node_, std::string name_) {
out << "<tr id='" << name_ << "' class=\"hiddenRow\">";
out << "<td>" << name_ << "</td>";
out << "<td class='errorCase' colspan='7'><div class='testcase'>" << irg3_utils_s_to_utf8(node_.name_) << "</div></td>";
out << "<td class='errorCase'><div class='testcase' style=\"margin-left: auto;\">" << node_.vecs_.size() << "</div></td>";
out << "<td class='errorCase' align='center'><a class=\"popup_link\" onfocus='this.blur();' href=\"javascript:showTestDetail('div_" << name_ << "'," << node_.vecs_.size() << ", false)\">";
out << "<span class=\"lang-cn\">" << irg3_utils_s_to_utf8("细节") << "</span>";
out << "<span class=\"lang-en\">error</span></a></td></tr>";
for (int i = 0; i < node_.vecs_.size(); i++) {
report_content(out, name_, i + 1, node_.vecs_[i]);
}
}
//类型
void report_type(std::ofstream& out, irg3_report_script& node) {
int pass_ = 0;
int fail_ = 0;
int error_ = 0;
int skip_ = 0;
for (auto& it : node.vecs_) {
for (auto& t : it.vecs_) {
pass_ += t.pass_;
fail_ += t.fail_;
error_ += t.error_;
skip_ += t.skip_;
}
}
int all_ = pass_ + fail_ + skip_ + error_;
char statistics_[8] = "";
if (all_ == 0)
sprintf(statistics_, "0.00%%");
else
sprintf(statistics_, "%.2lf%%", (pass_ * 1.0 / all_));
out << "<tr class='errorClass'>";
out << "<td>" << node.type_ << "</td>";
out << "<td>" << irg3_utils_s_to_utf8(node.content_) << "</td>";
out << "<td>" << node.vecs_.size() << "</td>";
out << "<td class=\"passCase\">" << pass_ << "</td>";
out << "<td class=\"failCase\">" << fail_ << "</td>";
out << "<td class=\"errorCase\">" << error_ << "</td>";
out << "<td class=\"skipCase\">" << skip_ << "</td>";
out << "<td style=\"text-align:right;\">" << statistics_ << "</td>";
out << "<td>" << all_ << "</td>";
out << "<td><a href=\"javascript:showClassDetail('" << node.type_ << "'," << node.vecs_.size() << ")\">";
out << "<span class=\"lang-cn\">" << irg3_utils_s_to_utf8("细节") << "</span><span class=\"lang-en\">Detail</span>";
out << "</a></td></tr>";
for (int i = 0; i < node.vecs_.size(); i++) {
char temp[64] = "";
sprintf(temp, "%s.%d", node.type_.c_str(), i + 1);
std::string str_ = temp;
report_script(out, node.vecs_[i], str_);
}
}
void report_report(std::ofstream& out, const char* title, std::vector<irg3_report_script>& vecs_, irg3_report_message& mes_) {
int pass_ = 0; //通过数量
int fail_ = 0; //失败数量
int error_ = 0; //错误数量
int skip_ = 0; //跳过数量
int scripts_ = 0; //脚本数量
for (auto& it : vecs_) {
scripts_ += it.vecs_.size();
for (auto& ir : it.vecs_) {
for (auto& t : ir.vecs_) {
pass_ += t.pass_;
fail_ += t.fail_;
error_ += t.error_;
skip_ += t.skip_;
}
}
}
int all_ = pass_ + fail_ + skip_ + error_;
char statistics_[8] = "";
sprintf(statistics_, "%.2lf%%", (pass_ * 1.0 / all_));
//head
{
out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
out << "<!DOCTYPE html PUBLIC \" -//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">";
out << "<html xmlns=\"http://www.w3.org/1999/xhtml\">";
out << "<head><title>" << irg3_utils_s_to_utf8(title) << "</title>";
out << "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />";
out << "<style type=\"text/css\" media=\"screen\">";
out << "body {font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"PingFang SC\", \"Hiragino Sans GB\", \"Microsoft YaHei\", \"Helvetica Neue\", Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";font-size: 14px;}";
out << "pre {word-wrap: break-word;word-break: break-all;overflow: auto;white-space: pre-wrap}";
out << "h1 {font-size: 16pt;color: gray}";
out << ".heading {margin-top: 0;margin-bottom: 1ex}";
out << ".heading .attribute {margin-top: 1ex;margin-bottom: 0}";
out << ".heading .description {margin-top: 4ex;margin-bottom: 6ex}";
out << "a.popup_link:hover {color: red}";
out << ".popup_window {display: block;position: relative;left: 0;top: 0;padding: 10px;background-color: #E6E6D6;text-align: left;font-size: 13px}";
out << ".popup_retry_window {padding-left: 50px;}";
out << "#show_detail_line {margin-top: 3ex;margin-bottom: 1ex}";
out << "#result_table {width: 100%;border-collapse: collapse;border: 1px solid #777}";
out << "#header_row {color: #fff;background-color: #777}";
out << "#result_table td {border: 1px solid #777;padding: 2px;}";
out << "#result_table td:nth-child(n+2) {min-width: 70px;width: 100%}";
out << "#result_table td:nth-child(n+3) {text-align: center;}";
out << "#result_table td:first-of-type {text-align: center;min-width: 60px;}";
out << "#total_row {font-weight: bold}";
out << ".passClass,.failClass,.errorClass,.skipClass {font-weight: bold}";
out << ".passCase {background-color: #d0e9c6}";
out << ".failCase {background-color: #ebcccc}";
out << ".errorCase {background-color: #faf2cc}";
out << ".skipCase {background-color: #c4e3f3}";
out << ".hiddenRow {display: none}";
out << ".testcase {margin-left: 2em}";
out << "#popup {position: fixed;left: 0;top: 0;width: 100%;height: 100%;text-align: center;display: none}";
out << "#popup .bg {background-color: rgba(0, 0, 0, .5);width: 100%;height: 100%}";
out << "#popup img {max-width: 100%;max-height: 100%;margin: auto;position: absolute;top: 0;left: 0;bottom: 0;right: 0;}";
out << "img.pic {cursor: pointer;width: auto;height: auto;max-width: 100%;max-height: 100%;}";
out << "#wrapper {margin: 0 auto;border-top: solid 2px #666;}";
out << "#wrapper .lang-en {display: none;}";
out << "#wrapper.lang-cn p.lang-cn {display: block;}";
out << "#wrapper.lang-cn span.lang-cn {display: inline;}";
out << "#wrapper.lang-cn .lang-en {display: none;}";
out << "#wrapper.lang-en .lang-cn {display: none;}";
out << "#wrapper.lang-en p.lang-en {display: block;}";
out << "#wrapper.lang-en span.lang-en {display: inline;}";
out << "#lang ul {float: right;margin: 0;padding: 2px 10px 4px 10px;background: #666;border-radius: 0 0 4px 4px;list-style: none;}";
out << "#lang li {margin: 0;float: left;padding: 0 5px;}";
out << "#lang li a {display: block;width: 24px;height: 24px;text-indent: -4em;overflow: hidden;background: transparent url(\"data:image/png; base64, iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA + f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAHiSURBVHja1Ja/jtNAEMZ/Y2/icBdxXAMSEu/A1dBR0NJQ8CS8AQ0tb4CQgEegPgQFOh7ixJUX4vgSx96ZoUgOO3 + KRDgFX7Or0Wg + f7PzeVfcnUMi4cA4OIEAARgAvY5r10AZgOGvl69Gkm4Xk9w3fJTg9f4MDz9 + OA3AsSTC4OmThaQE3Bp9w + eRmy + hie2I8us3gOMABFNFkjlW5PTPIvOLAO7YVMjfC/Sd4YuK4nOGuyMiABv7v6pP7mKmACEAeK1YPuPoWU52FgkPUiaf + ngFDjCD + Q/Fproo1vrSbUPuvR4eF7kBwDRi4ynlzxkyUMrvKTZabbrPFb9Jd2qPh7BK4DGiRYFeTJmdC8nAsVKaUes72eOK6Xm2G0GaYhpXCTzPsXEBgOZN8unrktHbAddvAKrdCESwqmoItI74eILlkw0bjt4Zltdg + 5hL8NhSYLGmurrCxuPN7Mv951 + LAh1kLQWxBlUw68bDGtEqaStQiB0SRMWlbh1yXWPu + MIc/wzTiC0dslBQR0TArfWPwJdr21KyttLKaeJijvmaD0gTMF/z57pPt8W37E1xaylwU0iE5OhON2fgjreMVmuMXC/ntus7QYAT4BFwr + Piv4HL2xstu21Xh4jAXP77V8WfAQAixA0rudAk0AAAAABJRU5ErkJggg == \") no-repeat 50% 50%;}";
out << "#lang li a#lang-en {background-image: url(\"data:image/png; base64, iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA + f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAIWSURBVHja1JY/SBthGIefu1xqS6K20KFDy0kopUiHmphIByUZotRAIZOTWZzFpYtbB0uh6KJTIdQhi9pBSwmmCOpgoUSKFItTh4AU6tCr16Rn5P58XZocDrlYuAz9wfHAcbzv9/2 + 932/k4QQdFIyHVbHE0iAAlwFgj7HNoG6AoRzudc/A4F/28yL2l7bb269yd9QgJAsS8zMjFIufyWRuHspXqtbnsHrH8oAIQlQJyfzlaGhCNFohJ2dI1Kp/iZ3d49IJvsvvJckmJ197JlACIEsy30KgGUJBgcjFIufSacfsLnpza2tL/x4 + qx15fR0Uz84hL8HjG1blEqHJJP9bGx8IpMZ8CSAMIzWq1cUhO24CSzLYWTkPisrH8lm46yuenN9fZ + br156WmRZFgQLjR3YrK2VyWSiFAp7TEw88iTAyZNca4t6e6h/P3EbzTRtxscfks9vk83G27JaPcOuVls/v6o4pltlajo9L1KpebG8vC9isbm2jMXmRDsZhiEAVWn4NTU1ysJCkenpMRYXS55cWnrPcSThUUVhzrquNEeFOjz8vOI4CrXa + aU7 + d3p29YJusMYwQD3Drb7AFRd14Xf0nXdtehbfAxdkhG13/5M0HCImiTcPhC2BVIAHMefOWrbCNxYqqZpvlukaVrTIrNye4CK1JH7xpSAXuAOcN3n4KfAceNG62qch4 + ygHPpv/+r + DMAXV79BpyNnBoAAAAASUVORK5CYII=\");}";
out << ".figure_ul {text-align: center;padding: 0;}";
out << ".figure_li {width: 30em;list-style: none;display: inline-block;vertical-align: baseline;}";
out << "tr {height: 2em;}</style>";
}
//script
{
out << "<script language=\"javascript\" type=\"text/javascript\">";
out << "var chartData_cn = [[" << pass_ << ", \"#1c965b\", \"" << irg3_utils_s_to_utf8("通过") << "\"],[" << fail_ << ", \"#ff5722\", \"" << irg3_utils_s_to_utf8("失败") << "\"],[" << error_ << ", \"#ff9800\", \"" << irg3_utils_s_to_utf8("错误") << "\"],[" << skip_ << ", \"#64b5f6\", \"" << irg3_utils_s_to_utf8("跳过") << "\"]];";
out << "var chartData_en = [[" << pass_ << ", \"#1c965b\", \"Passed\"],[" << fail_ << ", \"#ff5722\", \"Failed\"],[" << error_ << ", \"#ff9800\", \"Error\"],[" << skip_ << ", \"#64b5f6\", \"Skipped\"]];";
out << "function addClass(e, c) {if (!isClass(e, c)) {if (e.className) {e.className = e.className + \" \" + c;} else {e.className = c;}}}";
out << "function delClass(e, c) {if (isClass(e, c)) {let r = new RegExp('(?:^|\\s)' + c + '(?!\\S)', 'g');e.className = e.className.replace(r, '');}}";
out << "function isClass(e, c) {let r = new RegExp('(?:^|\\s)' + c + '(?!\\S)');return e.className.match(r);}";
out << "function showCase(level) {let trs = document.getElementsByTagName(\"tr\");for (let i = 0; i < trs.length; i++) {let tr = trs[i];let id = tr.id;if (id.substr(0, 2) === \"st\") {if (level === 4 || level === 3) {delClass(tr, 'hiddenRow');} else {addClass(tr, 'hiddenRow');}}if (id.substr(0, 2) === \"ft\") {if (level === 4 || level === 2) {delClass(tr, 'hiddenRow');} else {addClass(tr, 'hiddenRow');}}if (id.substr(0, 2) === \"pt\") {if (level === 4 || level === 1) {delClass(tr, 'hiddenRow');} else {addClass(tr, 'hiddenRow');}}if (id.substr(0, 2) === \"et\") {if (level === 4 || level === 5 || level === 2) {delClass(tr, 'hiddenRow');} else {addClass(tr, 'hiddenRow');}}if (id.substr(0, 4) === \"div_\") {addClass(tr, 'hiddenRow');}}}";
out << "function showClassDetail(cid, count) {let id_list = Array(count);let toHide = 1;for (let i = 0; i < count; i++) {let tid = cid + \".\" + (i + 1);let tr = document.getElementById(tid);if (tr) {id_list[i] = tid;if (tr.className) {toHide = 0;}}}for (let i = 0; i < count; i++) {let tid = id_list[i];if (toHide) {addClass(document.getElementById(tid), 'hiddenRow');} else {delClass(document.getElementById(tid), 'hiddenRow');}}let trs = document.getElementsByTagName(\"tr\");for (let i = 0; i < trs.length; i++) {let tr = trs[i];let id = tr.id;if (id.substr(0, 4) === \"div_\") {addClass(tr, 'hiddenRow');}}}";
out << "function showTestDetail(div_id, count, b) {let details_div_s = document.getElementsByName(div_id);for (let j = 0; j < details_div_s.length; j++) {let details_div = details_div_s[j];if (isClass(details_div, 'hiddenRow')) {delClass(details_div, 'hiddenRow');} else {addClass(details_div, \"hiddenRow\");}}for (let i = 1; i <= count; i++) {let details_div_s = document.getElementsByName(div_id + '.' + i);for (let j = 0; j < details_div_s.length; j++) {let details_div = details_div_s[j];if (details_div !== undefined) {if (b && isClass(details_div, 'hiddenRow')) {delClass(details_div, 'hiddenRow');} else {addClass(details_div, \"hiddenRow\");}}}}}";
out << "function html_escape(s) {s = s.replace(/&/g, \"&\");s = s.replace(/</g, \"<\");s = s.replace(/>/g, \">\");return s;}";
out << "function initChart() {cMargin = 20;cSpace = 40;canvas.width = canvas.parentNode.getAttribute(\"width\") * 2;canvas.height = canvas.parentNode.getAttribute(\"height\") * 2;canvas.style.height = canvas.height / 2 + \"px\";canvas.style.width = canvas.width / 2 + \"px\";cHeight = canvas.height - cMargin * 2;cWidth = canvas.width - cMargin * 2;radius = cHeight * 2 / 6; ox = canvas.width / 2 + cSpace; oy = canvas.height / 2;tWidth = 60; tHeight = 20;posX = cMargin;posY = cMargin; textX = posX + tWidth + 15;textY = posY + 18;startAngle = endAngle = 90 * Math.PI / 180; rotateAngle = 0;totleNb = 0;new_data_arr = [];for (var i = 0; i < dataArr.length; i++) {totleNb += dataArr[i][0];}for (var i = 0; i < dataArr.length; i++) {new_data_arr.push(dataArr[i][0] / totleNb);}totalYNomber = 10;ctr = 1;numctr = 50;speed = 1.2;lineStartAngle = -startAngle;line = 40;textPadding = 10;textMoveDis = 200;}";
out << "function goChart(dataArr) {var canvas, ctx;var cWidth, cHeight, cMargin, cSpace;var radius, ox, oy;var tWidth, tHeight;var posX, posY, textX, textY;var startAngle, endAngle;var totleNb;var ctr, numctr, speed;var mousePosition = {};var lineStartAngle, line, textPadding, textMoveDis;canvas = document.getElementById(\"chart\");if (canvas && canvas.getContext) {ctx = canvas.getContext(\"2d\");}initChart();function initChart() {cMargin = 20;cSpace = 40;canvas.width = canvas.parentNode.getAttribute(\"width\") * 2;canvas.height = canvas.parentNode.getAttribute(\"height\") * 2;canvas.style.height = canvas.height / 2 + \"px\";canvas.style.width = canvas.width / 2 + \"px\";cHeight = canvas.height - cMargin * 2;cWidth = canvas.width - cMargin * 2;radius = cHeight * 2 / 6; ox = canvas.width / 2 + cSpace; oy = canvas.height / 2;tWidth = 60; tHeight = 20;posX = cMargin;posY = cMargin; textX = posX + tWidth + 15;textY = posY + 18;startAngle = endAngle = 90 * Math.PI / 180; rotateAngle = 0;totleNb = 0;new_data_arr = [];for (var i = 0; i < dataArr.length; i++) {totleNb += dataArr[i][0];}for (var i = 0; i < dataArr.length; i++) {new_data_arr.push(dataArr[i][0] / totleNb);}totalYNomber = 10;ctr = 1;numctr = 50;speed = 1.2;lineStartAngle = -startAngle;line = 40;textPadding = 10;textMoveDis = 200;}drawMarkers();function drawMarkers() {ctx.textAlign = \"left\";for (var i = 0; i < dataArr.length; i++) {ctx.fillStyle = dataArr[i][1];ctx.fillRect(posX, posY + 40 * i, tWidth, tHeight);ctx.moveTo(parseInt(posX) + 0.5, parseInt(posY + 40 * i) + 0.5);ctx.font = 'normal 24px " << irg3_utils_s_to_utf8("微软雅黑") << "'; ctx.fillStyle = dataArr[i][1]; var percent = dataArr[i][2] + \"" << irg3_utils_s_to_utf8(":") << "\" + parseInt(100 * new_data_arr[i]) + \"%\";ctx.fillText(percent, parseInt(textX) + 0.5, parseInt(textY + 40 * i) + 0.5);}};pieDraw();function pieDraw(mouseMove) {for (var n = 0; n < dataArr.length; n++) {ctx.fillStyle = ctx.strokeStyle = dataArr[n][1];ctx.lineWidth = 1;var step = new_data_arr[n] * Math.PI * 2;var lineAngle = lineStartAngle + step / 2; lineStartAngle += step;ctx.beginPath();var x0 = ox + radius * Math.cos(lineAngle),y0 = oy + radius * Math.sin(lineAngle),x1 = ox + (radius + line) * Math.cos(lineAngle),y1 = oy + (radius + line) * Math.sin(lineAngle),x2 = x1,y2 = y1,linePadding = ctx.measureText(dataArr[n][2]).width + 10; ctx.moveTo(parseInt(x0) + 0.5, parseInt(y0) + 0.5);yMove = y0 + (y1 - y0) * ctr / numctr;ctx.lineTo(parseInt(x1) + 0.5, parseInt(yMove) + 0.5);if (x1 <= x0) {x2 -= line;ctx.textAlign = \"right\";ctx.lineTo(parseInt(x2 - linePadding) + 0.5, parseInt(yMove) + 0.5);ctx.fillText(dataArr[n][2], x2 - textPadding - textMoveDis * (numctr - ctr) / numctr, y2 - textPadding);} else {x2 += line;ctx.textAlign = \"left\";ctx.lineTo(parseInt(x2 + linePadding) + 0.5, parseInt(yMove) + 0.5);ctx.fillText(dataArr[n][2], x2 + textPadding + textMoveDis * (numctr - ctr) / numctr, y2 - textPadding);}ctx.stroke();}ctx.save();ctx.translate(ox, oy);ctx.rotate((Math.PI * 2 / numctr) * ctr / 2);ctx.strokeStyle = \"rgba(0,0,0,\" + 0.5 * ctr / numctr + \")\";ctx.beginPath();ctx.arc(0, 0, (radius + 20) * ctr / numctr, 0, Math.PI * 2, false);ctx.stroke();for (var j = 0; j < dataArr.length; j++) {endAngle = endAngle + new_data_arr[j] * ctr / numctr * Math.PI * 2; ctx.beginPath();ctx.moveTo(0, 0); ctx.arc(0, 0, radius * ctr / numctr, startAngle, endAngle, false);ctx.fillStyle = dataArr[j][1];if (mouseMove && ctx.isPointInPath(mousePosition.x * 2, mousePosition.y * 2)) {ctx.globalAlpha = 0.8;}ctx.closePath();ctx.fill();ctx.globalAlpha = 1;startAngle = endAngle; if (j == dataArr.length - 1) {startAngle = endAngle = 90 * Math.PI / 180;}}ctx.restore();if (ctr < numctr) {ctr++;setTimeout(function () {ctx.clearRect(-canvas.width, -canvas.height, canvas.width * 2, canvas.height * 2);drawMarkers();pieDraw();}, speed *= 1.085);}}var mouseTimer = null;canvas.addEventListener(\"mousemove\", function (e) {e = e || window.event;if (e.offsetX || e.offsetX == 0) {mousePosition.x = e.offsetX;mousePosition.y = e.offsetY;} else if (e.layerX || e.layerX == 0) {mousePosition.x = e.layerX;mousePosition.y = e.layerY;}clearTimeout(mouseTimer);mouseTimer = setTimeout(function () {ctx.clearRect(0, 0, canvas.width, canvas.height);drawMarkers();pieDraw(true);}, 10);});}";
out << "function load() {let el_wrapper = document.getElementById('wrapper');document.getElementById('lang-cn').onclick = function () {el_wrapper.className = 'lang-cn';goChart(chartData_cn);};document.getElementById('lang-en').onclick = function () {el_wrapper.className = 'lang-en';goChart(chartData_en);};let nav_lang = (location.hash || '').replace(/#/, '');if (nav_lang === 'cn' || nav_lang === 'en') {el_wrapper.className = 'lang-' + nav_lang;}let images = document.getElementsByClassName(\"pic\");let lens = images.length;let popup = document.getElementById(\"popup\");function show(event) {event = event || window.event;let target = document.elementFromPoint(event.clientX, event.clientY);showBig(target.src, target.title, target.alt);}for (let i = 0; i < lens; i++) {images[i].onclick = show;}popup.onclick = function () {popup.getElementsByTagName(\"img\")[0].src = \"\";popup.getElementsByTagName(\"img\")[0].title = \"\";popup.getElementsByTagName(\"img\")[0].alt = \"\";popup.style.display = \"none\";popup.style.zIndex = \"-1\";};function showBig(src, title, alt) {popup.getElementsByTagName(\"img\")[0].src = src;popup.getElementsByTagName(\"img\")[0].title = title;popup.getElementsByTagName(\"img\")[0].alt = alt;popup.style.display = \"block\";popup.style.zIndex = \"999999\";}draw();}";
out << "function draw() {goChart(chartData_cn);}</script></head>";
}
//body top
{
out << "<body onload=\"load()\"><div id=\"wrapper\" class=\"lang-cn\">";
out << "<div id=\"lang\"><ul><li><a href=\"#cn\" id=\"lang-cn\" title=\"" << irg3_utils_s_to_utf8("简体中文") << "\">cn</a></li><li><a href=\"#en\" id=\"lang-en\" title=\"English\">en</a></li></ul></div>";
out << "<div class='heading'><h1>" << irg3_utils_s_to_utf8("IRG3测试报告") << "</h1><table><tr><td style=\"width: 100%; vertical-align: top;\">";
out << "<p class='attribute'><strong><span class=\"lang-cn\">" << irg3_utils_s_to_utf8("启动时间:") << "</span>";
out << "<span class=\"lang-en\">Start Time:</span></strong> " << mes_.beg_time_ << "</p>";
out << "<p class='attribute'><strong><span class=\"lang-cn\">" << irg3_utils_s_to_utf8("结束时间:") << "</span>";
out << "<span class=\"lang-en\">End Time:</span></strong> " << mes_.end_time_ << "</p>";
out << "<p class='attribute'><strong><span class=\"lang-cn\">" << irg3_utils_s_to_utf8("运行时长:") << "</span>";
out << "<span class=\"lang-en\">Duration:</span></strong> " << mes_.time_ << "</p>";
out << "<p class='attribute'><strong><span class=\"lang-cn\">" << irg3_utils_s_to_utf8("结果:") << "</span><span class=\"lang-en\">Status:</span></strong>";
out << "<span class=\"lang-cn\">" << irg3_utils_s_to_utf8("合计:") << "</span>";
out << "<span class=\"lang-en\">Total:</span>" << all_ << " ";
out << "<span class=\"lang-cn\">" << irg3_utils_s_to_utf8("通过:") << "</span>";
out << "<span class=\"lang-en\">Passed:</span>" << pass_ << " ";
out << "<span class=\"lang-cn\">" << irg3_utils_s_to_utf8("失败:") << "</span>";
out << "<span class=\"lang-en\">Failed:</span>" << fail_ << " ";
out << "<span class=\"lang-cn\">" << irg3_utils_s_to_utf8("错误:") << "</span>";
out << "<span class=\"lang-en\">Error:</span>" << error_ << " ";
out << "<span class=\"lang-cn\">" << irg3_utils_s_to_utf8("跳过:") << "</span>";
out << "<span class=\"lang-en\">Skipped:</span>" << skip_ << " </p><p class='description'>";
out << irg3_utils_s_to_utf8("注:该网页的实现为网上代码,本人通过借鉴代码来进行修改,原代码中标签的作者名为:刘士");
out << "</p></td><td><div height=\"400\" width=\"600\"><canvas id=\"chart\" style=\"border: 1px solid #A4E2F9;\"> ";
out << irg3_utils_s_to_utf8("你的浏览器不支持HTML5 canvas");
out << "</canvas></div></td></tr></table></div>";
}
//body bottom
{
out << "<table id='result_table'><tr id='header_row'>";
std::string strs_[][2] = { {"序号","NO"},{"测试组/测试用例","Test Group/Test case"},
{"脚本数","Scripts"},{"通过","Passed"},{"失败","Failed"},{"错误","Erroneous"},
{"跳过","Skipped"},{"统计","Statistics"},{"计数","Count"},{"查看","View"} };
for (int i = 0; i < 10; i++) {
out << "<th><span class=\"lang-cn\">" << irg3_utils_s_to_utf8(strs_[i][0].c_str()) << "</span><span class=\"lang-en\">" << strs_[i][1] << "</span></th>";
}
out << "</tr>";
for (auto it : vecs_) {
report_type(out, it);
}
out << "<tr id='total_row'><td> </td>";
out << "<td><span class=\"lang-cn\">" << irg3_utils_s_to_utf8("合计") << "</span><span class=\"lang-en\">Total</span></td>";
out << "<td>" << scripts_ << "</td>";
out << "<td class=\"passCase\">" << pass_ << "</td>";
out << "<td class=\"failCase\">" << fail_ << "</td>";
out << "<td class=\"errorCase\">" << error_ << "</td>";
out << "<td class=\"skipCase\">" << skip_ << "</td>";
out << "<td style=\"text-align:right;\">" << statistics_ << "</td>";
out << "<td>" << all_ << "</td>";
out << "<td> </td></tr></table>";
out << "<div id='ending'> </div><div id=\"popup\"><div class=\"bg\"><img src=\"\" alt=\"\" /></div></div>";
out << "</div></body></html>";
}
}
};
#define IRG3_REPORT_HTML(irg3_mes_,irg3_cont_) Irg3_ReportHtml::getInstance()->report(##irg3_mes_,##irg3_cont_);
//==========================================================================
// 宏定义
//==========================================================================
#endif // !_IRG3_REPORT_HPP_
irg3_utils.hpp(常用的工具类)
#ifndef _IRG3_UTILS_H_
#define _IRG3_UTILS_H_
#include< windows.h >
#include <tchar.h>
#include <string>
#include <regex>
#include <vector>
//===============================================================================================
//用来比较连个字符串是否相等
inline bool irg3_utils_cmp_str(const char* buf, const char* cmd) {
if (buf == nullptr || cmd == nullptr)
return false;
while (*buf && *cmd) {
if (*buf != *cmd) {
break;
}
++buf;
++cmd;
}
if (*cmd || *buf) {
return false;
}
return true;
}
//===============================================================================================
//用来判断字符串是否满足正则表达式
inline bool irg3_utils_regex_match(std::string& str_, const char* pattern_str_) {
if (pattern_str_ == nullptr) {
return false;
}
std::regex pattern(pattern_str_);
std::smatch res;
if (std::regex_match(str_, res, pattern)) {
return true;
}
return false;
}
inline bool irg3_utils_regex_match(const char* str_, const char* pattern_str_) {
if (str_ == nullptr || pattern_str_ == nullptr) {
return false;
}
std::string str_temp_ = str_;
return irg3_utils_regex_match(str_temp_, pattern_str_);
}
//===============================================================================================
/*
* 将ipv4和端口号进行加密,生成一个十二字符的字符串
* return 指向buf_
*/
inline char* irg3_utils_decryp_ip_port(char* buf_, const char* ip_, int port_) {
if (buf_ == nullptr || ip_ == nullptr) {
return nullptr;
}
if (port_ > 65535 || port_ < 0) {
return nullptr;
}
int order_arr_[] = { 2,0,5,3,1,4 };
int val_[6];
if (!irg3_utils_regex_match(ip_, "((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)")) {
return nullptr;
}
sscanf_s(ip_, "%d.%d.%d.%d", &val_[0], &val_[1], &val_[2], &val_[3]);
val_[4] = port_ >> 8;
val_[5] = port_ & 0xFF;
//交换顺序
for (int i = 0; i < 6; i++) {
if (val_[i] == val_[order_arr_[i]])continue;
val_[i] = val_[i] ^ val_[order_arr_[i]];
val_[order_arr_[i]] = val_[order_arr_[i]] ^ val_[i];
val_[i] = val_[i] ^ val_[order_arr_[i]];
}
//重新生成字符串
char* p = buf_;
for (int i = 0; i < 6; i++) {
*p++ = (val_[i] / 16) + 'G';
*p++ = (val_[i] % 16) + 'C';
}
*p = '\0';
return buf_;
}
/*
* 将decryp_ip_port加密后的字符串解密,获取ipv4和端口号
*/
inline bool irg3_utils_encryp_ip_port(const char* buf_, char* ip_, int* port_) {
if (buf_ == nullptr || ip_ == nullptr || port_ == nullptr) {
return false;
}
int order_arr_[] = { 2,0,5,3,1,4 };
int val_[6];
const char* p = buf_;
int i = 0;
while (*p && *(p + 1)) {
if (i == 6) {
break;
}
val_[i++] = ((*p - 'G') * 16) + (*(p + 1) - 'C');
p += 2;
}
if (i != 6) {
return false;
}
//交换顺序
for (int i = 5; i >= 0; i--) {
if (val_[i] == val_[order_arr_[i]])continue;
val_[i] ^= val_[order_arr_[i]];
val_[order_arr_[i]] ^= val_[i];
val_[i] ^= val_[order_arr_[i]];
}
sprintf(ip_, "%d.%d.%d.%d", val_[0], val_[1], val_[2], val_[3]);
*port_ = (val_[4] << 8) + val_[5];
return true;
}
//===============================================================================================
/*
* 将字符串转成int类型
*/
inline bool irg3_utils_stoi(const char* buf_, int& val_) {
val_ = 0;
if (buf_ == nullptr) {
return false;
}
const char* p = buf_;
bool flag_ = false;
if (*p == '-') {
flag_ = true;
p++;
}
while (*p) {
if (*p < '0' || *p > '9') {
break;
}
val_ = val_ * 10 + (*p++ - '0');
}
val_ = flag_ ? -val_ : val_;
return true;;
}
//===============================================================================================
//用来比较一个字符串是否另一个字符串前缀
inline bool irg3_utils_with_str(const char* buf_, const char* start_, const char* end_) {
if (buf_ == nullptr || (start_ == nullptr && end_ == nullptr)) {
return false;
}
const char* p = buf_;
const char* q = start_;
if (start_ != nullptr) {
while (*p && *q) {
if (*p != *q) {
break;
}
++p;
++q;
}
if (*q) {
return false;
}
}
if (end_ != nullptr) {
q = end_;
while (*p) { ++p; }
while (*q) { ++q; }
while (p != buf_ && q != end_) {
if (*p != *q) {
break;
}
--p;
--q;
}
if (q != end_) {
return false;
}
}
return true;
}
//===============================================================================================
//获取一个字符串长度
inline int irg3_utils_get_size(const char* str_) {
if (str_ == nullptr) {
return -1;
}
int len = 0;
while (*str_) {
++len;
++str_;
}
return len;
}
//===============================================================================================
/*
* 获取文件状态
* path 文件路径
* return 0 路径不存在 1 文件夹 2 文件 -1 未知
*/
inline int irg3_utils_file_stat(const char* path) {
struct _stat st;
if (_stat(path, &st) == 0) {
if (st.st_mode & S_IFDIR) {
return 1;
}
else if (st.st_mode & S_IFREG) {
return 2;
}
return -1;
}
return 0;
}
//===============================================================================================
/*
* 使用sunday算法,判断字符串s中是否包含字符串p
*/
inline int irg3_utils_contain(const char* s, int n, const char* p, int m) {
if (s == nullptr || p == nullptr || n == -1 || m == -1) {
return -1;
}
int next[256];
for (int i = 0; i < 256; i++)
next[i] = -1;
for (int i = 0; i < m; i++) {
next[(p[i] & 0xff)] = i;
}
int j;
int k;
int i = 0;
while (i <= n - m) {
j = i;
k = 0;
while (j < n && k < m && (s[j]) == (p[k]))
j++, k++;
if (k == m)
return i;
if (i + m < n)
i += (m - next[(s[i + m] & 0xff)]);
else
break;
}
return -1;
}
//===============================================================================================
// std::string 转换为 UTF-8 编码
inline std::string irg3_utils_s_to_utf8(const std::string& str)
{
int nwLen = ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0);
wchar_t* pwBuf = new wchar_t[nwLen + 1];//一定要加1,不然会出现尾巴
ZeroMemory(pwBuf, nwLen * 2 + 2);
::MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.length(), pwBuf, nwLen);
int nLen = ::WideCharToMultiByte(CP_UTF8, 0, pwBuf, -1, NULL, NULL, NULL, NULL);
char* pBuf = new char[nLen + 1];
ZeroMemory(pBuf, nLen + 1);
::WideCharToMultiByte(CP_UTF8, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL);
std::string retStr(pBuf);
delete[]pwBuf;
delete[]pBuf;
pwBuf = NULL;
pBuf = NULL;
return retStr;
}
inline std::string irg3_utils_s_to_utf8(const std::string&& str)
{
return irg3_utils_s_to_utf8(str);
}
//===============================================================================================
// 将utf-8转成gbk
inline std::string irg3_utils_utf8_to_gb(const char* str)
{
std::string result;
WCHAR* strSrc;
LPSTR szRes;
//获得临时变量的大小
int i = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
strSrc = new WCHAR[i + 1];
MultiByteToWideChar(CP_UTF8, 0, str, -1, strSrc, i);
//获得临时变量的大小
i = WideCharToMultiByte(CP_ACP, 0, strSrc, -1, NULL, 0, NULL, NULL);
szRes = new CHAR[i + 1];
WideCharToMultiByte(CP_ACP, 0, strSrc, -1, szRes, i, NULL, NULL);
result = szRes;
delete[]strSrc;
delete[]szRes;
return result;
}
//===============================================================================================
//获取文件大小
inline size_t irg3_utils_get_file_size(char* filename)
{
struct stat statbuf;
if (filename == nullptr) {
return -1;
}
if (stat(filename, &statbuf)) {
return 0;
}
return statbuf.st_size;
}
//===============================================================================================
//比较两个文件是否相等
inline bool compareFiles(FILE* fp0, FILE* fp1)
{
if (fp0 == nullptr || fp1 == nullptr) {
return false;
}
bool result = true;
while (result) {
char b0[1024];
char b1[1024];
size_t const r0 = fread(b0, 1, sizeof(b0), fp0);
size_t const r1 = fread(b1, 1, sizeof(b1), fp1);
result = (r0 == r1);
if (!r0 || !r1) break;
if (result) result = memcmp(b0, b1, r0) == 0 ? true : false;
}
return result;
}
//===============================================================================================
//解析email_receiver对象的数据结构
inline void irg3_utils_parase_email_receiver(const char* buf_, std::vector<std::pair<std::string, std::string> >& vec_) {
if (buf_ == nullptr || buf_[0] == '\0') {
return;
}
char str_1[64] = "";
char str_2[64] = "";
int stat_ = 0;
char* p = str_1;
while (*buf_) {
if (*buf_ == ':') {
*p = '\0';
p = str_2;
buf_++;
continue;
}
else if (*buf_ == ',') {
*p = '\0';
p = str_1;
vec_.push_back({ str_1,str_2 });
buf_++;
continue;
}
*p++ = *buf_++;
}
if (*(buf_ - 1) != ',') {
*p = '\0';
vec_.push_back({ str_1,str_2 });
}
}
//===============================================================================================
//===============================================================================================
//===============================================================================================
//===============================================================================================
//===============================================================================================
//===============================================================================================
//===============================================================================================
#endif // !_IRG3_UTILS_H_
irg3_http.h
#pragma once
#include <string>
#include <openssl/ssl.h>
#include<unordered_map>
#include <functional>
//http 接收数据格式
typedef struct irg3_http_recv_head {
std::string http_; //协议版本
int code_; //状态码
std::unordered_map<std::string, std::string> map_;
}irg3_http_recv_head_;
//http 发送数据格式
typedef struct irg3_http_send_head {
std::string method_ = "GET";
std::string pro_ = "https";
int port_ = 443;
std::string host_ = "www.baidu.com";
std::string url_ = "/";
std::string version_ = "HTTP/1.0";
std::unordered_map<std::string, std::string>map_;
const char* body_ = nullptr;
int body_size_ = -1;
irg3_http_send_head() {
map_["Connection"] = "close";
map_["Accept"] = "*/*";
map_["Accept-Language"] = "zh-Hans-CN, zh-Hans; q=0.8, en-US; q=0.5, en; q=0.3";
map_["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134";
}
}irg3_http_send_head_;
class irg3_https
{
public:
virtual ~irg3_https(void);
static irg3_https* getInstance();
//发送get请求,参数照着irg3_http_send_head对象
//message_ 接收数据时用到的缓存区,nullptr的话会自动创建一个1025大小的空间
//message_size_ message_的大小
//return -1 失败 0 成功 1 错误 2 跳过
int https_get(const char* host_, const char* url_,
char* message_ = nullptr, int message_size_ = -1);
int http_get(const char* host_, const char* url_,
char* message_ = nullptr, int message_size_ = -1);
//发送post请求,参数照着irg3_http_send_head对象
//message_ 接收数据时用到的缓存区,nullptr的话会自动创建一个1025大小的空间
//message_size_ message_的大小
//return -1 失败 0 成功 1 错误 2 跳过
int https_post(const char* host_, const char* url_, const char* body_, int body_size_,
char* message_ = nullptr, int message_size_ = -1);
int http_post(const char* host_, const char* url_, const char* body_, int body_size_,
char* message_ = nullptr, int message_size_ = -1);
//method_ 对接收到的数据进行断言判断的方法
//message_ 接收数据时用到的缓存区,nullptr的话会自动创建一个1025大小的空间
//message_size_ message_的大小
//return -1 失败 0 成功 1 错误 2 跳过
int http(irg3_http_send_head_* head_, std::function<bool(const char* msg_)>method_,
char* message_ = nullptr, int message_size_ = -1);
private:
irg3_https(void);
private:
// 建立TCP连接套接字
bool tcp_conn(const char* pSvrIp, int iSvrPort, int& socket);
//发送数据到服务端
int https_send_to_svr(const irg3_http_send_head_* head_, std::function<bool(const char* msg_)>method_,
char* message_ = nullptr, int message_size_ = -1);
int http_send_to_svr(const irg3_http_send_head_* head_, std::function<bool(const char* msg_)>method_,
char* message_ = nullptr, int message_size_ = -1);
// 组装GET请求数据
bool getGetReqData(const irg3_http_send_head_* head_, std::string& str_);
// 组装POST请求数据
bool getPostReqData(const irg3_http_send_head_* head_, std::string& str_);
// 读取响应字符串到文件
int readResponse(SSL* ssl, char* message_, int message_size_, std::function<bool(const char* msg_)>method_, bool pro_flag_ = false);
int readResponse(int socketFd, char* message_, int message_size_, std::function<bool(const char* msg_)>method_, bool pro_flag_ = false);
};
irg3_http.cpp
#include "irg3_http.h"
#include <winsock.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <openssl/crypto.h>
#include <sstream>
#include <iostream>
#include "irg3_log.hpp"
#include "irg3_report.hpp"
#include "irg3_utils.hpp"
#include <fstream>
#include <io.h>
#pragma comment(lib,"libssl.lib")
#pragma comment(lib,"libcrypto.lib")
#pragma comment(lib,"ws2_32.lib")
//=======================================STATIC METHOD===============================================
//解析http接收到的头部
static bool getHttpHead(int socketFd, irg3_http_recv_head_* head_ = nullptr);
static bool getHttpHead(SSL* ssl, irg3_http_recv_head_* head_ = nullptr);
//解析http接收到的数据
//http1.0和1.1在接收到text/html类型的数据不一样,1.1会在数据中加入长度,最大未十六进制8000,如果不进行对应处理,会数据的显示
//经过fiddle抓包验证,从http1.1往后都需要进行额外处理
static int https_1_1(SSL* ssl);
static int http_1_1(int socket_);
//========================================STATIC=====================================================
static bool getHttpHead(int socketFd, irg3_http_recv_head_* head_) {
char key_[64];
char val_[128];
int stat_ = 0;
int readLen = 0;
char pHeader[1] = { 0 };
int i = 0;
char* p = key_;
if (head_ == nullptr) {
//去除协议头,不保存
IRG3_LOG_INFO("去除协议头,不保存");
while ((readLen = recv(socketFd, pHeader, 1, 0)) == 1) {
if (pHeader[0] == '\r' || pHeader[0] == '\n') {
i++;
if (i == 4) {
break;
}
continue;
}
i = 0;
}
return true;
}
// 响应头以\r\n\r\n 结束, 此处判断头是否传输完成
//请求行
while ((readLen = recv(socketFd, pHeader, 1, 0)) == 1) {
if (pHeader[0] == '\r' || pHeader[0] == '\n') {
i++;
if (i == 2) {
break;
}
*p = '\0';
irg3_utils_stoi(key_, head_->code_);
continue;
}
else if (pHeader[0] == ' ' && stat_ == 0) {
*p = '\0';
head_->http_ = key_;
p = key_;
stat_ = 1;
}
else {
*p++ = pHeader[0];
}
i = 0;
}
p = key_;
stat_ = 0;
//请求头
while ((readLen = recv(socketFd, pHeader, 1, 0)) == 1) {
if (pHeader[0] == '\r' || pHeader[0] == '\n') {
i++;
stat_ = 0;
if (i == 4) {
break;
}
else if (i == 1) {
*p = '\0';
int k_ = 1;
while (head_->map_.count(key_) == 1) {
sprintf(p, "_%d\0", k_);
}
head_->map_[key_] = val_;
p = key_;
}
else if (i == 2) {
p = key_;
}
continue;
}
else if (pHeader[0] == ':' && stat_ == 0) {
*p = '\0';
p = val_;
stat_ = 1;
}
else {
*p++ = pHeader[0];
}
i = 0;
}
IRG3_LOG_INFO("成功读取协议头");
return true;
}
static bool getHttpHead(SSL* ssl, irg3_http_recv_head_* head_) {
if (ssl == nullptr) {
return false;
}
char key_[64];
char val_[256];
int stat_ = 0;
int readLen = 0;
char pHeader[1] = { 0 };
int i = 0;
char* p = key_;
if (head_ == nullptr) {
//去除协议头,不保存
while ((readLen = SSL_read(ssl, pHeader, 1)) == 1) {
if (pHeader[0] == '\r' || pHeader[0] == '\n') {
i++;
if (i == 4) {
break;
}
continue;
}
i = 0;
}
return true;
}
// 响应头以\r\n\r\n 结束, 此处判断头是否传输完成
//请求行
while ((readLen = SSL_read(ssl, pHeader, 1)) == 1) {
if (pHeader[0] == '\r' || pHeader[0] == '\n') {
i++;
if (i == 2) {
break;
}
*p = '\0';
irg3_utils_stoi(key_, head_->code_);
continue;
}
else if (pHeader[0] == ' ' && stat_ == 0) {
*p = '\0';
head_->http_ = key_;
p = key_;
stat_ = 1;
}
else {
*p++ = pHeader[0];
}
i = 0;
}
p = key_;
stat_ = 0;
char* q = nullptr;
//请求头
while ((readLen = SSL_read(ssl, pHeader, 1)) == 1) {
if (pHeader[0] == '\r' || pHeader[0] == '\n') {
i++;
if (i == 4) {
break;
}
else if (i == 1) {
*p = '\0';
int k_ = 1;
while (head_->map_.count(key_) == 1) {
sprintf(q, "_%d\0", k_++);
}
head_->map_[key_] = val_;
p = key_;
}
else if (i == 2) {
p = key_;
stat_ = 0;
}
continue;
}
else if (pHeader[0] == ':' && stat_ == 0) {
*p = '\0';
q = p;
p = val_;
stat_ = 1;
}
else {
*p++ = pHeader[0];
}
i = 0;
}
return true;
}
static int https_1_1(SSL* ssl) {
int readLen = 0;
char pHeader[1] = { 0 };
int i = 0;
int val_ = 0;
// 响应头以\r\n结束, 此处判断头是否传输完成
while ((readLen = SSL_read(ssl, pHeader, 1)) == 1) {
if (pHeader[0] == '\r' || pHeader[0] == '\n') {
i++;
if (i == 2) {
break;
}
}
if (pHeader[0] >= '0' && pHeader[0] <= '9') {
val_ = val_ * 16 + (pHeader[0] - '0');
}
else if (pHeader[0] >= 'a' && pHeader[0] <= 'f') {
val_ = val_ * 16 + (pHeader[0] - 'a' + 10);
}
}
//val_代表数据量,数据以\r\n结束,数据长度+2
return val_ + 2;
}
static int http_1_1(int socket_) {
int readLen = 0;
char pHeader[1] = { 0 };
int i = 0;
int val_ = 0;
// 响应头以\r\n\r\n 结束, 此处判断头是否传输完成
while ((readLen = recv(socket_, pHeader, 1, 0)) == 1) {
if (pHeader[0] == '\r' || pHeader[0] == '\n') {
i++;
if (i == 2) {
break;
}
}
if (pHeader[0] >= '0' && pHeader[0] <= '9') {
val_ = val_ * 16 + (pHeader[0] - '0');
}
else if (pHeader[0] >= 'a' && pHeader[0] <= 'f') {
val_ = val_ * 16 + (pHeader[0] - 'a' + 10);
}
}
return val_ + 2;
}
//=======================================HTTPS=================================================
irg3_https::irg3_https(void) {
}
irg3_https::~irg3_https(void) {
}
irg3_https* irg3_https::getInstance()
{
static irg3_https httpsClient;
return &httpsClient;
}
int irg3_https::https_get(const char* host_, const char* url_, char* message_, int message_size_) {
irg3_http_send_head_ head_;
head_.method_ = "GET";
head_.pro_ = "https";
head_.port_ = 443;
head_.host_ = host_;
head_.url_ = url_;
return https_send_to_svr(&head_,nullptr, message_, message_size_);
}
int irg3_https::http_get(const char* host_, const char* url_, char* message_, int message_size_) {
irg3_http_send_head_ head_;
head_.method_ = "GET";
head_.pro_ = "http";
head_.port_ = 80;
head_.host_ = host_;
head_.url_ = url_;
return http_send_to_svr(&head_,nullptr, message_, message_size_);
}
int irg3_https::https_post(const char* host_, const char* url_, const char* body_, int body_size_, char* message_, int message_size_) {
irg3_http_send_head_ head_;
head_.method_ = "POST";
head_.pro_ = "https";
head_.port_ = 443;
head_.host_ = host_;
head_.url_ = url_;
head_.body_ = body_;
head_.body_size_ = body_size_;
return https_send_to_svr(&head_,nullptr, message_, message_size_);
}
int irg3_https::http_post(const char* host_, const char* url_, const char* body_, int body_size_, char* message_, int message_size_) {
irg3_http_send_head_ head_;
head_.method_ = "POST";
head_.pro_ = "http";
head_.port_ = 80;
head_.host_ = host_;
head_.url_ = url_;
head_.body_ = body_;
head_.body_size_ = body_size_;
return http_send_to_svr(&head_,nullptr, message_, message_size_);
}
int irg3_https::http(irg3_http_send_head_* head_, std::function<bool(const char*msg_)>method_,
char* message_, int message_size_) {
if (head_ == nullptr) {
return -1;
}
if (head_->pro_ == "http") {
return http_send_to_svr(head_,method_, message_, message_size_);
}
else if (head_->pro_ == "https") {
return https_send_to_svr(head_,method_, message_, message_size_);
}
}
int irg3_https::http_send_to_svr(const irg3_http_send_head_* head_, std::function<bool(const char* msg_)>method_, char* message_, int message_size_) {
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
return -1;
}
int stat_ = -1;
int socketFd = 0;;
do {
char* pSvrIp = NULL;
struct hostent* pHostent = NULL;
pHostent = gethostbyname(head_->host_.c_str());
if (pHostent == NULL) {
IRG3_LOG_ERROR("获取域名 %s 的ip地址失败", head_->host_.c_str());
}
pSvrIp = inet_ntoa(*(struct in_addr*)pHostent->h_addr_list[0]);
// 1.建立TCP连接
if (!tcp_conn(pSvrIp, head_->port_, socketFd)) {
IRG3_LOG_ERROR("与服务器 %s 建立连接失败", pSvrIp);
break;
}
//获取数据
std::string strReqData;
if (head_->method_ == "GET") {
getGetReqData(head_, strReqData);
}
else if (head_->method_ == "POST") {
getPostReqData(head_, strReqData);
}
IRG3_LOG_INFO("开始发送数据");
//发送数据
if (send(socketFd, strReqData.c_str(), strReqData.size(), 0) == SOCKET_ERROR) {
IRG3_LOG_ERROR("发送数据失败");
break;
}
IRG3_LOG_INFO("结束发送数据");
IRG3_LOG_INFO("开始接收首部数据");
5.读取响应数据
irg3_http_recv_head_ recv_head_;
//读取http协议头部
getHttpHead(socketFd, &recv_head_);
{
IRG3_REPORT_INFO("接收的首部数据:")
IRG3_REPORT_TEXT_LOCK;
IRG3_REPORT_TEXT("%s %d\n", recv_head_.http_.c_str(), recv_head_.code_);
for (auto& it : recv_head_.map_) {
IRG3_REPORT_TEXT(it.first.c_str());
IRG3_REPORT_TEXT(" = ");
IRG3_REPORT_TEXT(it.second.c_str());
IRG3_REPORT_TEXT("\n");
}
IRG3_REPORT_TEXT_UNLOCK;
}
std::string& content_type_ = recv_head_.map_["Content-Type"];
//iRet = readResponse(socketFd, path_, message_, message_size_);
//http1.1在接收到数据会分成一块一块,每块都会插入对应长度,以\r\n结尾,需要进行特殊处理
if (irg3_utils_contain(head_->version_.c_str(), head_->version_.length(), "1.1", 3) != -1 &&
irg3_utils_contain(content_type_.c_str(), content_type_.length(), "text/html", 9) != -1) {
//http/1.1 返回中Content-Type: text/html会比较特别,需要额外处理
stat_ = readResponse(socketFd, message_, message_size_, method_,true);
}
else {
stat_ = readResponse(socketFd, message_, message_size_, method_);
}
} while (false);
if (socket) {
IRG3_LOG_INFO("关闭socket连接:%d", socketFd);
closesocket(socketFd);
}
WSACleanup();
return stat_;
}
int irg3_https::https_send_to_svr(const irg3_http_send_head_* head_, std::function<bool(const char* msg_)>method_, char* message_, int message_size_)
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
return -1;
}
int stat_ = -1;
int socketFd = 0;
SSL_CTX* ctx = 0;
SSL* ssl = 0;
do
{
char* pSvrIp = NULL;
struct hostent* pHostent = NULL;
pHostent = gethostbyname(head_->host_.c_str());
if (pHostent == NULL) {
IRG3_LOG_ERROR("获取域名 %s 的ip地址失败", head_->host_.c_str());
break;
}
pSvrIp = inet_ntoa(*(struct in_addr*)pHostent->h_addr_list[0]);
// 1.建立TCP连接
if (!tcp_conn(pSvrIp, head_->port_, socketFd)) {
IRG3_LOG_ERROR("与服务器 %s 建立连接失败", pSvrIp);
break;
}
// 2.SSL初始化, 关联Socket到SSL,并建立连接
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
ctx = SSL_CTX_new(SSLv23_client_method());
if (ctx == NULL) {
IRG3_LOG_ERROR("新建一个SSL对象失败");
break;
}
ssl = SSL_new(ctx);
SSL_set_fd(ssl, socketFd);
int retCode = SSL_connect(ssl);
if (retCode != 1) {
IRG3_LOG_ERROR("与服务器 %s 建立SSL连接失败", pSvrIp);
break;
}
std::string strReqData;
if (head_->method_ == "GET") {
getGetReqData(head_, strReqData);
}
else if (head_->method_ == "POST") {
getPostReqData(head_, strReqData);
}
// 4.通过SSL发送数据,数据量不大一次write就够了,如果是文件上传就需要循环写了。
if (head_->method_ == "POST"&&head_->body_[0] == 'i' && head_->body_[1] == '\0') {
//发送前面的数据
SSL_write(ssl, strReqData.c_str(), strReqData.length());
if (irg3_utils_file_stat((head_->body_ + 2)) != 2) {
break;
}
// 使用 "rb" 读取二进制方式打开文件
FILE* p = fopen((head_->body_ + 2), "rb");
IRG3_LOG_INFO("打开数据文件:%s", (head_->body_ + 2));
if (p == nullptr) {
IRG3_LOG_ERROR("指定的文件路径不存在:%s",(head_->body_ + 2));
break;
}
// 用于接收读取数据的缓冲区
long fileLen = filelength(fileno(p));
//发送body的长度
char buffer[1024] = { 0 };
sprintf(buffer,"Content-Length: %d\r\n\r\n\0", fileLen);
IRG3_LOG_INFO("开始发送数据");
SSL_write(ssl, buffer, irg3_utils_get_size(buffer));
int len = 0;
while ((len = fread(buffer, sizeof(char), sizeof(buffer), p)) > 0) {
SSL_write(ssl, buffer, sizeof(buffer));
}
//发送结尾
SSL_write(ssl, "\r\n\r\n", 4);
IRG3_LOG_INFO("结束发送数据");
IRG3_LOG_INFO("关闭数据文件:%s", (head_->body_ + 2));
fclose(p);
}
else {
IRG3_LOG_INFO("开始发送数据");
int writeLen = SSL_write(ssl, strReqData.c_str(), strReqData.length());
if (writeLen <= 0) {
IRG3_LOG_ERROR("发送失败");
break;
}
IRG3_LOG_INFO("结束发送数据");
}
irg3_http_recv_head_ recv_head_;
getHttpHead(ssl, &recv_head_);
{
IRG3_REPORT_INFO("接收的首部数据:")
IRG3_REPORT_TEXT_LOCK;
IRG3_REPORT_TEXT("%s %d\n",recv_head_.http_.c_str(),recv_head_.code_);
for (auto& it : recv_head_.map_) {
IRG3_REPORT_TEXT(it.first.c_str());
IRG3_REPORT_TEXT(" = ");
IRG3_REPORT_TEXT(it.second.c_str());
IRG3_REPORT_TEXT("\n");
}
IRG3_REPORT_TEXT_UNLOCK;
}
std::string &content_type_ = recv_head_.map_["Content-Type"];
//http1.1在接收到数据会分成一块一块,每块都会插入对应长度,以\r\n结尾,需要进行特殊处理
if (irg3_utils_contain(head_->version_.c_str(), head_->version_.length(), "1.1", 3) != -1&&
irg3_utils_contain(content_type_.c_str(), content_type_.length(),"text/html",9)!=-1) {
//http/1.1 返回中Content-Type: text/html会比较特别,需要额外处理
stat_ = readResponse(ssl, message_, message_size_, method_, true);
}
else {
stat_ = readResponse(ssl, message_, message_size_, method_);
}
} while (false);
// 6.关闭socket、断开连接
if (socket) {
IRG3_LOG_INFO("关闭socket连接:%d", socketFd);
closesocket(socketFd);
}
if (ctx) {
IRG3_LOG_INFO("释放CTX对象");
SSL_CTX_free(ctx);
}
if (ssl) {
SSL_shutdown(ssl);
SSL_free(ssl);
IRG3_LOG_INFO("关闭SSL连接并释放");
}
WSACleanup();
return stat_;
}
bool irg3_https::tcp_conn(const char* pSvrIp, int iSvrPort, int& socket) {
socket = ::socket(AF_INET, SOCK_STREAM, 0);
if (socket == -1) {
return false;
}
sockaddr_in sa;
sa.sin_addr.s_addr = inet_addr(pSvrIp);
sa.sin_port = htons(iSvrPort);
sa.sin_family = AF_INET;
int retCode = ::connect(socket, (struct sockaddr*)&sa, sizeof(sa));
int nNetTimeout = 1000;
setsockopt(socket,SOL_SOCKET,SO_RCVTIMEO,(char*) & nNetTimeout, sizeof(int));
if (retCode == -1) {
return false;
}
return true;
}
bool irg3_https::getGetReqData(const irg3_http_send_head_* head_, std::string& str_) {
if (head_ == nullptr) {
return false;
}
std::stringstream stream;
stream << head_->method_ << " "<<head_->pro_<<"://" << head_->host_ << head_->url_ << " " << head_->version_ << "\r\n";
stream << "Host: " << head_->host_ << "\r\n";
for (auto& it : head_->map_) {
stream << it.first << ": " << it.second << "\r\n";
}
stream << "\r\n";
str_ = stream.str();
return true;
}
bool irg3_https::getPostReqData(const irg3_http_send_head_* head_, std::string& str_) {
if (head_ == nullptr) {
return false;
}
std::stringstream stream;
stream << head_->method_ << " " << head_->pro_ << "://" << head_->host_ << head_->url_ << " " << head_->version_ << "\r\n";
stream << "Host: " << head_->host_ << "\r\n";
for (auto& it : head_->map_) {
stream << it.first << ": " << it.second << "\r\n";
}
if (!head_->map_.count("Content-Type")) {
stream << "Content-Type: application/json; charset=utf-8\r\n";
}
if (head_->body_[0] == 'i' && head_->body_[1] == '\0') {
//body里面存放的时文件路径
str_ = stream.str();
return true;
}
stream << "Content-Length: " << head_->body_size_ << "\r\n\r\n";
stream << head_->body_ << "\r\n\r\n";
str_ = stream.str();
return true;
}
int irg3_https::readResponse(SSL* ssl,char* message_, int message_size_, std::function<bool(const char* msg_)>method_, bool pro_flag_) {
if (ssl == nullptr) {
IRG3_LOG_ERROR("ssl为空");
return -1;
}
IRG3_LOG_INFO("开始读取数据");
bool flag_ = false;
if (message_ == nullptr || message_size_ == -1) {
flag_ = true;
message_ = new char[1025];
message_size_ = 1024;
IRG3_LOG_WARN("未指定读取数据的缓存空间,自动创建1024大小的缓存空间");
}
int stat_ = -1;
// 读取响应体数据,一次读1k
int len_ = 0;
IRG3_REPORT_TEXT_LOCK;
if (pro_flag_) {
IRG3_LOG_INFO("使用http1.1方式读取数据");
int all_val_ = 0;
do {
if (len_ != 0) {
message_[len_] = '\0';
if (stat_ == -1&&method_) {
//断言
stat_ = method_(message_) ? 0 : 1;
}
IRG3_REPORT_TEXT_EX(message_);
}
all_val_ -= len_;
if (all_val_ == 0) {
//获取下一块数据的大小
all_val_ = https_1_1(ssl);
}
if (all_val_ == 0) { break; }
} while ((len_ = SSL_read(ssl, message_, min(message_size_, all_val_))) > 0);
}
else {
IRG3_LOG_INFO("使用http1.0方式读取数据");
while ((len_ = SSL_read(ssl, message_, message_size_)) > 0) {
message_[len_] = '\0';
if (stat_ == -1&&method_) {
//断言
stat_ = method_(message_)?0:1;
}
IRG3_REPORT_TEXT_EX(message_);
printf("%s", message_);
}
}
IRG3_REPORT_TEXT_EX("\n");
IRG3_REPORT_TEXT_UNLOCK;
IRG3_LOG_INFO("结束读取数据");
if (flag_) {
delete[]message_;
message_ = nullptr;
IRG3_LOG_INFO("释放缓存空间");
}
return stat_;
}
int irg3_https::readResponse(int socketFd, char* message_, int message_size_, std::function<bool(const char* msg_)>method_, bool pro_flag_) {
IRG3_LOG_INFO("开始读取数据");
bool flag_ = false;
int stat_ = -1;
if (message_ == nullptr || message_size_ == -1) {
flag_ = true;
message_ = new char[1025];
message_size_ = 1024;
IRG3_LOG_WARN("未指定读取数据的缓存空间,自动创建1024大小的缓存空间");
}
int len_ = 0;
IRG3_REPORT_INFO("接收的数据:");
IRG3_REPORT_TEXT_LOCK;
if (pro_flag_) {
IRG3_LOG_INFO("使用http1.1方式读取数据");
int all_val_ = 0;
do {
if (len_ != 0) {
message_[len_] = '\0';
IRG3_REPORT_TEXT_EX(message_);
if (stat_ == -1 && method_) {
//断言
stat_ = method_(message_) ? 0 : 1;
}
}
all_val_ -= len_;
//获取下一块数据的大小
if (all_val_ == 0) { all_val_ = http_1_1(socketFd); }
if (all_val_ == 0) { break; }
} while ((len_ = recv(socketFd, message_, min(message_size_, all_val_), 0)) > 0);
}
else {
IRG3_LOG_INFO("使用http1.0方式读取数据");
while ((len_ = recv(socketFd, message_, message_size_, 0)) > 0) {
message_[len_] = '\0';
IRG3_REPORT_TEXT_EX(message_);
if (stat_ == -1 && method_) {
//断言
stat_ = method_(message_) ? 0 : 1;
}
if (len_ != message_size_) {
break;
}
}
}
IRG3_REPORT_TEXT_EX("\n");
IRG3_REPORT_TEXT_UNLOCK;
IRG3_LOG_INFO("结束读取数据");
if (flag_) {
delete[]message_;
message_ = nullptr;
IRG3_LOG_INFO("释放缓存空间");
}
return stat_;
}
test.cpp(主函数)
#include "irg3_http.h"
int main() {
irg3_https::getInstance()->https_get("www.baidu.com", "/");
}