(Qt)深受QByteArray的陷害

这两天在维护以前写的一个服务端软件,这软件使用Qt开发的。

调试了2天,终于找到了答案。原因正是我太相信Qt的接口,QByteArray类提供了转换成char *的接口,可以这么转换:

QByteArray arr;
arr.toLatin1().data();

中断一下,以前在使用arr.toAscii().data()的时候也碰到了严重的问题。
【QString和char *的转换】


对于使用数量较少的数据,arr.toLatin1().data()可以直接作为参数传递,但对于安全性要求很严格的,就要考虑重新拷贝到自建的内存区域了(char *)。

【项目介绍】:
Windows服务端,该软件模拟登陆某个网站,抓取隐藏域,自动识别验证码,生成表单域并经过url编码,post给网站,实现模拟登陆。


【调试】:
昨天开始调试,发现验证码识别正确的,模拟登录失败,这问题让我很费解。终于,在使用了curl调试功能后(CURLOPT_DEBUGFUNCTION, CURLOPT_VERBOSE),真相大白了。结果竟然是http头的表单域不完整,如下:
Content-Type: application/x-www-form-urlencoded
后面没内容了。


有bug的代码:

bool CCurl::Post(const QString &actionUrl, const QString &fieldsInfo, QString &htmlStr)
{
	//...
	curl_easy_setopt(m_pCurl, CURLOPT_POSTFIELDS, fieldsInfo.toLatin1().data());
	//...
	return true;
}

注意,这里先说明一下curl_easy_setopt函数,该函数设置了表单域,需要一个char *指针,但curl_easy_setopt函数并没有真正的拷贝char *数据,只是利用了该指针读取对应的数据(这里我经过测试)。所以才会出现curl提交的时候,表单域不完整的bug。


执行成功的代码:

bool CCurl::Post(const QString &actionUrl, const QString &fieldsInfo, QString &htmlStr)
{
	//拷贝
	int len = fieldsInfo.size();
  char *buf = new char[len+1];
  qMemCopy(buf, fieldsInfo.toLatin1().data(), len);
  buf[len] = 0;
  buf[fieldsInfo.size()] = 0;
	//...
	curl_easy_setopt(m_pCurl, CURLOPT_POSTFIELDS, fieldsInfo.toLatin1().data());
	//...
	delete []  buf;//释放
	return true;
}

自己申请内容空间保存这部分内容,当curl提交完成后,再释放内存,这样就可以保证curl提交表单域正常了。


【总结】:
使用curl,若出现问题,必须要使用CURLOPT_DEBUGFUNCTION和CURLOPT_VERBOSE两个选项。

你可能感兴趣的:((Qt)深受QByteArray的陷害)