响应包分成三个部分(status+headers+nody)
#ifndef HTTPREQUEST_HPP
#define HTTPREQUEST_HPP
#include <algorithm>
#include <functional>
#include <stdexcept>
#include <system_error>
#include <map>
#include <string>
#include<memory>
#include <vector>
#include <cctype>
#include <cstddef>
#include <cstdint>
using namespace std;
#ifdef _WIN32
# pragma push_macro("WIN32_LEAN_AND_MEAN")
# pragma push_macro("NOMINMAX")
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# ifndef NOMINMAX
# define NOMINMAX
# endif
# include <winsock2.h>
# include <ws2tcpip.h>
# pragma pop_macro("WIN32_LEAN_AND_MEAN")
# pragma pop_macro("NOMINMAX")
# pragma comment(lib, "Ws2_32.lib")
#else
# include <sys/socket.h>
# include <netinet/in.h>
# include <netdb.h>
# include <unistd.h>
# include <errno.h>
#endif
namespace http
{
#ifdef _WIN32
class WinSock final
{
public:
WinSock(){
WSADATA wsaData;
int error = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (error != 0)throw std::system_error(error, std::system_category(), "WSAStartup failed");
started = true;
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) throw std::runtime_error("Invalid WinSock version");
}
~WinSock() {
if (started) WSACleanup();
}
WinSock(const WinSock&) = delete;
WinSock& operator=(const WinSock&) = delete;
WinSock(WinSock&& other) noexcept:started(other.started){
other.started = false;
}
WinSock& operator=(WinSock&& other) noexcept{
if (&other == this) return *this;
if (started) WSACleanup();
started = other.started;
other.started = false;
return *this;
}
private:
bool started = false;
};
#endif
inline int getLastError() noexcept
{
#ifdef _WIN32
return WSAGetLastError();
#else
return errno;
#endif
}
enum class InternetProtocol: uint8_t
{
V4,
V6
};
constexpr int getAddressFamily(InternetProtocol internetProtocol){
return (internetProtocol == InternetProtocol::V4) ? AF_INET :
(internetProtocol == InternetProtocol::V6) ? AF_INET6 :
throw std::runtime_error("Unsupported protocol");
}
class Socket final
{
public:
#ifdef _WIN32
using Type = SOCKET;
static constexpr Type Invalid = INVALID_SOCKET;
#else
using Type = int;
static constexpr Type Invalid = -1;
#endif
explicit Socket(InternetProtocol internetProtocol):endpoint(socket(getAddressFamily(internetProtocol), SOCK_STREAM, IPPROTO_TCP))
{
if (endpoint == Invalid)
throw std::system_error(getLastError(), std::system_category(), "Failed to create socket");
}
explicit Socket(Type s) noexcept:
endpoint(s)
{
}
~Socket()
{
if (endpoint != Invalid) close();
}
Socket(const Socket&) = delete;
Socket& operator=(const Socket&) = delete;
Socket(Socket&& other) noexcept:
endpoint(other.endpoint)
{
other.endpoint = Invalid;
}
Socket& operator=(Socket&& other) noexcept
{
if (&other == this) return *this;
if (endpoint != Invalid) close();
endpoint = other.endpoint;
other.endpoint = Invalid;
return *this;
}
inline operator Type() const noexcept {
return endpoint; }
private:
inline void close() noexcept
{
#ifdef _WIN32
closesocket(endpoint);
#else
::close(endpoint);
#endif
}
Type endpoint = Invalid;
};
inline std::string urlEncode(const std::string& str)
{
constexpr char hexChars[16] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
std::string result;
for (auto i = str.begin(