其中在做http数据包临控时碰到gzip压缩格式,在网友发布的一些技术文章基础上,经过一段时间的研究、调试,终于解析成功。现将核心代码公布于此,希望能够和大家一起共同学习交流。
注:以下代码需要依赖zlib开源库,可以到网上搜索下载。

/* HTTP gzip decompress */
int CNNHttp::httpgzdecompress(const PVOID zdata, DWORD nzdata,                 
           PVOID data, DWORD *ndata)
{
  int err = 0;
  z_stream d_stream = {0}; /* decompression stream */
  static char dummy_head[2] = 
  {
    0x8 + 0x7 * 0x10,
    (((0x8 + 0x7 * 0x10) * 0x100 + 30) / 31 * 31) & 0xFF,
  };
  d_stream.zalloc = (alloc_func)0;
  d_stream.zfree = (free_func)0;
  d_stream.opaque = (voidpf)0;
  d_stream.next_in  = (Bytef *)zdata;
  d_stream.avail_in = 0;
  d_stream.next_out = (Bytef *)data;
  if(inflateInit2(&d_stream, 47) != Z_OK) return -1;
  while (d_stream.total_out < *ndata && d_stream.total_in < nzdata) {
    d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */
    if((err = inflate(&d_stream, Z_NO_FLUSH)) == Z_STREAM_END) break;
    if(err != Z_OK )
    {
      if(err == Z_DATA_ERROR)
      {
        d_stream.next_in = (Bytef*) dummy_head;
        d_stream.avail_in = sizeof(dummy_head);
        if((err = inflate(&d_stream, Z_NO_FLUSH)) != Z_OK) 
        {
          return -1;
        }
      }
      else return -1;
    }
  }
  if(inflateEnd(&d_stream) != Z_OK) return -1;
  *ndata = d_stream.total_out;
  return 0;
}

----------------------------------------------------------------------------------

关注
liujun_newnew
刘全QQ235980289
本版等级:

 
#14 得分:0回复于: 2012-12-18 11:52:37
class CBuffer
{
  std::vector<BYTE> vecBuf;
public:
  void Reset(DWORD dwNewSize = 0)
  {
    vecBuf.resize(dwNewSize);
  }
  void Reset(PVOID pData, DWORD nLen)
  {
    vecBuf.clear();
    Append(pData, nLen);
  }
  bool IsEmpty() const
  {
    return vecBuf.empty();
  }
  void Append(PVOID pData, DWORD nLen)
  {
    vecBuf.insert(vecBuf.end(), (PBYTE)pData, (PBYTE)pData + nLen);
  }
  PBYTE GetData()
  {
    if (vecBuf.empty())
    {
      return NULL;
    }
    return &vecBuf[0];
  }
  DWORD GetDataLength()
  {
    return vecBuf.size();
  }
  BYTE& operator[](DWORD _Pos)
  {
    return vecBuf[_Pos];
  }
};

//返回true表示此次回应的所有ChunkData数据接收结束
bool OnRecvGzipData(CBuffer& cBuf, CBuffer& cBufLeft, CBuffer& cBufTmp, bool bIsChunked, char *szGzipData, int nLen)
{
  if (!bIsChunked)
  {
    cBuf.Append((PBYTE)szGzipData, nLen);
    return false;
  }

cBufLeft.Append(szGzipData, nLen);
  szGzipData = (char*)cBufLeft.GetData();
  nLen = (int)cBufLeft.GetDataLength();

while (nLen)
  {
    int nChunkSize = strtoul(szGzipData, NULL, 16);
    if (nChunkSize == 0) 
    {
      return true;
    }
    char* pos = strstr(szGzipData, "\r\n");
    if (!pos)
    {
      goto ToExit;
    }
    pos += strlen("\r\n");
    int len = (pos - szGzipData) + nChunkSize + strlen("\r\n");
    if (len > nLen)
    {
      goto ToExit;
    }

cBuf.Append((PBYTE)pos, nChunkSize);
    szGzipData += len;
    nLen -= len;
  }

cBufLeft.Reset();
  return false;

ToExit:
  cBufTmp.Reset(szGzipData, (DWORD)nLen);
  cBufLeft.Reset(cBufTmp.GetData(), cBufTmp.GetDataLength());
  return false;
}

