C - Распаковать сжатый http ответ - PullRequest
2 голосов
/ 05 марта 2012

У меня мало проблем с распаковкой HTTP-ответа gzip, я отделил часть данных от заголовков, но его заголовок gzip и сообщение содержат символы \ 0, которые char * принимает как нулевой терминатор, поэтому первый вопрос - как извлечь gzipped chunk?

Я не могу использовать строковые функции, такие как strcat, strlen, потому что это сжатые сжатые данные, которые содержат символы \ 0 в разных местах фрагмента.

Я использовал 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;
}

Ответы [ 3 ]

4 голосов
/ 05 марта 2012

Нет, тип char * ничего не говорит о содержимом, на которое он указывает, и не интерпретирует любое значение как терминатор. Функции str *, с другой стороны, предполагают, как представлены строки, и их нельзя использовать с двоичными данными или даже с текстовыми данными, имеющими другое представление.

Декомпрессия может быть довольно сложной, но вы можете взглянуть на zlib , которая сможет вам помочь.

2 голосов
/ 05 марта 2012

Content-Length: 12605 означает, что размер сжатого файла составляет 12605 байт.Поэтому просто скопируйте 12605 байт после заголовка сообщения в локальный буфер и передайте этот буфер функции распаковки.Также я не уверен, что ваша функция чтения сокетов читает все 12605 в одном потоке.Если нет, вам нужно добавить оставшиеся данные при следующем чтении в этот локальный буфер и после считывания 12605 байтов, а затем вызвать функцию распаковки.Нет проблем в использовании char * в качестве буфера.Проблема, с которой вы сталкиваетесь, заключается в том, что вы пытаетесь распечатать данные gzip в виде строки.

0 голосов
/ 05 марта 2012

Начало полезной нагрузки HTTP начинается после "\ r \ n \ r \ n" (после заголовка HTTP).

Используйте поле HTTP «Content-Length», чтобы получить размер полезной нагрузки HTTP.

Имея эту информацию, вы должны создать функцию для распаковки данных. С Zlib вы можете сделать это.

PS. обратите внимание, если он использует сырой формат или zlib с заголовком и трейлерами. Обычно HTTP использует заголовок и трейлер, а IMAP4 использует необработанный формат.

...