解析http头部和c++string的高级使用技巧

Posted qianbo_insist

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了解析http头部和c++string的高级使用技巧相关的知识,希望对你有一定的参考价值。

需求

需求是解析upnp协议中的http 协议 和xml 中取得响应的内容,使用c++字符串的高级特性和http协议“\\r\\n”的特性匹配,使用std::istringstream来获取string 类中的每一行,分而治之,对每一行字符串再进行分解,达到我们解析头部的目的,事实上,没有完美无缺的技术,各个协议都是用的组合拳,把各类协议组合而得到一个完整的解决方案,upnp协议就是组播协议套上使用http 和 xml 以及soap 等来完成发现和控制。

http协议头部示例

HTTP/1.1 200 OK
CACHE-CONTROL: max-age=300
DATE: Sat, 19 Jun 2021 08:10:55 GMT
EXT:
LOCATION: http://192.168.0.104:25826/description.xml
OPT: “http://schemas.upnp.org/upnp/1/0/”; ns=0101-NLS: 1d14711e-d0b3-11eb-ba82-84a8e6833d02
SERVER: Linux/4.9.44_s5, UPnP/1.0, Portable SDK for UPnP devices/1.6.19
X-User-Agent: redsonic
ST: urn:schemas-upnp-org:device:MediaRenderer:1
USN: uuid:bb5e-21ce-1111-11b2-f918-ec9c-3235-709a-::urn:schemas-upnp-org:device:MediaRenderer:1

我们需要拿到http 的版本和返回状态如 200 和 reason like “ok”
同时解析里面的每条内容,拿到每个header 的头部 行成 map<string,string>的结构返回

定义数据结构

typedef struct s_res
{
	string httpver;
	int status;
	string reason;
}s_res;

事实上,对于以下
//GET /live/1001 HTTP/1.1
//HTTP/1.1 200 OK
//POST /live/1001 HTTP/1.1
等我们都可以使用这种方法

下面开始解析,流程是

1 解析是否有HTTP 头部四字节

2 如果有,拿到HTTP头部后的返回状态status 和 reason

3 解析剩下的每一行,每一行都是 x :y 的结构,放入map

static s_res fetch_head_info(std::string &lines, map<string,string> &hmap)
{
	s_res res = {"",-1,""};
	if (strncmp(lines.c_str(), "HTTP", 4) != 0)
	{
		//not support now
		return res;
	}
	std::istringstream s(lines);
	std::string request;
	std::getline(s, request);
	if (request[request.size() - 1] == '\\r')
	{
		request.pop_back();
		//request.erase(request.end() - 1);//the same with pop_back
		//GET /live/1001 HTTP/1.1
		//HTTP/1.1 200 OK
		size_t i = 5;
		size_t lmax = request.size();
		while (request[++i] != ' ' && i < lmax);
		if (i == lmax - 1)
			return res;

		res.httpver = request.substr(5, i - 5);
		size_t pos = ++i;
		while (request[i++] != ' ' && i < lmax);
		if (i == lmax - 1)
			return res;
		string s = request.substr(pos, i - pos);
		res.status = atoi(s.c_str());
		res.reason = request.substr(i, lmax - i);
	}
	else
		return res;

	hmap.clear();
	std::string header;
	std::string::size_type end;
      2 步开始
	while (std::getline(s, header) && header != "\\r")
	{
		if (header[header.size() - 1] == '\\r')
		{
			//header.pop_back(); //or use this function
			header.erase(header.end() - 1); //remove last char
			end = header.find(": ", 0);

			if (end != std::string::npos)
			{
				std::string key = header.substr(0, end);
				std::string value = header.substr(end + 2);
				hmap[key] = value;
			}
		}
	}

	return res;
}

这样我们有效快速使用c++ string 的高级特性获取http协议的每一行,使用方法:

	map<string, string> ss;
	s_res res = fetch_head_info(sdata, ss);
	if (res.status == 200)
	{
		string lo = ss["LOCATION"];
		//const char *url = "http://192.168.1.144:1551/AVTransport/cff47b40-2475-7ff1-7459-318ec45c9853/control.xml";
		const char *pos = lo.c_str();
		char http[256] = {"http://" };
		......
	}

其中我们的res.status == 200 代表http协议返回正常,否则我们另作处理, 也可以加上判断结构体中的reason为"OK"
接下来一篇,我们将介绍如何解析upnp协议中的xml ,而不引入更多的库,使用c语言的strstr和sscanf来解决问题。

以上是关于解析http头部和c++string的高级使用技巧的主要内容,如果未能解决你的问题,请参考以下文章

计算机网络: HTTP,HTTPS,DNS,网页解析全过程

http头部信息解析

c函数sscanf的高级技巧

HTTP头部解析

c函数sscanf的高级技巧

HTTP报文头解析