Neat way of doing async HTTP request using WinApi
Recently, I needed to implement rather big part of the software based on HTTP requests with C++ and WinAPI.
As soon as the old-school blocking APIs are not the way to go in the 2014, I was choosing between COM-based WinHTTP and WinInet. I chose the latest because I read this (there is a lot more "yes" there on the WinInet side;)) and I software was not a service.
So here we go. C-style asynchronous API and OOP. Need to make a wrap, and good one - I will use it later almost everywhere!
But how could I do it the best way in the world (I am currently aware of, of course;))?
I decided to use the next schema:
1) Any class that needs to make an HTTP request, derives from "AsyncHttpRequest::Host" class
2) "AsyncHttpRequest::Host" class has the special static method making requests and special virtual method used as a callback
3) "AsyncHttpRequest::Host" also should take care of the request creating and destroying, i.e. memory management - to make the code for request/response processing as tiny as possible.
Here is the very "Host" class:
class Host
{
protected:
vector<shared_ptr<AsyncHttpRequest>> m_PendingRequests;
protected:
int HttpMakeRequest(const char* aszVerb, string aURL, string aReferrer = string(), DWORD adwContext = 0, HttpHeaders aHeaders = map<string, string>(), string aBody = string(), DWORD dwTimeOut = 5000);
public:
virtual void OnAsyncHttpRequestComplete(AsyncHttpRequest* apAsyncHttpRequest, DWORD adwResult);
};
As soon as the old-school blocking APIs are not the way to go in the 2014, I was choosing between COM-based WinHTTP and WinInet. I chose the latest because I read this (there is a lot more "yes" there on the WinInet side;)) and I software was not a service.
So here we go. C-style asynchronous API and OOP. Need to make a wrap, and good one - I will use it later almost everywhere!
But how could I do it the best way in the world (I am currently aware of, of course;))?
I decided to use the next schema:
1) Any class that needs to make an HTTP request, derives from "AsyncHttpRequest::Host" class
2) "AsyncHttpRequest::Host" class has the special static method making requests and special virtual method used as a callback
3) "AsyncHttpRequest::Host" also should take care of the request creating and destroying, i.e. memory management - to make the code for request/response processing as tiny as possible.
Here is the very "Host" class:
class Host
{
protected:
vector<shared_ptr<AsyncHttpRequest>> m_PendingRequests;
protected:
int HttpMakeRequest(const char* aszVerb, string aURL, string aReferrer = string(), DWORD adwContext = 0, HttpHeaders aHeaders = map<string, string>(), string aBody = string(), DWORD dwTimeOut = 5000);
public:
virtual void OnAsyncHttpRequestComplete(AsyncHttpRequest* apAsyncHttpRequest, DWORD adwResult);
};
And its successor making GET request to the aURL and printf-ing the response to stdout:
class AsyncAsyncHttpRequestHost : AsyncHttpRequest::Host
{
public:
AsyncAsyncHttpRequestHost(string aURL)
{
HttpMakeRequest("GET", aURL);
}
~AsyncAsyncHttpRequestHost()
{
}
virtual void OnAsyncHttpRequestComplete(AsyncHttpRequest* apAsyncHttpRequest, DWORD adwResult)
{
printf("Response:\n%s", apAsyncHttpRequest->GetResponse()->GetBody().c_str());
printf("Press any key to continue...");
}
};
The stuff about making request using WinInet is interesting as well (UTF8 <-> UTF16 string convertion is only top of it) but I decided it's not too complicated.
BTW, here is the sample on GitHub.
Problem solved!
Comments
Post a Comment