mirror of https://github.com/axmolengine/axmol.git
added winrt networking files
This commit is contained in:
parent
2aec149316
commit
60f672599b
|
@ -0,0 +1,366 @@
|
|||
/****************************************************************************
|
||||
Copyright (c) 2012 greathqy
|
||||
Copyright (c) 2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2014 Chukong Technologies Inc.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "HttpClient.h"
|
||||
|
||||
#include <thread>
|
||||
#include <queue>
|
||||
#include <condition_variable>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "base/CCVector.h"
|
||||
#include "base/CCDirector.h"
|
||||
#include "base/CCScheduler.h"
|
||||
|
||||
#include "platform/CCFileUtils.h"
|
||||
#include "HttpConnection-winrt.h"
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
namespace network {
|
||||
|
||||
static std::mutex s_requestQueueMutex;
|
||||
static std::mutex s_responseQueueMutex;
|
||||
|
||||
static std::condition_variable_any s_SleepCondition;
|
||||
|
||||
|
||||
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
|
||||
typedef int int32_t;
|
||||
#endif
|
||||
|
||||
static Vector<HttpRequest*>* s_requestQueue = nullptr;
|
||||
static Vector<HttpResponse*>* s_responseQueue = nullptr;
|
||||
|
||||
static HttpClient *s_pHttpClient = nullptr; // pointer to singleton
|
||||
|
||||
static std::string s_errorBuffer ="";
|
||||
|
||||
static std::string s_cookieFilename = "";
|
||||
|
||||
static std::string s_sslCaFilename = "";
|
||||
|
||||
// function used to collect response/header data
|
||||
static void writeData(std::vector<char> *pFromBuffer, std::vector<char> *pToBuffer)
|
||||
{
|
||||
if(nullptr == pFromBuffer || nullptr == pToBuffer)
|
||||
return;
|
||||
|
||||
pToBuffer->insert(pToBuffer->end(), pFromBuffer->begin(), pFromBuffer->end());
|
||||
}
|
||||
|
||||
static void processHttpResponse(HttpResponse* response, std::string& errorStr);
|
||||
|
||||
static HttpRequest *s_requestSentinel = new HttpRequest;
|
||||
|
||||
// Worker thread
|
||||
void HttpClient::networkThread()
|
||||
{
|
||||
auto scheduler = Director::getInstance()->getScheduler();
|
||||
|
||||
while (true)
|
||||
{
|
||||
HttpRequest *request;
|
||||
|
||||
// step 1: send http request if the requestQueue isn't empty
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_requestQueueMutex);
|
||||
while (s_requestQueue->empty()) {
|
||||
s_SleepCondition.wait(s_requestQueueMutex);
|
||||
}
|
||||
request = s_requestQueue->at(0);
|
||||
s_requestQueue->erase(0);
|
||||
}
|
||||
|
||||
if (request == s_requestSentinel) {
|
||||
break;
|
||||
}
|
||||
|
||||
// step 2: libcurl sync access
|
||||
|
||||
// Create a HttpResponse object, the default setting is http access failed
|
||||
HttpResponse *response = new (std::nothrow) HttpResponse(request);
|
||||
|
||||
processHttpResponse(response, s_errorBuffer);
|
||||
|
||||
|
||||
// add response packet into queue
|
||||
s_responseQueueMutex.lock();
|
||||
s_responseQueue->pushBack(response);
|
||||
s_responseQueueMutex.unlock();
|
||||
|
||||
if (nullptr != s_pHttpClient) {
|
||||
scheduler->performFunctionInCocosThread(CC_CALLBACK_0(HttpClient::dispatchResponseCallbacks, this));
|
||||
}
|
||||
}
|
||||
|
||||
// cleanup: if worker thread received quit signal, clean up un-completed request queue
|
||||
s_requestQueueMutex.lock();
|
||||
s_requestQueue->clear();
|
||||
s_requestQueueMutex.unlock();
|
||||
|
||||
|
||||
if (s_requestQueue != nullptr) {
|
||||
delete s_requestQueue;
|
||||
s_requestQueue = nullptr;
|
||||
delete s_responseQueue;
|
||||
s_responseQueue = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Worker thread
|
||||
void HttpClient::networkThreadAlone(HttpRequest* request, HttpResponse* response)
|
||||
{
|
||||
std::string errorStr;
|
||||
processHttpResponse(response, errorStr);
|
||||
|
||||
auto scheduler = Director::getInstance()->getScheduler();
|
||||
scheduler->performFunctionInCocosThread([response, request]{
|
||||
const ccHttpRequestCallback& callback = request->getCallback();
|
||||
Ref* pTarget = request->getTarget();
|
||||
SEL_HttpResponse pSelector = request->getSelector();
|
||||
|
||||
if (callback != nullptr)
|
||||
{
|
||||
callback(s_pHttpClient, response);
|
||||
}
|
||||
else if (pTarget && pSelector)
|
||||
{
|
||||
(pTarget->*pSelector)(s_pHttpClient, response);
|
||||
}
|
||||
response->release();
|
||||
// do not release in other thread
|
||||
request->release();
|
||||
});
|
||||
}
|
||||
|
||||
// Process Response
|
||||
static void processHttpResponse(HttpResponse* response, std::string& errorStr)
|
||||
{
|
||||
auto request = response->getHttpRequest();
|
||||
long responseCode = -1;
|
||||
int retValue = 0;
|
||||
HttpConnection xhr;
|
||||
bool ok = false;
|
||||
bool manualAuthReqd = false;
|
||||
|
||||
// Process the request -> get response packet
|
||||
switch (request->getRequestType())
|
||||
{
|
||||
case HttpRequest::Type::GET: // HTTP GET
|
||||
ok = (xhr.init(request) && xhr.open("GET", manualAuthReqd, s_cookieFilename) && xhr.send());
|
||||
break;
|
||||
|
||||
case HttpRequest::Type::POST: // HTTP POST
|
||||
ok = (xhr.init(request) && xhr.open("POST", manualAuthReqd, s_cookieFilename) && xhr.send());
|
||||
break;
|
||||
|
||||
case HttpRequest::Type::PUT: // HTTP PUT
|
||||
ok = (xhr.init(request) && xhr.open("PUT", manualAuthReqd, s_cookieFilename) && xhr.send());
|
||||
break;
|
||||
|
||||
case HttpRequest::Type::DELETE: // HTTP DELETE
|
||||
ok = (xhr.init(request) && xhr.open("DELETE", manualAuthReqd, s_cookieFilename) && xhr.send());
|
||||
break;
|
||||
|
||||
default:
|
||||
CCASSERT(true, "CCHttpClient: unknown request type, only GET and POST are supported");
|
||||
break;
|
||||
}
|
||||
|
||||
writeData(xhr.getResponseHeader(), response->getResponseHeader());
|
||||
writeData(xhr.getResponseData(), response->getResponseData());
|
||||
retValue = ok ? 0 : 1;
|
||||
errorStr = xhr.getErrorMessage();
|
||||
responseCode = xhr.getStatusCode();
|
||||
|
||||
// write data to HttpResponse
|
||||
response->setResponseCode(responseCode);
|
||||
|
||||
if (retValue != 0)
|
||||
{
|
||||
response->setSucceed(false);
|
||||
response->setErrorBuffer(errorStr.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
response->setSucceed(true);
|
||||
}
|
||||
}
|
||||
|
||||
// HttpClient implementation
|
||||
HttpClient* HttpClient::getInstance()
|
||||
{
|
||||
if (s_pHttpClient == nullptr) {
|
||||
s_pHttpClient = new (std::nothrow) HttpClient();
|
||||
}
|
||||
|
||||
return s_pHttpClient;
|
||||
}
|
||||
|
||||
void HttpClient::destroyInstance()
|
||||
{
|
||||
CC_SAFE_DELETE(s_pHttpClient);
|
||||
}
|
||||
|
||||
void HttpClient::enableCookies(const char* cookieFile) {
|
||||
if (cookieFile) {
|
||||
s_cookieFilename = std::string(cookieFile);
|
||||
}
|
||||
else {
|
||||
s_cookieFilename = (FileUtils::getInstance()->getWritablePath() + "cookieFile.txt");
|
||||
}
|
||||
}
|
||||
|
||||
void HttpClient::setSSLVerification(const std::string& caFile)
|
||||
{
|
||||
s_sslCaFilename = caFile;
|
||||
}
|
||||
|
||||
HttpClient::HttpClient()
|
||||
: _timeoutForConnect(30)
|
||||
, _timeoutForRead(60)
|
||||
{
|
||||
}
|
||||
|
||||
HttpClient::~HttpClient()
|
||||
{
|
||||
if (s_requestQueue != nullptr) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_requestQueueMutex);
|
||||
s_requestQueue->pushBack(s_requestSentinel);
|
||||
}
|
||||
s_SleepCondition.notify_one();
|
||||
}
|
||||
|
||||
s_pHttpClient = nullptr;
|
||||
}
|
||||
|
||||
//Lazy create semaphore & mutex & thread
|
||||
bool HttpClient::lazyInitThreadSemphore()
|
||||
{
|
||||
if (s_requestQueue != nullptr) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
|
||||
s_requestQueue = new (std::nothrow) Vector<HttpRequest*>();
|
||||
s_responseQueue = new (std::nothrow) Vector<HttpResponse*>();
|
||||
|
||||
auto t = std::thread(CC_CALLBACK_0(HttpClient::networkThread, this));
|
||||
t.detach();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//Add a get task to queue
|
||||
void HttpClient::send(HttpRequest* request)
|
||||
{
|
||||
if (false == lazyInitThreadSemphore())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!request)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
request->retain();
|
||||
|
||||
if (nullptr != s_requestQueue) {
|
||||
s_requestQueueMutex.lock();
|
||||
s_requestQueue->pushBack(request);
|
||||
s_requestQueueMutex.unlock();
|
||||
|
||||
// Notify thread start to work
|
||||
s_SleepCondition.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
void HttpClient::sendImmediate(HttpRequest* request)
|
||||
{
|
||||
if (!request)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
request->retain();
|
||||
// Create a HttpResponse object, the default setting is http access failed
|
||||
HttpResponse *response = new (std::nothrow) HttpResponse(request);
|
||||
|
||||
auto t = std::thread(&HttpClient::networkThreadAlone, this, request, response);
|
||||
t.detach();
|
||||
}
|
||||
|
||||
// Poll and notify main thread if responses exists in queue
|
||||
void HttpClient::dispatchResponseCallbacks()
|
||||
{
|
||||
// log("CCHttpClient::dispatchResponseCallbacks is running");
|
||||
//occurs when cocos thread fires but the network thread has already quited
|
||||
if (nullptr == s_responseQueue) {
|
||||
return;
|
||||
}
|
||||
HttpResponse* response = nullptr;
|
||||
|
||||
s_responseQueueMutex.lock();
|
||||
|
||||
if (!s_responseQueue->empty())
|
||||
{
|
||||
response = s_responseQueue->at(0);
|
||||
s_responseQueue->erase(0);
|
||||
}
|
||||
|
||||
s_responseQueueMutex.unlock();
|
||||
|
||||
if (response)
|
||||
{
|
||||
HttpRequest *request = response->getHttpRequest();
|
||||
const ccHttpRequestCallback& callback = request->getCallback();
|
||||
Ref* pTarget = request->getTarget();
|
||||
SEL_HttpResponse pSelector = request->getSelector();
|
||||
|
||||
if (callback != nullptr)
|
||||
{
|
||||
callback(this, response);
|
||||
}
|
||||
else if (pTarget && pSelector)
|
||||
{
|
||||
(pTarget->*pSelector)(this, response);
|
||||
}
|
||||
|
||||
response->release();
|
||||
// do not release in other thread
|
||||
request->release();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
NS_CC_END
|
|
@ -0,0 +1,741 @@
|
|||
/****************************************************************************
|
||||
Copyright (c) 2012 greathqy
|
||||
Copyright (c) 2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2014 Chukong Technologies Inc.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "network/HttpCookie.h"
|
||||
#include "HttpConnection-winrt.h"
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
namespace network {
|
||||
|
||||
// Format and add default headers (Platform specific approach)
|
||||
static void formatHeaders(std::vector<std::string>& headers)
|
||||
{
|
||||
#if defined(_XBOX_ONE)
|
||||
for(auto iter = headers.begin(); iter != headers.end(); ++iter)
|
||||
{
|
||||
(*iter) += "\r\n";
|
||||
}
|
||||
|
||||
// append default headers
|
||||
headers.emplace_back("User-Agent: XB1_IXHR2_HTTP\r\n");
|
||||
headers.emplace_back("x-xbl-device-type: XboxOne\r\n");
|
||||
headers.emplace_back("x-xbl-client-type: Console\r\n");
|
||||
headers.emplace_back("x-xbl-client-version: 1.0\r\n");
|
||||
headers.emplace_back("x-xbl-contract-version: 1\r\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Get user authentication token (Platform specific approach)
|
||||
static bool getAuthenticationToken(std::string verb, std::string url, std::string headersXST, std::string bodyXST, std::string& token, std::string& signature)
|
||||
{
|
||||
#if defined(_XBOX_ONE)
|
||||
using namespace Windows::Xbox::System;
|
||||
|
||||
token = "";
|
||||
signature = "";
|
||||
User^ loggedInUser = nullptr;
|
||||
int ind = 0;
|
||||
|
||||
while(ind < User::Users->Size)
|
||||
{
|
||||
loggedInUser = User::Users->GetAt(ind++);
|
||||
if(loggedInUser->IsSignedIn)
|
||||
break;
|
||||
|
||||
loggedInUser = nullptr;
|
||||
}
|
||||
|
||||
if(nullptr == loggedInUser)
|
||||
return false;
|
||||
|
||||
Platform::Array<unsigned char>^ body;
|
||||
|
||||
if(!bodyXST.empty()) {
|
||||
body = ref new Platform::Array<unsigned char>((unsigned char*)bodyXST.c_str(), bodyXST.size());
|
||||
}
|
||||
else {
|
||||
body = ref new Platform::Array<unsigned char>(1);
|
||||
body[0] = 0;
|
||||
}
|
||||
|
||||
// this method will crash if TitleId & PrimaryServiceConfigId not specified in Package.appxmanifest.
|
||||
auto asynOp = loggedInUser->GetTokenAndSignatureAsync(
|
||||
ref new Platform::String(std::wstring(verb.begin(), verb.end()).c_str()),
|
||||
ref new Platform::String(std::wstring(url.begin(), url.end()).c_str()),
|
||||
ref new Platform::String(std::wstring(headersXST.begin(), headersXST.end()).c_str()), body);
|
||||
|
||||
bool bRet = false;
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
asynOp->Completed = ref new Windows::Foundation::AsyncOperationCompletedHandler<GetTokenAndSignatureResult^>(
|
||||
[&token, &signature, &bRet, &hr](Windows::Foundation::IAsyncOperation<GetTokenAndSignatureResult^>^ operation, Windows::Foundation::AsyncStatus status)
|
||||
{
|
||||
if(status == Windows::Foundation::AsyncStatus::Completed) {
|
||||
try
|
||||
{
|
||||
auto result = operation->GetResults();
|
||||
|
||||
std::wstring tok = result->Token->Data();
|
||||
std::wstring sig = result->Signature->Data();
|
||||
token = std::string(tok.begin(), tok.end());
|
||||
signature = std::string(sig.begin(), sig.end());
|
||||
|
||||
bRet = true;
|
||||
}
|
||||
catch(Platform::Exception^ e)
|
||||
{
|
||||
bRet = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
hr = operation->ErrorCode.Value;
|
||||
|
||||
if(hr == 0x87dd0021) //AM_E_NO_TOKEN_REQUIRED
|
||||
bRet = true;
|
||||
}
|
||||
});
|
||||
|
||||
while(asynOp->Status == Windows::Foundation::AsyncStatus::Started)
|
||||
{
|
||||
::Sleep(1);
|
||||
}
|
||||
|
||||
return bRet;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// CXMLHTTPRequest2Callback
|
||||
CXHR2Callback::CXHR2Callback() :
|
||||
_statusCode(0),
|
||||
_hWfC(nullptr),
|
||||
_errorMsg("")
|
||||
{
|
||||
}
|
||||
|
||||
CXHR2Callback::~CXHR2Callback()
|
||||
{
|
||||
if (nullptr != _hWfC)
|
||||
{
|
||||
CloseHandle(_hWfC);
|
||||
_hWfC = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT CXHR2Callback::RuntimeClassInitialize()
|
||||
{
|
||||
_hWfC = CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
HRESULT CXHR2Callback::OnRedirect(IXMLHTTPRequest2 *pXHR, const WCHAR *pwszRedirectUrl)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(pXHR);
|
||||
UNREFERENCED_PARAMETER(pwszRedirectUrl);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CXHR2Callback::OnHeadersAvailable(IXMLHTTPRequest2 *pXHR, DWORD dwStatus, const WCHAR *pwszStatus)
|
||||
{
|
||||
_statusCode = dwStatus;
|
||||
|
||||
if(nullptr == pXHR) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
WCHAR *headers = nullptr;
|
||||
HRESULT hr = pXHR->GetAllResponseHeaders(&headers);
|
||||
|
||||
if(SUCCEEDED(hr)) {
|
||||
std::wstring hdr = headers;
|
||||
_headers.insert(_headers.end(), hdr.begin(), hdr.end());
|
||||
}
|
||||
|
||||
if(headers != nullptr) {
|
||||
CoTaskMemFree(headers);
|
||||
headers = nullptr;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT CXHR2Callback::OnDataAvailable(IXMLHTTPRequest2 *pXHR, ISequentialStream *pResponseStream)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(pXHR);
|
||||
|
||||
return ReadStreamData(pResponseStream);
|
||||
}
|
||||
|
||||
HRESULT CXHR2Callback::OnResponseReceived(IXMLHTTPRequest2 *pXHR, ISequentialStream *pResponseStream)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(pXHR);
|
||||
|
||||
HRESULT hr = ReadStreamData(pResponseStream);
|
||||
|
||||
CompleteRequest(hr);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT CXHR2Callback::OnError(IXMLHTTPRequest2 *pXHR, HRESULT hrError)
|
||||
{
|
||||
CompleteRequest(hrError);
|
||||
|
||||
return hrError;
|
||||
}
|
||||
|
||||
HRESULT CXHR2Callback::WaitForComplete(PDWORD pdwStatus)
|
||||
{
|
||||
HRESULT hr = E_FAIL;
|
||||
|
||||
if (NULL != _hWfC)
|
||||
{
|
||||
hr = S_OK;
|
||||
DWORD error;
|
||||
|
||||
error = WaitForSingleObjectEx(_hWfC, INFINITE, FALSE);
|
||||
|
||||
if (error == WAIT_FAILED) {
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
if (error != WAIT_OBJECT_0) {
|
||||
hr = E_ABORT;
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
*pdwStatus = _statusCode;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT CXHR2Callback::ReadStreamData(ISequentialStream* pResponseStream)
|
||||
{
|
||||
if(pResponseStream == NULL) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
CCHAR buff[READ_BUFFER_MAX];
|
||||
DWORD totalBytes = 0;
|
||||
DWORD bytesRead = 0;
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
do
|
||||
{
|
||||
hr = pResponseStream->Read(buff, READ_BUFFER_MAX, &bytesRead);
|
||||
|
||||
if(FAILED(hr)) {
|
||||
break;
|
||||
}
|
||||
|
||||
_data.insert(_data.end(), &buff[0], buff + bytesRead);
|
||||
totalBytes += bytesRead;
|
||||
}
|
||||
while(hr == S_OK);
|
||||
|
||||
if(SUCCEEDED(hr)) {
|
||||
hr = S_OK;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
void CXHR2Callback::CompleteRequest(HRESULT hrError)
|
||||
{
|
||||
if (NULL != _hWfC) {
|
||||
SetEvent(_hWfC);
|
||||
}
|
||||
|
||||
switch (hrError)
|
||||
{
|
||||
case S_OK:
|
||||
case S_FALSE:
|
||||
_statusCode = 200;
|
||||
break;
|
||||
|
||||
case INET_E_AUTHENTICATION_REQUIRED:
|
||||
_statusCode = 401;
|
||||
_errorMsg = ERR_MSG_401;
|
||||
break;
|
||||
|
||||
case INET_E_DOWNLOAD_FAILURE:
|
||||
_statusCode = 500;
|
||||
_errorMsg = ERR_MSG_DL_FLD;
|
||||
break;
|
||||
|
||||
case INET_E_FORBIDFRAMING:
|
||||
_statusCode = 403;
|
||||
_errorMsg = ERR_MSG_403;
|
||||
break;
|
||||
|
||||
case INET_E_RESOURCE_NOT_FOUND:
|
||||
_statusCode = 404;
|
||||
_errorMsg = ERR_MSG_404;
|
||||
break;
|
||||
|
||||
case RPC_S_PROXY_ACCESS_DENIED:
|
||||
_statusCode = 407;
|
||||
_errorMsg = ERR_MSG_407;
|
||||
break;
|
||||
|
||||
case ERROR_RESOURCE_CALL_TIMED_OUT:
|
||||
_statusCode = 408;
|
||||
_errorMsg = ERR_MSG_408;
|
||||
break;
|
||||
|
||||
case INET_E_INVALID_REQUEST:
|
||||
_statusCode = 400;
|
||||
_errorMsg = ERR_MSG_400;
|
||||
break;
|
||||
|
||||
case E_ABORT:
|
||||
_statusCode = 412;
|
||||
_errorMsg = ERR_MSG_412;
|
||||
break;
|
||||
|
||||
default:
|
||||
_statusCode = 500;
|
||||
_errorMsg = ERR_MSG_500;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//CXHR2DataStream
|
||||
CXHR2DataStream::CXHR2DataStream() :
|
||||
_pData(nullptr),
|
||||
_dataSize(0),
|
||||
_seekIndex(0),
|
||||
_refCnt(1)
|
||||
{
|
||||
}
|
||||
|
||||
CXHR2DataStream::~CXHR2DataStream()
|
||||
{
|
||||
if(nullptr != _pData)
|
||||
delete[] _pData;
|
||||
}
|
||||
|
||||
ULONG CXHR2DataStream::Length()
|
||||
{
|
||||
return _dataSize;
|
||||
}
|
||||
|
||||
HRESULT CXHR2DataStream::Init(const void *psBuffer, ULONG cbBufferSize)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if(psBuffer == nullptr || cbBufferSize > REQUEST_BUFFER_MAX) {
|
||||
hr = E_INVALIDARG;
|
||||
}
|
||||
|
||||
if(SUCCEEDED(hr)) {
|
||||
_dataSize = cbBufferSize;
|
||||
_seekIndex = 0;
|
||||
_pData = new (std::nothrow) BYTE[_dataSize];
|
||||
|
||||
if(_pData == nullptr)
|
||||
hr = E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
if(SUCCEEDED(hr)) {
|
||||
memcpy_s(_pData, _dataSize, psBuffer, cbBufferSize);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT CXHR2DataStream::Read(void *pv, ULONG cb, ULONG *pcbRead)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if(pv == nullptr) {
|
||||
hr = E_INVALIDARG;
|
||||
}
|
||||
|
||||
if(SUCCEEDED(hr)) {
|
||||
BYTE* pOutput = (BYTE*)pv;
|
||||
BYTE* _pInput = _pData;
|
||||
|
||||
for(*pcbRead = 0; *pcbRead < cb; (*pcbRead)++)
|
||||
{
|
||||
if(_seekIndex == _dataSize) {
|
||||
hr = S_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
pOutput[*pcbRead] = _pInput[*pcbRead];
|
||||
_seekIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT CXHR2DataStream::Write(const void *pv, ULONG cb, ULONG *pcbWritten)
|
||||
{
|
||||
HRESULT hr = E_NOTIMPL;
|
||||
|
||||
UNREFERENCED_PARAMETER(pv);
|
||||
UNREFERENCED_PARAMETER(cb);
|
||||
UNREFERENCED_PARAMETER(pcbWritten);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
ULONG CXHR2DataStream::AddRef()
|
||||
{
|
||||
return ::InterlockedIncrement(&_refCnt);
|
||||
}
|
||||
|
||||
ULONG CXHR2DataStream::Release()
|
||||
{
|
||||
ULONG refCnt = ::InterlockedDecrement(&_refCnt);
|
||||
|
||||
if(0 == refCnt) {
|
||||
delete this;
|
||||
}
|
||||
|
||||
return refCnt;
|
||||
}
|
||||
|
||||
HRESULT CXHR2DataStream::QueryInterface(REFIID riid, void **ppvObject)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if(ppvObject == nullptr) {
|
||||
hr = E_INVALIDARG;
|
||||
}
|
||||
|
||||
void *pObject = nullptr;
|
||||
|
||||
if(SUCCEEDED(hr)) {
|
||||
|
||||
if(riid == IID_IUnknown) {
|
||||
pObject = static_cast<IUnknown*>((IDispatch*)this);
|
||||
}
|
||||
else if(riid == IID_IDispatch) {
|
||||
pObject = static_cast<IDispatch*>(this);
|
||||
}
|
||||
else if(riid == IID_ISequentialStream) {
|
||||
pObject = static_cast<ISequentialStream*>(this);
|
||||
}
|
||||
else {
|
||||
hr = E_NOINTERFACE;
|
||||
}
|
||||
}
|
||||
|
||||
if(SUCCEEDED(hr)) {
|
||||
AddRef();
|
||||
*ppvObject = pObject;
|
||||
pObject = nullptr;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT CXHR2DataStream::GetTypeInfoCount(unsigned int FAR* pctinfo)
|
||||
{
|
||||
HRESULT hr = E_NOTIMPL;
|
||||
|
||||
if(pctinfo)
|
||||
*pctinfo = 0;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT CXHR2DataStream::GetTypeInfo(unsigned int iTInfo, LCID lcid, ITypeInfo FAR* FAR* ppTInfo)
|
||||
{
|
||||
HRESULT hr = E_NOTIMPL;
|
||||
|
||||
if(ppTInfo)
|
||||
*ppTInfo = 0;
|
||||
|
||||
UNREFERENCED_PARAMETER(iTInfo);
|
||||
UNREFERENCED_PARAMETER(lcid);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT CXHR2DataStream::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgDispId)
|
||||
{
|
||||
HRESULT hr = DISP_E_UNKNOWNNAME;
|
||||
|
||||
UNREFERENCED_PARAMETER(riid);
|
||||
UNREFERENCED_PARAMETER(rgszNames);
|
||||
UNREFERENCED_PARAMETER(cNames);
|
||||
UNREFERENCED_PARAMETER(lcid);
|
||||
UNREFERENCED_PARAMETER(rgDispId);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT CXHR2DataStream::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR* pDispParams, VARIANT FAR* pVarResult, EXCEPINFO FAR* pExcepInfo, unsigned int FAR* puArgErr)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
UNREFERENCED_PARAMETER(dispIdMember);
|
||||
UNREFERENCED_PARAMETER(riid);
|
||||
UNREFERENCED_PARAMETER(lcid);
|
||||
UNREFERENCED_PARAMETER(wFlags);
|
||||
UNREFERENCED_PARAMETER(pDispParams);
|
||||
UNREFERENCED_PARAMETER(pVarResult);
|
||||
UNREFERENCED_PARAMETER(pExcepInfo);
|
||||
UNREFERENCED_PARAMETER(puArgErr);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
// HttpConnection
|
||||
HttpConnection::HttpConnection() :
|
||||
_isInitialized(false),
|
||||
_spXhr(nullptr),
|
||||
_spXhrCallback(nullptr),
|
||||
_spXhrRequestData(nullptr),
|
||||
_pRequest(nullptr),
|
||||
_timeOutInMs(0)
|
||||
{
|
||||
}
|
||||
|
||||
HttpConnection::~HttpConnection()
|
||||
{
|
||||
}
|
||||
|
||||
bool HttpConnection::init(HttpRequest *pRequest, DWORD timeOutInMs)
|
||||
{
|
||||
if (_isInitialized || nullptr == pRequest) {
|
||||
return _isInitialized;
|
||||
}
|
||||
|
||||
HRESULT hr = CoInitializeEx(NULL, NULL);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = CoCreateInstance(CLSID_FreeThreadedXMLHTTP60, NULL, CLSCTX_SERVER, IID_PPV_ARGS(&_spXhr));
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = MakeAndInitialize<CXHR2Callback>(&_spXhrCallback);
|
||||
}
|
||||
|
||||
if(SUCCEEDED(hr)) {
|
||||
_pRequest = pRequest;
|
||||
_timeOutInMs = timeOutInMs;
|
||||
|
||||
LONG size = _pRequest->getRequestDataSize();
|
||||
|
||||
if(size > 0) {
|
||||
_spXhrRequestData = Make<CXHR2DataStream>();
|
||||
hr = _spXhrRequestData->Init(_pRequest->getRequestData(), size);
|
||||
}
|
||||
}
|
||||
|
||||
return _isInitialized = SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
bool HttpConnection::open(std::string verb)
|
||||
{
|
||||
return open(verb, false, "");
|
||||
}
|
||||
|
||||
bool HttpConnection::open(std::string verb, bool userAuthentication)
|
||||
{
|
||||
return open(verb, userAuthentication, "");
|
||||
}
|
||||
|
||||
bool HttpConnection::open(std::string verb, std::string cookieFile)
|
||||
{
|
||||
return open(verb, false, cookieFile);
|
||||
}
|
||||
|
||||
bool HttpConnection::open(std::string verb, bool userAuthentication, std::string cookieFile)
|
||||
{
|
||||
if (!_isInitialized) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::wstring method(verb.begin(), verb.end());
|
||||
std::string url(_pRequest->getUrl());
|
||||
std::wstring wUrl(url.begin(), url.end());
|
||||
HRESULT hr = _spXhr->Open(method.c_str(), wUrl.c_str(), _spXhrCallback.Get(), NULL, NULL, NULL, NULL);
|
||||
|
||||
if(SUCCEEDED(hr) && _timeOutInMs != 0) {
|
||||
hr = _spXhr->SetProperty(XHR_PROP_TIMEOUT, _timeOutInMs);
|
||||
}
|
||||
|
||||
#if 0
|
||||
if(SUCCEEDED(hr)) {
|
||||
hr = _spXhr->SetProperty(XHR_PROP_ONDATA_THRESHOLD, READ_BUFFER_MAX);
|
||||
}
|
||||
#endif
|
||||
|
||||
auto headers = _pRequest->getHeaders();
|
||||
formatHeaders(headers);
|
||||
|
||||
for(auto header : headers)
|
||||
{
|
||||
std::string key = header.substr(0, header.find_first_of(':'));
|
||||
std::string value = header.substr(header.find_first_of(':') + 1, header.size() - 1);
|
||||
if(SUCCEEDED(hr)) {
|
||||
hr = _spXhr->SetRequestHeader(std::wstring(key.begin(), key.end()).c_str(), std::wstring(value.begin(), value.end()).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if(SUCCEEDED(hr) && userAuthentication) {
|
||||
std::string authHeaders = std::accumulate(headers.begin(), headers.end(), std::string(""));
|
||||
hr = authenticateUser(verb, url, authHeaders);
|
||||
}
|
||||
|
||||
if(SUCCEEDED(hr) && !cookieFile.empty()) {
|
||||
hr = processCookieFile(url, cookieFile);
|
||||
}
|
||||
|
||||
if(FAILED(hr)) {
|
||||
cancelRequest(hr);
|
||||
}
|
||||
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
HRESULT HttpConnection::authenticateUser(std::string& verb, std::string& url, std::string& headers)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
std::string authToken;
|
||||
std::string authSig;
|
||||
std::string authBody;
|
||||
|
||||
if(_pRequest->getRequestDataSize() > 0)
|
||||
authBody = _pRequest->getRequestData();
|
||||
|
||||
if(getAuthenticationToken(verb, url, headers, authBody, authToken, authSig)) {
|
||||
hr = _spXhr->SetRequestHeader(L"Authorization", std::wstring(authToken.begin(), authToken.end()).c_str());
|
||||
|
||||
if(SUCCEEDED(hr)) {
|
||||
hr = _spXhr->SetRequestHeader(L"Signature", std::wstring(authSig.begin(), authSig.end()).c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = INET_E_AUTHENTICATION_REQUIRED;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT HttpConnection::processCookieFile(std::string& url, std::string& cookieFile)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
HttpCookie cookie;
|
||||
cookie.setCookieFileName(cookieFile);
|
||||
auto cookies = cookie.getCookies();
|
||||
std::string cookieInfo = "";
|
||||
int cCnt = 0;
|
||||
|
||||
for(auto iter = cookies->begin(); iter != cookies->end(); iter++)
|
||||
{
|
||||
if(url.find(iter->domain) != std::string::npos)
|
||||
{
|
||||
std::string keyVal = iter->name;
|
||||
keyVal.append("=");
|
||||
keyVal.append(iter->value);
|
||||
if(cCnt != 0) {
|
||||
cookieInfo.append(";");
|
||||
}
|
||||
cookieInfo.append(keyVal);
|
||||
cCnt++;
|
||||
}
|
||||
}
|
||||
|
||||
if(!cookieInfo.empty() && nullptr != _spXhr) {
|
||||
hr = _spXhr->SetRequestHeader(L"Cookie", std::wstring(cookieInfo.begin(), cookieInfo.end()).c_str());
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
bool HttpConnection::send()
|
||||
{
|
||||
if (!_isInitialized) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HRESULT hr = E_FAIL;
|
||||
|
||||
if(nullptr == _spXhrRequestData) {
|
||||
hr = _spXhr->Send(NULL, 0);
|
||||
}
|
||||
else {
|
||||
hr = _spXhr->Send(_spXhrRequestData.Get(), _spXhrRequestData->Length());
|
||||
}
|
||||
|
||||
if(SUCCEEDED(hr)) {
|
||||
DWORD status = 0;
|
||||
hr = _spXhrCallback->WaitForComplete(&status);
|
||||
}
|
||||
else {
|
||||
cancelRequest(hr);
|
||||
}
|
||||
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
DWORD HttpConnection::getStatusCode()
|
||||
{
|
||||
return _spXhrCallback != nullptr ? _spXhrCallback->_statusCode : 500;
|
||||
}
|
||||
|
||||
std::string HttpConnection::getErrorMessage()
|
||||
{
|
||||
return _spXhrCallback != nullptr ? _spXhrCallback->_errorMsg : ERR_MSG_500;
|
||||
}
|
||||
|
||||
std::vector<char>* HttpConnection::getResponseHeader()
|
||||
{
|
||||
return _spXhrCallback != nullptr ? &_spXhrCallback->_headers : nullptr;
|
||||
}
|
||||
|
||||
std::vector<char>* HttpConnection::getResponseData()
|
||||
{
|
||||
return _spXhrCallback != nullptr ? &_spXhrCallback->_data : nullptr;
|
||||
}
|
||||
|
||||
void HttpConnection::cancelRequest(HRESULT hrError)
|
||||
{
|
||||
if(nullptr != _spXhr) {
|
||||
_spXhr->Abort();
|
||||
_spXhrCallback->CompleteRequest(hrError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_CC_END
|
|
@ -0,0 +1,157 @@
|
|||
/****************************************************************************
|
||||
Copyright (c) 2012 greathqy
|
||||
Copyright (c) 2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2014 Chukong Technologies Inc.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "network/HttpRequest.h"
|
||||
#include "network/HttpClient.h"
|
||||
|
||||
#include <thread>
|
||||
#include <queue>
|
||||
#include <numeric>
|
||||
#include <condition_variable>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <wrl.h>
|
||||
#if defined(_XBOX_ONE)
|
||||
#include <ixmlhttprequest2.h>
|
||||
#else
|
||||
#include <Msxml6.h>
|
||||
#endif
|
||||
using namespace Microsoft::WRL;
|
||||
using namespace Microsoft::WRL::Details;
|
||||
|
||||
#include "base/CCVector.h"
|
||||
#include "base/CCDirector.h"
|
||||
#include "base/CCScheduler.h"
|
||||
|
||||
#include "platform/CCFileUtils.h"
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
namespace network {
|
||||
|
||||
const int READ_BUFFER_MAX = 16 * 1024;
|
||||
const int REQUEST_BUFFER_MAX = 4 * 1024 * 1024;
|
||||
|
||||
const char ERR_MSG_500[] = "Internal server error";
|
||||
const char ERR_MSG_400[] = "Invalid request";
|
||||
const char ERR_MSG_401[] = "Authentication is required to access this resource";
|
||||
const char ERR_MSG_403[] = "Forbidden";
|
||||
const char ERR_MSG_404[] = "Specified resource could not be found";
|
||||
const char ERR_MSG_407[] = "Proxy authentication failed";
|
||||
const char ERR_MSG_408[] = "Request timed out";
|
||||
const char ERR_MSG_412[] = "Request aborted";
|
||||
const char ERR_MSG_DL_FLD[] = "The download of the specified resource has failed";
|
||||
|
||||
class CXHR2Callback : public Microsoft::WRL::RuntimeClass<RuntimeClassFlags<ClassicCom>, IXMLHTTPRequest2Callback>
|
||||
{
|
||||
public:
|
||||
CXHR2Callback();
|
||||
~CXHR2Callback();
|
||||
|
||||
HRESULT RuntimeClassInitialize();
|
||||
HRESULT ReadStreamData(ISequentialStream* pResponseStream);
|
||||
STDMETHODIMP OnRedirect(IXMLHTTPRequest2 *pXHR, const WCHAR *pwszRedirectUrl);
|
||||
STDMETHODIMP OnHeadersAvailable(IXMLHTTPRequest2 *pXHR, DWORD dwStatus, const WCHAR *pwszStatus);
|
||||
STDMETHODIMP OnDataAvailable(IXMLHTTPRequest2 *pXHR, ISequentialStream *pResponseStream);
|
||||
STDMETHODIMP OnResponseReceived(IXMLHTTPRequest2 *pXHR, ISequentialStream *pResponseStream);
|
||||
STDMETHODIMP OnError(IXMLHTTPRequest2 *pXHR, HRESULT hrError);
|
||||
STDMETHODIMP WaitForComplete(PDWORD pdwStatus);
|
||||
|
||||
protected:
|
||||
void CompleteRequest(HRESULT hrError);
|
||||
|
||||
private:
|
||||
HANDLE _hWfC;
|
||||
DWORD _statusCode;
|
||||
std::string _errorMsg;
|
||||
std::vector<char> _headers;
|
||||
std::vector<char> _data;
|
||||
|
||||
friend class HttpConnection;
|
||||
};
|
||||
|
||||
class CXHR2DataStream : public Microsoft::WRL::RuntimeClass<RuntimeClassFlags<ClassicCom>, ISequentialStream, IDispatch>
|
||||
{
|
||||
public:
|
||||
CXHR2DataStream();
|
||||
~CXHR2DataStream();
|
||||
|
||||
STDMETHODIMP_(ULONG) Length();
|
||||
STDMETHODIMP Init(const void *psBuffer, ULONG cbBufferSize);
|
||||
|
||||
STDMETHODIMP Read(void *pv, ULONG cb, ULONG *pcbRead);
|
||||
STDMETHODIMP Write(const void *pv, ULONG cb, ULONG *pcbWritten);
|
||||
|
||||
STDMETHODIMP_(ULONG) AddRef();
|
||||
STDMETHODIMP_(ULONG) Release();
|
||||
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);
|
||||
|
||||
STDMETHODIMP GetTypeInfoCount(unsigned int FAR* pctinfo);
|
||||
STDMETHODIMP GetTypeInfo(unsigned int iTInfo, LCID lcid, ITypeInfo FAR* FAR* ppTInfo);
|
||||
STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgDispId);
|
||||
STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR* pDispParams, VARIANT FAR* pVarResult, EXCEPINFO FAR* pExcepInfo, unsigned int FAR* puArgErr);
|
||||
|
||||
private:
|
||||
ULONG _refCnt;
|
||||
BYTE* _pData;
|
||||
ULONG _dataSize;
|
||||
ULONG _seekIndex;
|
||||
};
|
||||
|
||||
class HttpConnection
|
||||
{
|
||||
public:
|
||||
HttpConnection();
|
||||
~HttpConnection();
|
||||
|
||||
bool init(HttpRequest *pRequest, DWORD timeOutInMs = 0);
|
||||
bool open(std::string verb);
|
||||
bool open(std::string verb, bool userAuthentication);
|
||||
bool open(std::string verb, std::string cookieFile);
|
||||
bool open(std::string verb, bool userAuthentication, std::string cookieFile);
|
||||
bool send();
|
||||
DWORD getStatusCode();
|
||||
std::string getErrorMessage();
|
||||
std::vector<char>* getResponseHeader();
|
||||
std::vector<char>* getResponseData();
|
||||
|
||||
protected:
|
||||
void cancelRequest(HRESULT hrError);
|
||||
HRESULT authenticateUser(std::string& verb, std::string& url, std::string& headers);
|
||||
HRESULT processCookieFile(std::string& url, std::string& cookieFile);
|
||||
|
||||
private:
|
||||
bool _isInitialized;
|
||||
ComPtr<IXMLHTTPRequest2> _spXhr;
|
||||
ComPtr<CXHR2Callback> _spXhrCallback;
|
||||
ComPtr<CXHR2DataStream> _spXhrRequestData;
|
||||
DWORD _timeOutInMs;
|
||||
cocos2d::network::HttpRequest* _pRequest;
|
||||
};
|
||||
}
|
||||
|
||||
NS_CC_END
|
Loading…
Reference in New Issue