2014-09-17 2 views
3

Я использую curl для связи с сервером.Разбор HTTP-заголовков в C++

Когда я делаю запрос данных я получаю HTTP заголовки следуют данные в формате JPEG, разделенных границей следующим образом:

enter image description here

Мне нужно разобрать

  1. Граница строки
  2. Контент-длина.

Я скопировал поступающие данные к массив символов следующим образом:

static size_t OnReceiveData (void * pvData, size_t tSize, size_t tCount, void * pvUser) 
{ 
    printf("%*.*s", tSize * tCount, tSize * tCount, pvData); 

    char* _data; 
    if(pvData != nullptr && 0 != tCount) 
    { 
     _data = new char[tCount]; 
     memcpy(_data, pvData, tCount); 
    } 

    return (tCount); 
} 

Как лучше всего это сделать в C++ ?? Как я могу проверить и проанализировать массив _data для информации, которую я хочу? Являются ли какие-либо дополнительные библиотеки, которые я могу использовать, например?

+0

Ответ на вопрос, не используя boost или что-то еще, будет высоко оценен. – Jonny

ответ

4

можно разобрать заголовки на лету или поместить их в карту и после процесса позже. Использование find, substr методы из std::string. Посмотрите на Boost String Algorithms Library, он содержит множество алгоритмов, например. trim

например, размещать заголовки в std::map INTO и распечатать их (грубые порезы):

#include <stdlib.h> 
#include <iostream> 
#include <sstream> 
#include <string> 
#include <map> 
#include <boost/algorithm/string.hpp> 

int main(int argc, char* argv[]) { 
    const char* s = "HTTP/1.1 200 OK\r\n" 
    "Content-Type: image/jpeg; charset=utf-8\r\n" 
    "Content-Length: 19912\r\n\r\n"; 

    std::map<std::string, std::string> m; 

    std::istringstream resp(s); 
    std::string header; 
    std::string::size_type index; 
    while (std::getline(resp, header) && header != "\r") { 
    index = header.find(':', 0); 
    if(index != std::string::npos) { 
     m.insert(std::make_pair(
     boost::algorithm::trim_copy(header.substr(0, index)), 
     boost::algorithm::trim_copy(header.substr(index + 1)) 
    )); 
    } 
    } 

    for(auto& kv: m) { 
    std::cout << "KEY: `" << kv.first << "`, VALUE: `" << kv.second << '`' << std::endl; 
    } 

    return EXIT_SUCCESS; 
} 

вы получите выход:

KEY: `Content-Length`, VALUE: `19912` 
KEY: `Content-Type`, VALUE: `image/jpeg; charset=utf-8` 

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

+0

Поскольку он использует libcurl, вы знаете, что он получает один полный заголовок в каждом обратном вызове, что значительно упрощает анализ. –

1

cpp-netlib проект (на основе усиления) содержит полный MIME-анализатор (написанный с boost.spirit).

Я не очень доволен, что интерфейс анализатора, но она хорошо работает.

1

я бы поставил все заголовки в карте, после чего вы можете легко итерацию через него. Не требуется никакого повышения. Здесь приведен базовый рабочий пример с libcurl:

#include <iostream> 
#include <string> 
#include <map> 
#include <curl/curl.h> 

static size_t OnReceiveData (void * pData, size_t tSize, size_t tCount, void * pmUser) 
{ 
    size_t length = tSize * tCount, index = 0; 
    while (index < length) 
    { 
     unsigned char *temp = (unsigned char *)pData + index; 
     if ((temp[0] == '\r') || (temp[0] == '\n')) 
      break; 
     index++; 
    } 

    std::string str((unsigned char*)pData, (unsigned char*)pData + index); 
    std::map<std::string, std::string>* pmHeader = (std::map<std::string, std::string>*)pmUser; 
    size_t pos = str.find(": "); 
    if (pos != std::string::npos) 
     pmHeader->insert(std::pair<std::string, std::string> (str.substr(0, pos), str.substr(pos + 2))); 

    return (tCount); 
} 

int main(int argc, char* argv[]) 
{ 
    CURL *curl = curl_easy_init(); 
    if (!curl) 
     return 1; 

    std::map<std::string, std::string> mHeader; 

    curl_easy_setopt(curl, CURLOPT_URL, "http://www.example.com"); 
    curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, OnReceiveData); 
    curl_easy_setopt(curl, CURLOPT_HEADERDATA, &mHeader); 
    curl_easy_setopt(curl, CURLOPT_NOBODY, true); 
    curl_easy_perform(curl); 
    curl_easy_cleanup(curl); 

    std::map<std::string, std::string>::const_iterator itt; 
    for (itt = mHeader.begin(); itt != mHeader.end(); itt++) 
    { 
     if (itt->first == "Content-Type" || itt->first == "Content-Length") 
      std::cout << itt->first << ": " << itt->second << std::endl; 
    } 
}