分类: 嵌入式
2013-07-26 00:35:40
使用QtLauncher登录163邮箱,提示:“会话已过期,请重新登录”。
经抓包分析请求头和响应头,发现当点击“登录”后,服务器响应头部分如下:
Set-Cookie: Coremail=qyWzaHbRaaiac%uCxebjllEMcVbRVxsKllHpHmZKcLEAML; path=/; domain=mail.163.com
Location:
……
Set-Cookie为返回给浏览器的Cookie,其域为mail.163.com。
Location意为当当前页加载完后,立即转到指定页。
细心观察,会发现Coremail=qyWzaHbRaaiac%uCxebjllEMcVbRVxsKllHpHmZKcLEAML的%后面字符串与中sid的值是相同的。
下一步浏览器向服务器发送的请求头部分如下:
GET /jy3/main.jsp?sid=uCxebjllEMcVbRVxsKllHpHmZKcLEAML HTTP/1.1
Host: tg1a117.mail.163.com
Cookie: Province=028; City=028; NTES_SESS=knmC3rCt8vSQt5SUmyvr21CMu2_UYTdq33voW7yy2P1hnO47rnp41.abHOZBkq3iFWt2dLNCeUEyLiL3GF4bPRlL2mGBm3BU.
……
可以看出,Cookie中没有包含Coremail。而请求的URL中有sid信息,于是猜测,可能是服务器端收到请求后,用URL中的sid值与请求头Cookie中的sid值进行比较,若相同,则登录成功,若Cookie中没有相应的值(即Coremail),则登录失败,提示“会话过期”。
既然这儿有可能出问题,那就要找出为什么Coremail没有加入到请求Cookie中,看了一天源码,终于找到了问题所在。
在Qt中有个类QNetworkCookieJar,用于存放所有的Cookie。这个类有个成员函数,QList
QList
{
Q_D(const QNetworkCookieJar);
QDateTime now = QDateTime::currentDateTime();
QList
// scan our cookies for something that matches
QList
end = d->allCookies.constEnd();
for ( ; it != end; ++it) {
if (!isParentDomain(url.host(), it->domain()))
continue;
……
if (insertIt == result.end())
result += *it;
}
return result;
}
在这个函数中,使用循环,对每个Cookie进行判断,看是否符合条件。函数isParentDomain定义如下:
static inline bool isParentDomain(QString domain, QString reference)
{
if (!reference.startsWith(QLatin1Char('.'))) //注释掉
return domain == reference; //注释掉
return domain.endsWith(reference) || domain == reference.mid(1);
}
判断Cookie的域是否以“.”开头,若不是以点开头,就判断url的主机名是否与该域相同,相同则返回true。
若Cookie域是以“.”开头,就判断url主机名是否以Cookie域为结束串,或者url主机名是否与Cookie域“.”后面的字符串相同。只要有一个为真,返回true。
举个例子:
url主机名为x1.x2.x3.com,Cookie域名为.x3.com,返回true。
url主机名为x1.x2.x3.com,Cookie域名为x3.com,返回false。
回到我们的问题上,Coremail这个Cookie的域名是mail.163.com,url的主机名是tg1a117.mail.163.com,返回的是false。而正确情况应该是返回true。
注释掉if…return…这两行,重新编译,运行,OK,问题解决。
之前登录CSDN也是登录不上,现在问题也解决了。
注意,这里用的Qt是4.5.1版的。