2012-03-05 26 views
1

gzipで圧縮されたhttpレスポンスの問題はほとんどありません。ヘッダーからデータ部分を区切りましたが、gzipヘッダーとメッセージに\ 0文字が含まれています。 gzippedチャンク?C - 圧縮解除されたHTTPレスポンス

strcat、strlenのような文字列関数は、チャンク内のさまざまな場所で¥0文字を含む圧縮されたgzippedデータであるため使用できません。

私はlibcurlを使用しましたが、Cソケットよりも比較的低速です。ここ

は、サンプル応答の一部である:

HTTP/1.1 200 OK 
Cache-Control: private, max-age=0 
Content-Type: text/html; charset=utf-8 
P3P: CP="NON UNI COM NAV STA LOC CURa DEVa PSAa PSDa OUR IND" 
Vary: Accept-Encoding 
Content-Encoding: gzip 
Content-Length: 12605 
Date: Mon, 05 Mar 2012 11:46:30 GMT 
Connection: keep-alive 
Set-Cookie: _FP=EM=1; expires=Wed, 05-Mar-2014 11:46:29 GMT; domain=.bing.com; path=/ 

����ՠ����AU��o� 

サンプルコード:

#define MAXDATASIZE 1024 

char *recvData; // Holds entire gzip data 
char recvBuff[MAXDATASIZE]; // Holds gzip chunk 
int offset=0; 
while(1){ 
    recvBytes = recv(sockfd, &recvBuff, MAXDATASIZE-1, 0); 
    totalRecvBytes += recvBytes; 

    // get content length, this runs first time only as required 
    if(!clfnd){ 
     regi = regexec(&clregex, &recvBuff, 3, clmatch, 0); 
     if(!regi){ 
      strncpy(clarr, recvBuff + clmatch[2].rm_so, clmatch[2].rm_eo-clmatch[2].rm_so); 
      clarr[clmatch[2].rm_eo-clmatch[2].rm_so] = '\0'; 
      cl = atoi(clarr); 
      clfnd=1; 
      regfree(&clregex); 
      recvData = malloc(cl * sizeof(char)); 
      memset(recvData, 0, sizeof recvData); 
     } 
    } 

    // get data part from 1st iteration, furthur iterations contain only data 
    if(!datasplit){ 
     int strtidx; 
     char *datastrt = strstr(&recvBuff, "\r\n\r\n"); 
     if(datastrt != NULL){ 
      strtidx = datastrt - recvBuff + 4; 
      memcpy(recvData, recvBuff + strtidx, recvBytes-strtidx); 
      datasplit=1; 
      offset = recvBytes-strtidx; 
     } 
    } 
    else{ 
     memcpy(recvData + offset, recvBuff, recvBytes); 
     offset += recvBytes; 
    } 
    if (offset >= cl) 
     break; 
} 

char *outData = malloc(offset*4 * sizeof(char)); 
memset(outData, 0, sizeof outData); 
int ret = inf(recvData, offset, outData, offset*4); 

機能を膨らま:

int inf(const char *src, int srcLen, const char *dst, int dstLen){ 
z_stream strm; 
strm.zalloc=NULL; 
strm.zfree=NULL; 
strm.opaque=NULL; 

strm.avail_in = srcLen; 
strm.avail_out = dstLen; 
strm.next_in = (Bytef *)src; 
strm.next_out = (Bytef *)dst; 

int err=-1, ret=-1; 
err = inflateInit2(&strm, MAX_WBITS+16); 
if (err == Z_OK){ 
    err = inflate(&strm, Z_FINISH); 
    if (err == Z_STREAM_END){ 
     ret = strm.total_out; 
    } 
    else{ 
     inflateEnd(&strm); 
     return err; 
    } 
} 
else{ 
    inflateEnd(&strm); 
    return err; 
} 
inflateEnd(&strm); 
printf("%s\n", dst); 
return err; 
} 
+0

あなたはいくつかの大きな問題を抱えています...受け取ったパケットごとにrecvDataを割り当ててクリアします.1)あなたがメモリをリークさせ、2)最後のrecvDataに0の束と最後のパケットが含まれていることを意味します。また、私はオフセットのあなたの使用がファンキーであると思う、それは最初のパケットのために更新されていません。 – harald