void OnRecvData(HANDLE hand, int iRet, char* buf)
{
  //NNLOG_TRACE_FUN();
  class CGzipDataPackBuf
  {
  public:
    CBuffer vecByteGzipDataBuf;
    CBuffer vecByteGzipDataDecodeBuf;
    CBuffer vecByteBufLeft;
    bool begin_gzip_text_html;
    bool bIsChunked;
    bool bIsUtf8;
    DWORD dwGetTickCount;

CGzipDataPackBuf()
    {
      Reset();
    }
    void Reset()
    {
      dwGetTickCount = ::GetTickCount();
      begin_gzip_text_html = false;
      bIsChunked = false;
      bIsUtf8 = false;
    }
  };

typedef std::map<HANDLE, CGzipDataPackBuf> MapCGzipDataPackBuf_T;
  static MapCGzipDataPackBuf_T s_MapCGzipDataPackBuf;
  static CCriticalSection s_csMapCGzipDataPackBuf;

if (!buf || (0 >= iRet))
  {
    return;
  }
  NNLOG_DEBUG(_T("len:%u, data:%S"), iRet, buf);
  //CWinFile::Write(CWinModule::WinGetModuleFileName() + _T(".") _T(__FUNCTION__), buf, (DWORD)iRet);

const DWORD MAX_GzipDataBuf = 1024*1024;
/*
Content-Type: text/html; charset=utf-8 
Content-Language: zh-CN

content="text/html;charset=gb2312"

Content-Type: text/html;charset=gbk
*/

char *tstr = NULL;
  bool bRecvChunkGzipDataComplete = false;
  CGzipDataPackBuf* pCGzipDataPackBuf = NULL;
  if ((15 <= iRet) 
    && (0 == StrCmpNIA(buf, "HTTP/1.1 200 OK", 15))
    && StrStrIA(buf, "Content-Type: text/html")
    && StrStrIA(buf, "Content-Encoding: gzip")
    && strstr(buf, "\r\n\r\n")//此处未考虑http头信息分包接收的情况
    )
  {
    //NNLOG_TRACE_ACTION_SCOPE(HTTP_200_OK);
    NN_WIN_SCOPED_LOCK(s_csMapCGzipDataPackBuf);
    pCGzipDataPackBuf = &s_MapCGzipDataPackBuf[hand];
  }
  else
  {
    //NNLOG_TRACE_ACTION_SCOPE(Find pCGzipDataPackBuf);
    NN_WIN_SCOPED_LOCK(s_csMapCGzipDataPackBuf);
    MapCGzipDataPackBuf_T::iterator it = s_MapCGzipDataPackBuf.find(hand);
    if (s_MapCGzipDataPackBuf.end() == it)
    {
      return;
    }
    pCGzipDataPackBuf = &it->second;
  }
  char* pos = NULL;
  if (!pCGzipDataPackBuf->begin_gzip_text_html 
    && (pos = strstr(buf, "\r\n\r\n"))
    )
  {
    //NNLOG_TRACE_ACTION_SCOPE(check http data);
    pos[0] = 0;
    if (!StrStrIA(buf, "Content-Type: text/html")
      || !StrStrIA(buf, "Content-Encoding: gzip"))
    {
      //此处未考虑http头信息分包接收的情况
      NNLOG_ASSERT(0);//上面已作初步判断,这里一般不太可能发生
      WIN_SCOPED_LOCK(s_csMapCGzipDataPackBuf);
      s_MapCGzipDataPackBuf.erase(hand);
      return;
    }

pCGzipDataPackBuf->begin_gzip_text_html = true;
    pCGzipDataPackBuf->bIsUtf8 = NULL != StrStrIA(buf, "charset=utf-8");
    pCGzipDataPackBuf->bIsChunked = NULL != StrStrIA(buf, "Transfer-Encoding: chunked");

pos[0] = '\r';//还原
    pos += strlen("\r\n\r\n");
    iRet -= (pos - buf);
    buf = pos;
    bRecvChunkGzipDataComplete = OnRecvGzipData(pCGzipDataPackBuf->vecByteGzipDataBuf, pCGzipDataPackBuf->vecByteBufLeft, pCGzipDataPackBuf->vecByteGzipDataDecodeBuf, pCGzipDataPackBuf->bIsChunked, buf, iRet);
    //if (pCGzipDataPackBuf->bIsChunked)
    //{
    //  CWinFile::Write(CWinModule::WinGetModuleFileName() + _T(".") _T(__FUNCTION__), (PVOID)buf, (DWORD)iRet);
    //}
  }
  else if (pCGzipDataPackBuf->begin_gzip_text_html)
  {
    //NNLOG_TRACE_ACTION_SCOPE(append gzip data);
    bRecvChunkGzipDataComplete = OnRecvGzipData(pCGzipDataPackBuf->vecByteGzipDataBuf, pCGzipDataPackBuf->vecByteBufLeft, pCGzipDataPackBuf->vecByteGzipDataDecodeBuf, pCGzipDataPackBuf->bIsChunked, buf, iRet);
    //if (pCGzipDataPackBuf->bIsChunked)
    //{
    //  CWinFile::Write(CWinModule::WinGetModuleFileName() + _T(".") _T(__FUNCTION__), (PVOID)buf, (DWORD)iRet);
    //}
  }
  if (!pCGzipDataPackBuf->vecByteGzipDataBuf.IsEmpty() 
    && (!pCGzipDataPackBuf->bIsChunked || bRecvChunkGzipDataComplete) 
    || (MAX_GzipDataBuf < pCGzipDataPackBuf->vecByteGzipDataBuf.GetDataLength()) )
  {
    //NNLOG_TRACE_ACTION_SCOPE(try parse gzip);
    DWORD Length = MAX_GzipDataBuf*2;
    pCGzipDataPackBuf->vecByteGzipDataDecodeBuf.Reset(Length);
    --Length;
    int iRetDec = CNNHttp::httpgzdecompress(pCGzipDataPackBuf->vecByteGzipDataBuf.GetData(), pCGzipDataPackBuf->vecByteGzipDataBuf.GetDataLength(), pCGzipDataPackBuf->vecByteGzipDataDecodeBuf.GetData(), &Length);
    if (0 == iRetDec)
    {
      //<input type=hidden name=tn value="77071064_1_pg">
      pCGzipDataPackBuf->vecByteGzipDataDecodeBuf[Length] = '\0';
      CString gzipData;
      if (pCGzipDataPackBuf->bIsUtf8)
      {
        gzipData = CA2CT((const char*)pCGzipDataPackBuf->vecByteGzipDataDecodeBuf.GetData(), CP_UTF8);
      }
      else
      {
        gzipData = CA2CT((const char*)pCGzipDataPackBuf->vecByteGzipDataDecodeBuf.GetData(), CP_ACP);
        //NNLOG_DEBUG(_T("gzip len:%u, data:%S"), Length, vecByteGzipDataDecodeBuf.GetData());
      }
      if (!gzipData.IsEmpty())
      {
        if (mc.GetdwHttpGzipPackMaxShowLen() < (DWORD)gzipData.GetLength())
        {
          gzipData = gzipData.Left(mc.GetdwHttpGzipPackMaxShowLen() / 2) + _T("...") + gzipData.Right(mc.GetdwHttpGzipPackMaxShowLen() / 2);
        }
        NNLOG_DEBUG(_T("gzip len:%u, data:%s"), gzipData.GetLength(), gzipData.GetString());
      }
      //pCGzipDataPackBuf->vecByteGzipDataBuf.Reset();
    }
    if (((0 == iRetDec) && !pCGzipDataPackBuf->bIsChunked) || bRecvChunkGzipDataComplete || (MAX_GzipDataBuf < pCGzipDataPackBuf->vecByteGzipDataBuf.GetDataLength()))
    {
      WIN_SCOPED_LOCK(s_csMapCGzipDataPackBuf);
      s_MapCGzipDataPackBuf.erase(hand);
    }
  }

{
    DWORD dwGetTickCount = ::GetTickCount();
    WIN_SCOPED_LOCK(s_csMapCGzipDataPackBuf);
    NNLOG_DEBUG(_T("s_MapCGzipDataPackBuf.size():%u"), s_MapCGzipDataPackBuf.size());
    BOOST_FOREACH(MapCGzipDataPackBuf_T::value_type& v, s_MapCGzipDataPackBuf)
    {
      CGzipDataPackBuf& gdpb(v.second);
      if (dwGetTickCount - gdpb.dwGetTickCount > 1000 * 60)
      {
        s_MapCGzipDataPackBuf.erase(v.first);
        break;//下次再处理其它的
      }
    }
  }
}

