HTTP协议有时候不返回Content-Length 该怎么办

prettysky 2006-07-14 11:42:42
比如大家可以抓包看一下
http://www.flyrom.com/PHPWind_UTF8_4.3.2/upload/ck.php?windid=

真郁闷,如果不但不返回Content-Length 而且HTTP协议头后面(#13#10#13#10)

并不是正文的开始,而是 XXX+空格+空格+#13#10后面才是正文

注:
XXX有时候是16进制的正文长度比如“d3af8”此时后面的2个空格是没有的,这样我也可以计算到长度并处理。
但有时候则是完全无意义的数字,真是搞不懂。



不过浏览器倒是完全可以处理这种情况,不知道是如何处理的。我看了HTTP的RFC但是找不到,或者哪位仁兄发来详细的HTTP RFC文档。
...全文
2863 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
prettysky 2006-07-14
  • 打赏
  • 举报
回复
另外说一下,我是以双回车(#13#10#13#10)以后的内容被认为是主体,不知道是否正确。
prettysky 2006-07-14
  • 打赏
  • 举报
回复
没有长度也可以处理,但问题是有时候 协议头结束后开始的第一字节并不是正文。

我发现好像Unlix的系统会出现这种情况,

HTTP头没有包含长度,而是在头结束后第一字节到#13#10之间是一个16进制的主体长度。

必须处理这种情况,否则得到的主体头部多出N字节。

还有一种情况更离谱,就是我上面说的,头结束后第一字节到#13#10之间是一个包含空格的未知数字,根本没法处理阿。
fim 2006-07-14
  • 打赏
  • 举报
回复
并不是所有的的HTTP文件都会返回Content-Length,有的是所谓的chunked,客户端不知道文件的大小,只能不停地接收,只到没有数据了,即recv返回0或错误
prettysky 2006-07-14
  • 打赏
  • 举报
回复
其中RecvBuffer是接收到的整个封包
prettysky 2006-07-14
  • 打赏
  • 举报
回复
赫赫,感谢2楼的提示,我找了找Chunked编码的资料自己搞定了。这100分给大家平分了吧

以下是我的代码

其中RecvBuffer是接收到的增个封包,String类型,最后处理过的RecvBuffer就是主体内容

else if Pos('transfer-encoding: chunked',LowerCase(RecvBuffer))>0 then begin
//取得正文内容,包含Chunked部分
ChunkStr:=Copy(RecvBuffer,Pos(#13#10#13#10,RecvBuffer)+4,Length(RecvBuffer));
RecvBuffer:='';
ChunkIndex:=1;
While ChunkIndex<Length(ChunkStr) do begin
//取得一个Chunk
TempStr:=Copy(ChunkStr,ChunkIndex,Pos(#13#10,ChunkStr)-1);
if TryStrToInt('$'+Trim(TempStr),Len) then begin //使用Trim是因为有些时候TempStr后面有一个空格
if Len=0 then Break;
//计主体内容
RecvBuffer:=RecvBuffer+Copy(ChunkStr,ChunkIndex+Length(TempStr)+2,Len);
end;
ChunkIndex:=ChunkIndex+Length(TempStr)+2+Len+2;
end;

如果代码有什么不足,或没有预料到的错误请指出 谢谢
ybbqy 2006-07-14
  • 打赏
  • 举报
回复
以前写过,见笑了,是datachunked.自从遇见此类BT网站过,我还是改用CHttp了.



DWORD WINAPI CHttpIO::ReceiveChunkedThread(LPVOID pParam)
{

SOCKET Socket = ((SOCKET )((void **)pParam)[0]);
char *pHtmlBuf = (char *)((void **)pParam)[1];
int nHtmlBufLen = (int)((void **)pParam)[2];
CString *pCookie = (CString *)((void **)pParam)[3];
CEvent *pCreateRecvChunkedEvent = (CEvent *)((void **)pParam)[4];
CEvent *pGetHtmlEvent = (CEvent *)((void **)pParam)[5];
pCreateRecvChunkedEvent->SetEvent();

// 接收HTTP头信息
char szRecvBuf[2048]={0};
int nRecvLen = 0;

// 找HTTP头的结尾
while(true)
{
int nTmpRecvLen = recv(Socket,(char *)szRecvBuf+nRecvLen,sizeof(szRecvBuf),0);
// 错误,悲观处理
if (nTmpRecvLen < 1)
break;
nRecvLen += nTmpRecvLen;

// 找http头的结尾
char *pHtmlPack = strstr(szRecvBuf, "\r\n\r\n");
if(pHtmlPack != NULL)
{
/*
// 找cookie
int nContentLength = {0};
for (int nCurParse = 0;nCurParse < pHtmlPack-szRecvBuf;)
{
// 取出当前行
char szCurLineData[2048] = {0};
char *pEol = strstr(szRecvBuf+nCurParse, "\r\n") + strlen("\r\n");
int nCurLineLen = pEol - (szRecvBuf+nCurParse);
memcpy(szCurLineData, szRecvBuf+nCurParse, nCurLineLen);
nCurParse += nCurLineLen;

CString strCurLineData;
strCurLineData = szCurLineData;
strCurLineData.MakeLower();
if (pCookie!=NULL)
if (strncmp("set-cookie: " , strCurLineData, strlen("set-cookie: ")) == 0)
{
char szCookie[128] = {0};
memcpy(szCookie, szCurLineData+strlen("set-cookie: "), strstr(szCurLineData, ";")-szCurLineData-strlen("set-cookie: "));
*pCookie = szCookie;
}

}

//*/

// 求HTTP包内html数据开始位置
pHtmlPack += strlen("\r\n");
memcpy(szRecvBuf, pHtmlPack, (szRecvBuf+nRecvLen) - pHtmlPack);
memset(szRecvBuf + ((szRecvBuf+nRecvLen) - pHtmlPack), 0, pHtmlPack-szRecvBuf);
nRecvLen = (szRecvBuf+nRecvLen) - pHtmlPack;
break;
}
}

// HTTP包长总度
int nHtmlPackLen = 0;
// 当前包还需要多少数据
int nHtmlPackNeedLen = 0;
// 接收HTTP中的HTML包一直到最后一个长度为0的包
do
{
// 当前HTTP包内的HTML数据位置
char *pHtmlPack = szRecvBuf;
// 处理一个段数据
// 数据已Chunked编码所以需要还原
// ,Chunked包结构类似[长度][数据......][长度][数据......][长度][数据......]
do
{
if (nHtmlPackNeedLen < 1) // 说明是一个Chunked新包
{
pHtmlPack = strstr(szRecvBuf+strlen("\r\n"), "\r\n");
if (pHtmlPack != NULL)
{
// 取得包长度

pHtmlPack += strlen("\r\n");

char szHtmlPackLen[32] = {0};
memcpy(szHtmlPackLen, szRecvBuf, pHtmlPack - szRecvBuf);
sscanf(szHtmlPackLen, "%x", &nHtmlPackLen);

nHtmlPackNeedLen = nHtmlPackLen;
}
else
{
// 该段数据长度不够,无法取出长度,继续接收.
break;
}
}
else
{
// 将数据取出给返回数据的缓冲
CString strHtmlPackBuf;
if (nHtmlPackNeedLen < szRecvBuf+nRecvLen - pHtmlPack) // 需要的数据小于现在包内的数据,说明该包数据都在当前数据段(nRecvBuf)内
strHtmlPackBuf.GetBufferSetLength(nHtmlPackNeedLen);
else // 现有数据不够需要数据,现有多少给多少
strHtmlPackBuf.GetBufferSetLength(szRecvBuf+nRecvLen - pHtmlPack);
memcpy(strHtmlPackBuf.GetBuffer(strHtmlPackBuf.GetLength()
), pHtmlPack, strHtmlPackBuf.GetLength());
strncat(pHtmlBuf, strHtmlPackBuf.GetBuffer(0), nHtmlBufLen);
// 将得到的数据从接收buf(szRecvBuf)中删除(提前)
memcpy(szRecvBuf, pHtmlPack+strHtmlPackBuf.GetLength(), (szRecvBuf+nRecvLen)-(pHtmlPack+strHtmlPackBuf.GetLength()));
nRecvLen = szRecvBuf+nRecvLen-(pHtmlPack+strHtmlPackBuf.GetLength());
memset(szRecvBuf+nRecvLen, 0, sizeof(szRecvBuf)-nRecvLen);
nHtmlPackNeedLen -= strHtmlPackBuf.GetLength();
}
}while(nRecvLen > 0 && nHtmlPackLen>0); // 当szRecvBuf有数据未处理时

int nTmpRecvLen = recv(Socket, szRecvBuf+nRecvLen, sizeof(szRecvBuf)-nRecvLen, 0);
if (nTmpRecvLen > 0)
nRecvLen += nTmpRecvLen;
else
break;

}while(nHtmlPackLen > 0 || nRecvLen > 0);

//*/
pGetHtmlEvent->SetEvent();

return 0;
}
dabaicai 2006-07-14
  • 打赏
  • 举报
回复
这个也不清楚
fim 2006-07-14
  • 打赏
  • 举报
回复
这就不懂了,第一次碰到你这样的情况,看看还有没有其它人会的?

1,593

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 网络通信/分布式开发
社区管理员
  • 网络通信/分布式开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