+0

おっと... 1)プログラムはrecvDataに1回だけメモリを割り当てます。基本的にはコードをコピーしていますので、問題はありませんので、その状態をコピーするのを忘れました。更新されたコードを参照してください2)オフセットは一時的に3に設定され、 memcpy()の最初のmemcpy()はそれを必要としません。2 memcpy()を書く理由は、最初のmemcpy()のIF条件でデータからヘッダを分割して、オフセットをヘッダを除いたデータバイト数バイトすなわちオフセット= recvBytes-strtidx;問題は最初のmemcpy()で\ 0文字をコピーしていないことです。recvBuffのgzippedデータから3文字しかコピーしません。 – Coder

+0

プログラムはhttp応答を解凍します! memcpy()は\ 0文字をコピーしていましたが、Eclipseデバッガはgzipチャンク全体を表示していなかったため、\ 0で破損していました。上記のコードを更新しました。 – Coder

答えて

4

いいえ、タイプchar *それが指し示す内容については何も言及しておらず、ターミネーターとしての値も解釈しません。一方、str *関数は、文字列がどのように表現されるかを前提にしており、バイナリデータや異なる表現を持つテキストデータでも使用できません。

圧縮解除はかなり複雑になる可能性がありますが、お手伝いできるのはzlibです。

+0

ありがとう、私はすでにzlibを解凍しようとしましたが、正しいgzipped入力が得られないため、-3というデータエラーが返されます。 – Coder

+0

どのようにデータをzlibに渡しますか? – harald

+0

私はチャンクでチャンクを解凍することはできますが、データ部分全体を解凍するinflate関数を持っていますが、問題はその1つのデータチャンクを選ぶ方法です。 strtok()を使って\ r \ nに分割すると、残りのチャンクを返すのではなく、最初のrecv()繰り返しから3つのgzipped文字を返します。同様に、recv()の呼び出しの残りの部分で\ 0で折れ、完全なチャンクを返します。デバッグすると、eclipseは3文字後に7 \ 0文字があることを示していました。これらの文字はgzipヘッダーの一部で、他の非ゼロ文字の一部です。 – Coder

2

Content-Length:12605は、gzippedファイルのサイズが12605バイトであることを示します。したがって、メッセージヘッダのあと12605バイトをローカルバッファにコピーし、そのバッファを圧縮解除関数に渡してください。また、ソケット読み込み機能が12605全体を1つのフローで読み取るかどうかはわかりません。そうでない場合は、次の読み込み時に残りのデータをこのローカルバッファに追加し、12605バイトが読み込まれた時点で解凍関数を呼び出す必要があります。 バッファとしてchar *を使用する際に問題はありません。 URの問題は、urがgzipデータを文字列として出力しようとしているためです。

+0

私はgzipデータを印刷していません。現在、プログラムは1回で2048バイトの反復で12605バイトを読み込み、データの途中で\ 0に出会うと切り捨てられるgzippedデータを追加できません。一時的にバッファサイズを12605に増やす必要がありますか? – Coder

+0

'char buf [12605]; int offset = 0; do { recv_len = recv(ソケット、&recv_data、2048、0); (recv_len> 0){ \t/*もしバッファにデータをコピーし、次のデータ受信のブロックをコピーするオフセット*/ \tのmemcpy(BUF +オフセット、recv_data、recv_len)をインクリメントします。 \tオフセット=オフセット+ recv_len; } }(recv_len> 0); これが役に立ったら – snibu

+0

@Coder、私たちにコードを示してください。おそらく助けになるでしょう。あなたがまだバイナリデータに文字列関数を使用しようとしているように思えます。 – harald

0

HTTPペイロードの先頭は、「\ r \ n \ r \ n」(HTTPヘッダーの後ろ)の後に開始されます。

HTTPフィールド "Content-Length"を使用して、HTTPペイロードサイズを取得します。

この情報を使用して、データを解凍する関数を作成する必要があります。 Zlibを使うとそれを行うことができます。

PS。ヘッダーと予告編を含む生の書式またはzlibを使用している場合は注意してください。通常、HTTPはヘッダとトレーラを使用し、IMAP4はrawフォーマットを使用します。

関連する問題