在各层hook临控的代码中调用上面函数:
DEFINE_MY_WINAPI_RET(int, recv)(
   IN SOCKET s,
   __out_bcount_part(len, return) __out_data_source(NETWORK) char FAR * buf,
   IN int len,
   IN int flags
   )
{
  LOG_TRACE_FUN();
  int iRet = recv_(s, buf, len, flags);
  OnRecvData((HANDLE)s, iRet, buf);
  return iRet;
}

DEFINE_MY_WINAPI_RET(int, WSARecv)(
    IN SOCKET s,
    __in_ecount(dwBufferCount) __out_data_source(NETWORK) LPWSABUF lpBuffers,
    IN DWORD dwBufferCount,
    __out_opt LPDWORD lpNumberOfBytesRecvd,
    IN OUT LPDWORD lpFlags,
    __in_opt LPWSAOVERLAPPED lpOverlapped,
    __in_opt LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
    )
{
  int iRet = WSARecv_(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpOverlapped, lpCompletionRoutine);
  if ((0 == iRet) && !(lpNumberOfBytesRecvd && (0 == *lpNumberOfBytesRecvd))/* || (WSA_IO_PENDING == ::GetLastError())*/)
  {
    LOG_TRACE_FUN();
    for (DWORD i = 0; i < dwBufferCount; ++i)
    {
      OnRecvData((HANDLE)s, (lpNumberOfBytesRecvd && (1 == dwBufferCount)) ? *lpNumberOfBytesRecvd : (int)lpBuffers[i].len, lpBuffers[i].buf);
    }
  }
  return iRet;
}

