http的響應數據由下面2部分構成:
響應頭 + 數據部分
數據部分的格式由響應頭說明
一般情況下,HTTP的響應頭包含Content-Length域來指明數據的長度,例如:
有時候,服務器生成HTTP響應時,不好確定響應數據的大小,可能是大文件的下載或后臺需要復雜的邏輯處理生成頁面,這樣一般就使用chunked編碼進行傳輸。使用chunked編碼進行傳輸不用事先說明要傳輸的頁面內容的大小,通過一定的規則指明傳輸結束。
通常使用chunked編碼進行傳輸的時候,會先將數據進行壓縮。HTTP響應頭中的Content-Encoding域指明了壓縮格式。

當數據很大的時候,還會分多個塊(chunk)傳輸。chunked編碼的格式如下:

注意chunk數據長度的單位是字節,不包括后面的\r\n。以一個長度為0的塊作為結尾。
把所有的chunk數據部分組合起來存入文件,就是一個標準的gzip壓縮文件。
怎么樣把所有chunk數據部分提取出來呢?明白了上面的格式,其實就很簡單了。
如果我們是通過TCP接收的數據,首先要解決一個問題:找到chunk數據開始的地方,上面提到chunk前面是HTTP響應頭。其它先不管,響應頭是以連續的\r\n\r\n結尾的,這之后就是響應的數據部分。
假設我們有一個buffer
char *m_contentData;
里面存儲著按序收到的所有響應數據。
可以通過如下方式移動到數據部分,即chunked數據開始的地方(下圖所示:從A移動到B)
int n=0;
while(*m_contentData)
{
if (*m_contentData=='\r' || *m_contentData=='\n')
n++;
else
n=0;
if (n==4)
break;
m_contentData++;
}

定義char *m_gzipContentData保存gzip數據,可以通過如下方式獲取到gzip數據,然后寫入文件。
int len=0;
char ss[10];
char *p = m_contentData;
char *q = m_gzipData;
int gzip_len = 0;
while(1)
{
sscanf(p, "%s", ss);
//read chunk-size
len = HexToDecimal(ss); //convert hex to decimal
if (len == 0) //to chunk end
break;
p+=2; //read \r\n
memcpy(q, p, len);
q += len;
p += len;
gzip_len += len;
p += 2; //read \r\n
}
fwrite(m_gzipData, 1, gzip_len, fp);