【Web】C++ Http -- 记一次使用第三方http请求的问题解决
2016-06-15 02:10
549 查看
使用一个第三方的http请求,在VS里打印如下,而作者在处理时,以\r\n\r\n处理获取头部,剩余部分全部作为了body,害的我追了几个小时,wireShark抓包如下。
http分四部分:头部、头部分隔符、body长度,body
(头部)
\r\n\r\n
(bodylength)\r\n
body
看到上述 71\r\n,该被处理掉,此为body的长度(后面带了一个\r\n作为结束符)
附上wireShark的抓包图:
122bytes的数据段和VS打印的相符
细心的读者获取会看到:图中出现了(gzip):132 bytes -> 122 bytes
还没有搞懂,在 HTTP chunked response 里为什么两个 Data chunk,,分别为122 + 10,
而gizp又是怎么使用的呢??有机会继续追踪。。
附HTTP:找不到原作者是谁了,和下载地址了,非常感谢原作者的贡献:
Http.h
Http.cpp
http分四部分:头部、头部分隔符、body长度,body
(头部)
\r\n\r\n
(bodylength)\r\n
body
HTTP/1.1 200 OK\r\n Date: Tue, 14 Jun 2016 17:42:00 GMT\r\n Server: Apache/2.4.7 (Ubuntu)\r\n Vary: Accept-Encoding\r\n Connection: close\r\n Transfer-Encoding: chunked\r\n Content-Type: text/plain;charset=UTF-8\r\n \r\n\r\n 71\r\n 00rtmp://video-center.alivecdn.com/show/3-1?vhost=live.abcdedo.com\r\n 閫夋墜鐜嬪皬涓洿鎾?\r\n admin\r\n 2eCuw0F\r\n S0000007qv\r\n
看到上述 71\r\n,该被处理掉,此为body的长度(后面带了一个\r\n作为结束符)
附上wireShark的抓包图:
122bytes的数据段和VS打印的相符
细心的读者获取会看到:图中出现了(gzip):132 bytes -> 122 bytes
还没有搞懂,在 HTTP chunked response 里为什么两个 Data chunk,,分别为122 + 10,
而gizp又是怎么使用的呢??有机会继续追踪。。
附HTTP:找不到原作者是谁了,和下载地址了,非常感谢原作者的贡献:
Http.h
#pragma once #include <string> typedef bool (*httpResponseCB)(const char* data, int len, int offset, int totalsize, bool bFin, void* param) ; struct HttpResponse { public: explicit HttpResponse(){ clear();} std::string http_version; // 版本 unsigned int status_code; // 状态码 std::string status_message; // 状态 std::string header; // HTTP包头 std::string body; // HTTP返回的内容 std::string content_type; std::string modify_time; unsigned int content_length; unsigned int total_length; unsigned int offset; httpResponseCB funcResponseCB; void* param; void clear() { http_version.clear(); status_code = -1; status_message.clear(); header.clear(); content_type.clear(); modify_time.clear(); content_length = 0; total_length = 0; offset = 0; body.clear(); funcResponseCB = NULL; param = NULL; } }; class CHttpPrivate; // 封装ASIO操作 /* * @brief 发送http请求并接收结果, 单线程, 同步 */ class CHttp { public: CHttp(void); virtual ~CHttp(void); //************************************ // Method: PostRequest // FullName: CHttp::PostRequest // Access: public // Returns: bool // Qualifier: // Parameter: const std::string & szUrl // Parameter: CHttpResponse & result HTTP请求返回的结果 // Parameter: const std::string & data 默认为空, 使用GET http请求, 若不为空, 则POST HTTP请求和data //************************************ bool PostRequest(const std::string &szUrl, HttpResponse &result, const std::string &data = std::string(), int rangeStart = 0); // post bool PostRequest(const std::string &szUrl, std::string &szResult, const std::string &data = std::string()); // post //************************************ // Method: ParseUrl // FullName: CHttp::ParseUrl // Access: public // Returns: bool return false indicate invalid URL // Qualifier: // Parameter: std::string szUrl 传入URL // Parameter: std::string & szHost 解析后的host // Parameter: std::string & szParam 解析后的host参数 //************************************ bool ParseUrl(std::string szUrl, std::string &szHost, std::string &szParam); enum{ SUCCESS_OK = 0, ERR_BADURL, ERR_NETWORK, ERR_HTTPRESP, ERR_UNKNOWN }; int GetLastErr() { return m_lasterr;}; private: int m_lasterr; CHttpPrivate *p; friend class CHttpPrivate; };
Http.cpp
#include "stdafx.h" #include "Http.h" #include <vector> #include <algorithm> #include <iostream> #include <sstream> #include <boost/asio.hpp> #include <boost/algorithm/string.hpp> #include "CStringUtilUnicode.h" using boost::asio::ip::tcp; class CHttpPrivate { private: bool ParseHeader(const std::string &str, HttpResponse &result); CHttp* _d; public: CHttpPrivate(CHttp* d); enum HTTP_METHOD{ GET, POST}; bool RecvResponse(HttpResponse &result); bool connect(const std::string &szHost); void FillRequest( boost::asio::streambuf &request, HTTP_METHOD method , const std::string &szHost, const std::string &szParam, const std::string &data = std::string(), const int rangeStart = 0); boost::asio::io_service m_io_service; tcp::resolver m_resolver; tcp::socket m_socket; }; CHttpPrivate::CHttpPrivate( CHttp* d ) : m_resolver(m_io_service) , m_socket(m_io_service) { _d = d; } bool CHttpPrivate::ParseHeader(const std::string &strHeader, HttpResponse &result) { // Check that response is OK. std::istringstream response_stream(strHeader); response_stream >> result.http_version; response_stream >> result.status_code; std::string strLine; std::getline(response_stream, strLine); while (!strLine.empty()) { if (strLine.find("Content-Type:") != std::string::npos) { result.content_type = strLine.substr(strlen("Content-Type:")); result.content_type.erase(0, result.content_type.find_first_not_of(" ")); } if (strLine.find("Content-Length:") != std::string::npos) { result.content_length = atoi(strLine.substr(strlen("Content-Length:")).c_str()); result.total_length = result.content_length; } if (strLine.find("Last-Modified:") != std::string::npos) { result.modify_time = strLine.substr(strlen("Last-Modified:")); result.modify_time.erase(0, result.modify_time.find_first_not_of(" ")); } if (strLine.find("Content-Range: bytes") != std::string::npos) { std::string tmp = strLine.substr(strlen("Content-Range: bytes")); result.offset = atoi(tmp.substr(0, tmp.find('-')).c_str()); int ipos = tmp.find('/'); int ivalue = 0; if (ipos != std::string::npos) { ivalue = atoi(tmp.substr(ipos+1).c_str()); } if (ivalue) result.total_length = ivalue; } strLine.clear(); std::getline(response_stream, strLine); } /* if (result.offset < 0 && result.content_length+result.offset>0 ) result.offset += result.content_length; */ if ( result.http_version.substr(0, 5) != "HTTP/") { _d->m_lasterr = CHttp::ERR_HTTPRESP; std::cout << "Invalid response\n"; return false; } if (result.status_code != 200 && result.status_code != 206) { _d->m_lasterr = CHttp::ERR_HTTPRESP; std::cout << "Response returned with status code " << result.status_code << "\n"; return false; } return true; } bool CHttpPrivate::RecvResponse( HttpResponse &result ) { boost::asio::streambuf response; std::ostringstream packetStream; try { _d->m_lasterr = CHttp::SUCCESS_OK; // Read until EOF, writing data to output as we go. bool hasReadHeader = false; boost::system::error_code error; result.body.clear(); while (boost::asio::read(m_socket, response, boost::asio::transfer_at_least(1), error)) { packetStream.str(""); packetStream << &response; std::string packetString = packetStream.str(); std::wstring log = CUtility::Ansi2Wchar(packetString); OutputDebugString(log.c_str()); if (!hasReadHeader) { // 取出http header size_t nEndHeader = packetString.find("\r\n\r\n"); if(nEndHeader == std::string::npos) continue; hasReadHeader = true; result.header = packetString.substr(0, nEndHeader); if (!ParseHeader(result.header, result)) return false; packetString.erase(0, nEndHeader + 4); int bodyLenPos = packetString.find("\r\n"); packetString.erase(0, bodyLenPos + 2); int bodyEndPos = packetString.find("\r\n"); packetString = packetString.substr(0, bodyEndPos); std::wstring log = CUtility::Ansi2Wchar(packetString); OutputDebugString(log.c_str()); } // response.consume(response.size()); if (result.funcResponseCB) { if (!result.param) { _d->m_lasterr = CHttp::ERR_UNKNOWN; return false; } if (!result.funcResponseCB(packetString.c_str(), packetString.length(), result.offset, result.total_length, false, result.param)) { _d->m_lasterr = CHttp::ERR_UNKNOWN; return false; } } else { result.body.append(packetString); } } if (result.funcResponseCB) { result.funcResponseCB(NULL, 0, 0, result.content_length, true, result.param); } if (error != boost::asio::error::eof) { _d->m_lasterr = CHttp::ERR_UNKNOWN; throw boost::system::system_error(error); } } catch (std::exception& e) { std::cout << "Exception: " << e.what() << "\n"; if (_d->m_lasterr == CHttp::SUCCESS_OK) _d->m_lasterr = CHttp::ERR_NETWORK; return false; } return true; } void CHttpPrivate::FillRequest( boost::asio::streambuf &request, HTTP_METHOD method , const std::string &szHost, const std::string &szParam, const std::string &data /*= std::string()*/, const int rangeStart) { // Form the request. We specify the "Connection: close" header so that the // server will close the socket after transmitting the response. This will // allow us to treat all data up until the EOF as the content. std::ostream request_stream(&request); switch(method) { case GET: request_stream << "GET " ; request_stream << szParam << " HTTP/1.1\r\n"; request_stream << "Host: " << szHost << "\r\n"; break; case POST: request_stream << "POST "; request_stream << szParam << " HTTP/1.1\r\n"; request_stream << "Host: " << szHost << "\r\n"; request_stream << "Content-Length:" << data.size(); break; } request_stream << "Accept: */*\r\n"; request_stream << "Pragma: no-cache\r\n"; request_stream << "Cache-Control: no-cache\r\n"; request_stream << "Connection: close\r\n"; if (rangeStart) { request_stream << "Range: bytes=" << rangeStart << "- \r\n"; } request_stream << "\r\n"; } bool CHttpPrivate::connect( const std::string &szHost ) { // Get a list of endpoints corresponding to the server name. std::string szService ("http"); std::string szIp = szHost; int i = szHost.find(":") ; if (i != -1) { szService = szHost.substr(i+1); szIp = szHost.substr(0, i); } tcp::resolver::query query(szIp, szService); tcp::resolver::iterator endpoint_iterator = m_resolver.resolve(query), end_it; // Try each endpoint until we successfully establish a connection. tcp::resolver::iterator it = boost::asio::connect(m_socket, endpoint_iterator); if(it == end_it) return false; return true; } CHttp::CHttp(void) { p = new CHttpPrivate(this); m_lasterr = SUCCESS_OK; } CHttp::~CHttp(void) { delete p; } bool CHttp::ParseUrl(std::string szUrl, std::string &szHost, std::string &szParam) { do { if(szUrl.empty()) break; boost::trim(szUrl); std::string szProtocol = szUrl.substr(0, 7); boost::to_upper(szProtocol); size_t pos; if(szProtocol.compare("HTTP://") != 0 ) break; pos = szUrl.find_first_of("/", 7); if(std::string::npos == pos) break; szHost = szUrl.substr(7, pos - 7); szParam = szUrl.substr(pos, std::string::npos); return true; } while (0); return false; } bool CHttp::PostRequest( const std::string &szUrl, HttpResponse &result, const std::string &data /*= std::string()*/ , int rangeStart/* =0 */) { try { std::string szHost; std::string szParam; if(!ParseUrl(szUrl, szHost, szParam)) { m_lasterr = ERR_BADURL; std::cerr << "Fail in parsing url " << std::endl; return false; } if(!p->connect(szHost)) { m_lasterr = ERR_NETWORK; return false; } boost::asio::streambuf request; if(data.empty()) { p->FillRequest(request, CHttpPrivate::GET, szHost, szParam, std::string(), rangeStart); boost::asio::write(p->m_socket, request); } else { p->FillRequest(request, CHttpPrivate::POST, szHost, szParam, std::string(), rangeStart); boost::asio::write(p->m_socket, request); boost::asio::write(p->m_socket, boost::asio::buffer(data)); } if(!p->RecvResponse(result)) return false; } catch (std::exception& e) { m_lasterr = ERR_UNKNOWN; std::cout << "Exception: " << e.what() << "\n"; return false; } return true; } bool CHttp::PostRequest( const std::string &szUrl, std::string &szResult, const std::string &data /*= std::string()*/ ) { HttpResponse result; if(!this->PostRequest(szUrl, result)) return false; szResult = result.body; return true; }
相关文章推荐
- java-WEB中的监听器Lisener
- RPC failed; result=22, HTTP code = 411
- GUI - Web前端开发框架
- Extjs4.0 最新最全视频教程
- MyEclipse Web Project转Eclipse Dynamic Web Project
- axis备忘
- HTTP Header 属性列表
- nginx中http核心模块的配置指令2
- nginx中http核心模块的配置指令3
- nginx中http核心模块的配置指令4
- nginx中http的fastcgi模块的配置指令1
- 如何在 Linux 中快速地通过 HTTP 提供文件访问服务
- 创业如何选择WEB开发语言
- Erlang实现的一个Web服务器代码实例
- 防止网页脚本病毒执行的方法-from web
- 深入HTTP head的使用详解
- Ruby程序中发送基于HTTP协议的请求的简单示例