NTSTATUS
MYNTAPI(NtDeviceIoControlFile)(HANDLE FileHandle,
                      HANDLE Event,
                      PIO_APC_ROUTINE ApcRoutine,
                      PVOID ApcContext,
                      PIO_STATUS_BLOCK IoStatusBlock,
                      ULONG IoControlCode,
                      PVOID InputBuffer,
                      ULONG InputBufferLength,
                      PVOID OutputBuffer,
                      ULONG OutputBufferLength
                      )
{
  PAFD_WSABUF  lpBuffers = NULL;
  PAFD_INFO AfdInfo = (PAFD_INFO)InputBuffer;

if (((AFD_RECV == IoControlCode) || (IoControlCode == AFD_SEND)) && AfdInfo && AfdInfo->BufferArray)
  {
    lpBuffers = AfdInfo->BufferArray;
  }

NTSTATUS st = NtDeviceIoControlFile_(FileHandle,
    Event,
    ApcRoutine,
    ApcContext,
    IoStatusBlock,
    IoControlCode,
    InputBuffer,
    InputBufferLength,
    OutputBuffer,
    OutputBufferLength);

if (AFD_RECV == IoControlCode)
  {
    if (NT_SUCCESS(st) && lpBuffers && lpBuffers->buf)
    {
      LOG_TRACE_FUN();
      OnRecvData(FileHandle, IoStatusBlock->Information, lpBuffers->buf);
    }
  }

return st;

http数据包解析碰到gzip压缩格式的解压的更多相关文章

  1. GPS数据包格式及数据包解析

    GPS数据包解析 GPS数据包解析 目的 GPS数据类型及格式 数据格式 数据解释 解析代码 结构体定义 GPRMC解析函数 GPGGA解析函数 测试样例输出 gps数据包格式 gps数据解析 车联网 ...

  2. 一个C++版的网络数据包解析策略

    C++版的网络数据包解析策略(升级版) 一.数据包格式形如下图 二.代码 int ReceiveFromRemoteEndPoint() { int nPackageDataLength = ; ch ...

  3. 【九度OJ】题目1475:IP数据包解析 解题报告

    [九度OJ]题目1475:IP数据包解析 解题报告 标签(空格分隔): 九度OJ http://ac.jobdu.com/problem.php?pid=1475 题目描述: 我们都学习过计算机网络, ...

  4. Wireshark-过滤器-数据包解析

    目录 过滤器 数据包解析 参考 推荐阅读: https://www.cnblogs.com/zwtblog/tag/计算机网络/ 过滤器 显示过滤器 和 捕获过滤器,俩者使用非常类似. 在Wiresh ...

  5. Linux 常见压缩格式详解

    linux 文件压缩格式详解 压缩文件原理 在计算机科学和信息论中,数据压缩或者源编码是按照特定的编码机制用比未经编码少的数据比特(或者其它信息相关的单位)表示信息的过程.例如,如果我们将" ...

  6. initrd.img的压缩(制作)及解压的过程

    一.启动镜像initrd.img 文件类RedHat 系统从vmlinuz 核心引导后,会读取initrd.img 启动镜像.该文件中包含驱动模块等信息,是非常重要的文件.不同版本使用的格式不同.1. ...

  7. *.tar 用 tar –xvf 解压 *.gz 用 gzip -d或者gunzip 解压 *.tar.gz和*.tgz 用 tar –xzf 解压 *.bz2 用 bzip2 -d或者用bunzip2 解压 、*.tar.bz2用tar –xjf 解压

    解压: 1.*.tar 用 tar –xvf 解压, --skip-old-files跳过已经存在的文件,压缩用tar -cvf 2.*.bz2 用 bzip2 -d或者用bunzip2 解压 3.* ...

  8. linux 中压缩记得压缩用c,解压用x

    tar -c: 建立压缩档案-x:解压-t:查看内容-r:向压缩归档文件末尾追加文件-u:更新原压缩包中的文件 这五个是独立的命令,压缩解压都要用到其中一个,可以和别的命令连用但只能用其中一个.下面的 ...

  9. liunx之zip格式的解压命令

    zip -r myfile.zip ./* 将当前目录下的所有文件和文件夹全部压缩成myfile.zip文件,-r表示递归压缩子目录下所有文件. 2.unzip unzip -o -d /home/s ...

随机推荐

  1. 【不积跬步,无以致千里】Linux下启动Oracle服务和监听程序

    oracle数据库是重量级的,其管理非常复杂,将其在linux平台上的启动和关闭步骤整理一下. 安装完毕oracle以后,需要创建oracle系统用户,并在/home/oracle下面的.bash_p ...

  2. Android Error

    [2016-03-27 13:00:51 - XWeChat] Dx warning: Ignoring InnerClasses attribute for an anonymous inner c ...

  3. PostgreSQL的prepare 和 execute 动作背后

    我给PostgreSQL的源代码加入了调试信息以后,会有如下表现: 我执行Prepare: postgres=# prepare s(; PREPARE postgres=# 背后的反应: ** In ...

  4. XML和HTML中常用转义字符:

    XML和HTML中都有一些特殊的字符,这些字符在XML和HTML中是不能直接使用的,如果必须使用这些字符,应该使用其对应的转义字符. XML常用转义字符: 字符 转义字符 描述 & & ...

  5. AdventureWorks Databases 2008 下载地址

    AdventureWorks Databases 2008 下载地址: RECOMMENDED DOWNLOAD  AdventureWorks2012_Database.zip example, 3 ...

  6. js大小写转换

    toUpperCase 方法返回一个字符串,该字符串中的所有字母都被转化为大写字母 sn.toUpperCase() toLowerCase 方法返回一个字符串,该字符串中的字母被转换为小写字母 sn ...

  7. windows 7 共享,未授予用户在此计算机上的请求登录类型

    刚刚重装了windows7,新下载的一个ghost版本,结果却不能共享,每次访问这台机器的共享都提示, 未授予用户在此计算机上的请求登录类型 这个情况好像是存在于win7访问win7,我用一台XP系统 ...

  8. View绘制详解(四),谝一谝layout过程

    上篇博客我们介绍了View的测量过程,这只是View显示过程的第一步,第二步就是layout了,这个我们一般译作布局,其实就是在View测量完成之后根据View的大小,将其一个一个摆放在ViewGro ...

  9. 转--object-C 与lua使用wax交互

    [51CTO独家译文]2011年6月的编程语言排行榜Lua语言一军突起,一举进入前十名.这与一年前苹果决定在iOS系统上使用Lua语言密不可分.但是,你了解如何用Lua语言在iOS上开发应用吗?51C ...

  10. 反射机制及开源框架xUitls的使用,使用HttpUtils通过断点续传下载文件

    反射: Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法: 对于任意一个对象,都能够调用它的任意一个方法和属性 Java反射机制主要提供下面几种用途: 1•在运行时判断 ...