使用zlib库函数实现http报文的解压

来源:互联网 发布:淘宝卖家发货货到付款 编辑:程序博客网 时间:2024/05/17 15:38

最近做项目的时候遇到了一个问题,那就是需要获得http响应报文主体内容,一般响应主体会通过gzip格式进行压缩,本文就是针对这种情况所写的,可以进行内存解压,而不需要保存至本地文件再解压。至于chunked分块传输方式要先进行报文重组再进行解压,本文暂不考虑。

下图是我抓取的一个http数据包,由Content-Encoding:gzip\r\n知该报文经过了gzip压缩,而压缩后的长度可以根据Content_Length=:785\r\n知为785字节,即输入参数len。压缩后的报文保存在哪里呢??我们可以查找“\r\n\r\n"这个字符串,压缩后的报文部分就保存在其接下来的内存地址之中,即输入参数source指针。

下面直接上代码:

#define MY_BUFF_SIZE = 1024int ungzip(char* source,int len,char*des)//des为解压之后的内容要保存的地方{int ret,have;int offset=0;void * buff = source;z_stream d_stream;char uncompr[MY_BUFF_SIZE]={0};//d_stream.zalloc = Z_NULL;d_stream.zfree = Z_NULL;d_stream.opaque = Z_NULL;d_stream.next_in = Z_NULL;//inflateInit和inflateInit2都必须初始化next_in和avail_ind_stream.avail_in = 0;//deflateInit和deflateInit2则不用ret = inflateInit2(&d_stream,47);//这里一定要用inflateInit2()函数进行初始化,其他的不行,我试过貌似第二个参数为31也可以,可以按照自己情况选择d_stream.next_in= buff;//下一个要解压的字节d_stream.avail_in= len;//还有多少字节需要解压do//本处含义为:开始解压,每循环一次代表解压出了1024个字节(可能只解压了几百个字节)。并将解压出的内容缓存到uncompr中,然后赋值给des;{ bzero(uncompr, MY_BUFF_SIZE); d_stream.next_out=(Bytef *)uncompr; d_stream.avail_out=MY_BUFF_SIZE; ret = inflate(&d_stream,Z_NO_FLUSH);//这里就是解压函数 assert(ret != Z_STREAM_ERROR); if (ret != Z_OK && ret != Z_STREAM_END)//解压正常返回Z_OK,解压结束返回Z_STREAM_END,     {       printf("\ninflate ret = %d\n", ret);//可能出现ret=-3,即Z_DATA_ERROR,这可能是因为数据格式不对;还有其他错误,暂时没碰到       break;     } have=MY_BUFF_SIZE-d_stream.avail_out;//这里是将uncompr赋值给des memcpy(des+offset,uncompr,have); offset+=have;}while(d_stream.avail_out==0);//结束循环条件,当最后一次循环时,解压出的字节一般不到1024字节,所以d_stream.avail_out!=0,即还有可用字节。inflateEnd(&d_stream);memcpy(des+offset,"\0",1);//\0表示结束return ret;}
对上面的数据包用上面的程序可以解压正常不报错!!

但上面代码中有一个不对的地方,那就是len的取值,这里说的是取Content_Length=:785\r\n后的785,但是当此数字比较大时会导致解压报错ret=-3,即数据格式出错,这是因为数据包再网络中传输时有最大传输长度,我们知道MTU=1560字节(我记得是这个),而tcp协议再三次握手时会协商最大接受长度MSS,该值默认为560多,具体数字我忘了,最大为1460。这意味着什么呢?我抓得另一个数据包Content_Length=:38188\r\n,但是当我调试时发现source指针在1049字节(这个数字没有意义,只不过是1460-响应报文首部长度)后就没有任何内容了,这时用上面的函数解压时当这1049个字节解压完之后必然会报ret=-3的错,因为这之后都是空,显然不符合gzip压缩格式。所以要想不报错len值应该取Content_Length和MSS(握手协商出来的)的较小者!!!!这样解压正确,但只解压了网页的一部分,对吧。要想全部解压就要把其他的包也找到并解压。这和chunked并不一样,chunked是先重组在解压,而这里是先解压在组合。因为我做的项目里面我需要的内容就在第一个包里,所以这部分没有做,希望感兴趣的同学可以补充上~~


好了,我的第一篇博客就先写到这里吧。

2 0
原创粉丝点击