code : https://github.com/EomTaeWook/Cpp-Util/tree/master/Util/Web
윈도우 함수 Wrapping
NS.h
#pragma once
#ifndef HTTP_H
#define HTTP_H
#define NS_WEB_HTTP_BEGIN namespace Util { namespace Web { namespace Http {
#define NS_WEB_HTTP_END } } }
#define USING_WEB_HTTP using namespace Util::Web::Http;
#define NS_WEB_BEGIN namespace Util { namespace Web {
#define NS_WEB_END } }
#define USING_WEB_HTTP using namespace Util::Web::Http;
#define USING_WEB using namespace Util::Web;
#endif
WebEnum.h
#pragma once
#include "NS.h"
NS_WEB_BEGIN
enum class Method
{
Get,
Post,
Put,
Delete
};
NS_WEB_END
Url.h
#pragma once
#pragma once
#include "NS.h"
#include <string>
#include <algorithm>
NS_WEB_BEGIN
class Url
{
public:
Url();
Url(std::string url);
Url(std::wstring url);
virtual ~Url();
private:
std::wstring _path;
std::wstring _protocol;
std::wstring _host;
int _port;
public:
void Parse(std::string url);
void Parse(std::wstring url);
std::wstring GetPath();
std::wstring GetProtocol();
std::wstring GetHost();
int GetPort();
};
inline Url::Url()
{
}
inline Url::Url(std::string url)
{
Parse(std::wstring().assign(url.begin(), url.end()));
}
inline Url::Url(std::wstring url)
{
Parse(url);
}
inline Url::~Url()
{
}
inline void Url::Parse(std::string url)
{
Parse(std::wstring().assign(url.begin(), url.end()));
}
inline void Url::Parse(std::wstring url)
{
if (url.size() == 0) return;
auto beginIdx = url.find(L"://");
if (beginIdx != std::wstring::npos)
{
_protocol = url.substr(0, beginIdx).c_str();
std::transform(_protocol.begin(), _protocol.end(), _protocol.begin(), ::tolower);
beginIdx += 3;
}
else
{
_protocol = L"http";
beginIdx = 0;
}
auto endIdx = url.find(L"/", beginIdx);
if (endIdx != std::wstring::npos)
{
_host = url.substr(beginIdx, endIdx - beginIdx);
std::transform(_host.begin(), _host.end(), _host.begin(), ::tolower);
beginIdx = endIdx;
}
else
_host = url.substr(beginIdx, url.size() - beginIdx);
endIdx = _host.rfind(L":");
if (endIdx != std::wstring::npos)
{
_port = std::stoi(_host.substr(endIdx + 1, _host.size() - endIdx));
_host.erase(endIdx, _host.size() - endIdx);
}
else
_port = 80;
if (beginIdx != 0)
{
_path = url.substr(beginIdx, url.size() - beginIdx);
std::transform(_path.begin(), _path.end(), _path.begin(), ::tolower);
}
}
inline std::wstring Url::GetPath()
{
return _path;
}
inline std::wstring Url::GetProtocol()
{
return _protocol;
}
inline std::wstring Url::GetHost()
{
return _host;
}
inline int Url::GetPort()
{
return _port;
}
NS_WEB_END
HttpClient.h
#pragma once
#include <Windows.h>
#include <winhttp.h>
#include "WebEnum.h"
#include "Url.h"
#include <string>
#include <functional>
#pragma comment(lib ,"winhttp.lib")
NS_WEB_HTTP_BEGIN
class HttpClient
{
public:
HttpClient();
virtual ~HttpClient();
private:
HINTERNET _session;
HINTERNET _connect;
HINTERNET _request;
int _protocolType;
char _buffer[2048];
Url _url;
std::wstring _header;
std::function<void(int, std::string&)> _callback;
std::string _response;
int _responseCode;
public:
void Init(std::string url);
bool SendRequestAsync(std::string requestData = "", Method method = Method::Get, std::function<void(int, std::string&)> callback = nullptr);
std::string SendRequest(std::string requestData = "", Method method = Method::Get);
void HeaderAppend(std::string header);
private:
void Invoke(unsigned long code, void* info, unsigned long length);
void Close();
private:
static void __stdcall Invoke(HINTERNET handle, DWORD_PTR context, DWORD status, void* info, DWORD infoLength);
};
inline HttpClient::HttpClient()
{
_protocolType = 0;
}
inline HttpClient::~HttpClient()
{
Close();
}
NS_WEB_HTTP_END
HttpClient.cpp
#include "HttpClient.h"
NS_WEB_HTTP_BEGIN
void HttpClient::Init(std::string url)
{
try
{
_url.Parse(url);
if (_url.GetProtocol() == L"https")
_protocolType = WINHTTP_FLAG_SECURE;
}
catch (...)
{
throw std::exception("InitException");
}
}
std::string HttpClient::SendRequest(std::string requestData, Method method)
{
try
{
_session = WinHttpOpen(L"0",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS,
0);
if (_session)
{
_connect = WinHttpConnect(_session,
_url.GetHost().c_str(),
_url.GetPort(),
0);
}
std::wstring type = L"GET";
std::wstring path = _url.GetPath().c_str();
switch (method)
{
case Method::Get:
path.append(requestData.begin(), requestData.end());
requestData.clear();
break;
case Method::Post:
type = L"POST";
break;
case Method::Put:
type = L"PUT";
break;
case Method::Delete:
type = L"Delete";
break;
}
_request = WinHttpOpenRequest(_connect,
type.c_str(),
path.c_str(),
NULL,
WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
_protocolType);
if (_header.size() == 0)
_header = L"content-type:application/x-www-form-urlencoded";
WinHttpAddRequestHeaders(_request, _header.c_str(), (DWORD)_header.size(), WINHTTP_ADDREQ_FLAG_ADD);
if (WinHttpSendRequest(_request,
WINHTTP_NO_ADDITIONAL_HEADERS,
0,
(LPVOID)requestData.c_str(),
(DWORD)requestData.size(),
(DWORD)requestData.size(),
(DWORD_PTR)this))
{
if (WinHttpReceiveResponse(_request, NULL))
{
unsigned long readSize = 0;
do
{
WinHttpQueryDataAvailable(_request, &readSize);
if (readSize <= 0) break;
WinHttpReadData(_request, _buffer, sizeof(_buffer), &readSize);
_response.append(_buffer, readSize);
readSize = 0;
} while (readSize > 0);
}
}
else
{
throw std::exception();
}
}
catch (...)
{
Close();
throw std::exception("RequestException");
}
Close();
return _response;
}
bool HttpClient::SendRequestAsync(std::string requestData, Method method, std::function<void(int, std::string&)> callback)
{
try
{
_session = WinHttpOpen(L"0",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS,
WINHTTP_FLAG_ASYNC);
if (_session)
{
_connect = WinHttpConnect(_session,
_url.GetHost().c_str(),
_url.GetPort(),
0);
}
std::wstring type = L"GET";
std::wstring path = _url.GetPath().c_str();
_callback = callback;
switch (method)
{
case Method::Get:
path.append(requestData.begin(), requestData.end());
requestData.clear();
break;
case Method::Post:
type = L"POST";
break;
case Method::Put:
type = L"PUT";
break;
case Method::Delete:
type = L"Delete";
break;
}
_request = WinHttpOpenRequest(_connect,
type.c_str(),
path.c_str(),
NULL,
WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
_protocolType);
if (_header.size() == 0)
_header = L"content-type:application/x-www-form-urlencoded";
WinHttpAddRequestHeaders(_request, _header.c_str(), (DWORD)_header.size(), WINHTTP_ADDREQ_FLAG_ADD);
WinHttpSetStatusCallback(_request,
HttpClient::Invoke,
WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS,
0);
auto result = WinHttpSendRequest(_request,
WINHTTP_NO_ADDITIONAL_HEADERS,
0,
(LPVOID)requestData.c_str(),
(DWORD)requestData.size(),
(DWORD)requestData.size(),
(DWORD_PTR)this);
return result;
}
catch (...)
{
throw std::exception("RequestException");
}
}
void HttpClient::HeaderAppend(std::string header)
{
if (header.size() == 0) return;
auto data = std::wstring().assign(header.begin(), header.end());
_header.append(data + L"\n");
}
void HttpClient::Close()
{
if (_request) WinHttpCloseHandle(_request);
if (_connect) WinHttpCloseHandle(_connect);
if (_session) WinHttpCloseHandle(_session);
}
void HttpClient::Invoke(unsigned long code, void* info, unsigned long length)
{
switch (code)
{
case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE:
WinHttpReceiveResponse(_request, NULL);
break;
case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE:
{
unsigned long status = 0;
unsigned long statusSize = sizeof(unsigned long);
std::string response;
WinHttpQueryHeaders(_request,
WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
WINHTTP_HEADER_NAME_BY_INDEX,
&status,
&statusSize,
WINHTTP_NO_HEADER_INDEX);
_responseCode = status;
WinHttpQueryDataAvailable(_request, NULL);
break;
}
case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE:
{
WinHttpReadData(_request, &_buffer, sizeof(_buffer), NULL);
break;
}
case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
{
if (length != 0)
{
_response.append(_buffer, length);
WinHttpQueryDataAvailable(_request, NULL);
}
else
{
if (_callback != nullptr)
{
_callback(_responseCode, _response);
this->Close();
}
}
break;
}
case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
if (_callback != nullptr)
{
_callback(code, _response.append("WINHTTP_CALLBACK_STATUS_REQUEST_ERROR"));
this->Close();
}
break;
}
}
void __stdcall HttpClient::Invoke(HINTERNET handle, DWORD_PTR context, DWORD status, void* info, DWORD infoLength)
{
auto client = reinterpret_cast<HttpClient*>(context);
if (client != NULL)
client->Invoke(status, info, infoLength);
}
NS_WEB_HTTP_END
'개발관련 > C&C++' 카테고리의 다른 글
반복자(iterator)가 포함된 Queue (0) | 2018.09.08 |
---|---|
IOCP Socket Client 구현 (0) | 2018.05.31 |
MSMQ(MS MessageQueue) (0) | 2018.05.15 |
Functional 이용한 델리게이트 (0) | 2018.04.26 |
IOCP Socket Server 구현 (0) | 2018.04.16 |