Разница между заголовком и контентом ответа HTTP-сервера (сокетов)

я хочу знать, есть ли возможность узнать, где в ответе Stream заголовок заканчивается?

Предыстория вопроса заключается в следующем: я использую сокеты в c для получения контента с веб-сайта, содержимое кодируется в gzip. Я хотел бы прочитать содержимое напрямую из streamа и закодировать содержимое gzip с помощью zlib. Но как я знаю, что началось gzip-контент, и заголовок http завершен.

Я грубо пробовал два пути, которые дают мне некоторые, на мой взгляд, странные результаты. Во-первых, я читаю во всем streamе и распечатываю его в терминале, мой http-заголовок заканчивается «\ r \ n \ r \ n», как я ожидал, но вовремя, я просто получаю ответ один раз, чтобы получить заголовок а затем читать содержимое с циклом while, здесь заголовок заканчивается без «\ r \ n \ r \ n».

Зачем? И каким образом это правильный способ чтения содержимого?

Я просто дам вам код, чтобы вы могли видеть, как я получаю ответ от сервера.

//first way (gives rnrn) char *output, *output_header, *output_content, **output_result; size_t size; FILE *stream; stream = open_memstream (&output, &size); char BUF[BUFSIZ]; while(recv(socket_desc, BUF, (BUFSIZ - 1), 0) > 0) { fprintf (stream, "%s", BUF); } fflush(stream); fclose(stream); output_result = str_split(output, "\r\n\r\n"); output_header = output_result[0]; output_content = output_result[1]; printf("Header:\n%s\n", output_header); printf("Content:\n%s\n", output_content); 

,

 //second way (doesnt give rnrn) char *content, *output_header; size_t size; FILE *stream; stream = open_memstream (&content, &size); char BUF[BUFSIZ]; if((recv(socket_desc, BUF, (BUFSIZ - 1), 0) > 0) { output_header = BUF; } while(recv(socket_desc, BUF, (BUFSIZ - 1), 0) > 0) { fprintf (stream, "%s", BUF); //i would just use this as input stream to zlib } fflush(stream); fclose(stream); printf("Header:\n%s\n", output_header); printf("Content:\n%s\n", content); 

Оба дают тот же результат, что и их печать на терминале, но в этом случае вы должны распечатать еще несколько разрывов, по крайней мере, я ожидаю, потому что они теряются, разбивая строку.

Я новичок в c, поэтому я могу просто наблюдать за некоторыми легкими вещами.

Вы вызываете recv() в цикле до тех пор, пока сокет не отключится или не сработает (и неправильно записывает полученные данные в ваш stream), сохраняя все необработанные данные в вашем буфере char* . Это неверный способ чтения HTTP-ответа, особенно если используются HTTP-алименты (в этом случае в конце ответа не произойдет отключение). Вы должны следовать правилам, изложенным в RFC 2616 . А именно:

  1. Прочитайте до тех пор, пока не появится последовательность "\r\n\r\n" . Больше не читайте байтов.

  2. Анализ полученных заголовков в соответствии с правилами RFC 2616 Раздел 4.4 . Они сообщают вам фактический формат оставшихся данных ответа.

  3. Прочтите данные в формате, открытом в # 2.

  4. Проверьте полученные заголовки на наличие заголовка Connection: close если ответ использует HTTP 1.1, или отсутствие заголовка Connection: keep-alive если ответ использует HTTP 0.9 или 1.0. Если обнаружено, закройте конец соединения сокета, потому что сервер закрывает его конец. В противном случае держите соединение открытым и повторно используйте его для последующих запросов (если вы не используете соединение, и в этом случае закройте его).

  5. Обработайте полученные данные по мере необходимости.

Короче говоря, вам нужно сделать что-то более похожее на это (псевдокод):

 string headers[]; byte data[]; string statusLine = read a CRLF-delimited line; int statusCode = extract from status line; string responseVersion = extract from status line; do { string header = read a CRLF-delimited line; if (header == "") break; add header to headers list; } while (true); if ( !((statusCode in [1xx, 204, 304]) || (request was "HEAD")) ) { if (headers["Transfer-Encoding"] ends with "chunked") { do { string chunk = read a CRLF delimited line; int chunkSize = extract from chunk line; if (chunkSize == 0) break; read exactly chunkSize number of bytes into data storage; read and discard until a CRLF has been read; } while (true); do { string header = read a CRLF-delimited line; if (header == "") break; add header to headers list; } while (true); } else if (headers["Content-Length"] is present) { read exactly Content-Length number of bytes into data storage; } else if (headers["Content-Type"] begins with "multipart/") { string boundary = extract from Content-Type header; read into data storage until terminating boundary has been read; } else { read bytes into data storage until disconnected; } } if (!disconnected) { if (responseVersion == "HTTP/1.1") { if (headers["Connection"] == "close") close connection; } else { if (headers["Connection"] != "keep-alive") close connection; } } check statusCode for errors; process data contents, per info in headers list;