在C ++中解析HTTP头

时间:2014-09-17 17:34:53

标签: c++ http boost libcurl

我使用curl与服务器通信。

当我发出数据请求时,我会收到HTTP标题,然后是jpeg数据,这些数据由边界分隔,如下所示:

enter image description here

我需要解析

  1. 边界字符串
  2. 内容长度。
  3. 我已将传入的数据复制到char数组中,如下所示:

    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数组以获取我想要的信息?我可以使用任何boost库吗?

3 个答案:

答案 0 :(得分:4)

您可以动态解析标题或将其放入地图并稍后进行后期处理。 使用std::string中的findsubstr方法。 查看Boost String Algorithms Library,它包含许多算法,例如trim

e.g。将标题放入std::map并打印它们(粗略剪切):

#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`

拥有标题后,您可以提取所需的标题以进行后期处理。

答案 1 :(得分:1)

cpp-netlib项目(基于boost)包含一个完整的MIME解析器(用boost.spirit编写)。

我对解析器的界面并不是很满意,但效果很好。

答案 2 :(得分: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;
    }
}