标题:CEF3中如何截获XMLHttpRequest(HDR)请求和返回数据!
Title: How to intercept XMLHttpRequest in CEF3!
阅读对象:主要是给自己看的,免得以后忘记。
环境:[1]VS2013SP3 [2]cef_binary_3.1916.1804_windows32
第一次更新日期:2014-11-4
最近更新日期:2014-11-4
正文:
总共分为四步步骤:
第一步:
extern UINT WM_XMLHttpRequest;
CefRefPtr<CefResourceHandler> ClientHandler::GetResourceHandler(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request)
{
//http://www.magpcss.org/ceforum/viewtopic.php?f=6&t=10794
if (request->GetResourceType() == RT_XHR)
{
//Second?
CefRefPtr<KagulaResourceHandler> resHandler = new KagulaResourceHandler();
resHandler->_browser = browser;
resHandler->_frame = frame;
resHandler->_clientHandler = this;
return resHandler;
}
return NULL;
}
第二步:
KagulaResourceHandler.h清单
#pragma once
#include <include/cef_app.h>
#include <include/cef_urlrequest.h>
class ClientHandler;
class KagulaUrlRequestClient;
class KagulaResourceHandler : public CefResourceHandler
{
public:
KagulaResourceHandler() :
_offset(0)
{}
virtual bool ProcessRequest(CefRefPtr<CefRequest> request,
CefRefPtr<CefCallback> callback)
OVERRIDE;
virtual void GetResponseHeaders(CefRefPtr<CefResponse> response,
int64& response_length,
CefString& redirectUrl) OVERRIDE;
virtual void Cancel() OVERRIDE;
virtual bool ReadResponse(void* data_out, int bytes_to_read,
int& bytes_read,
CefRefPtr<CefCallback> callback)
OVERRIDE;
public:
CefRefPtr<ClientHandler> _clientHandler;
CefRefPtr<CefBrowser> _browser;
CefRefPtr<CefFrame> _frame;
CefRefPtr<CefCallback> _responseHeadersReadyCallback;
CefRefPtr<KagulaUrlRequestClient> _webRequestClient;
CefRefPtr<CefURLRequest> _webRequest;
std::string _content;
private:
size_t _offset;
IMPLEMENT_REFCOUNTING(KagulaResourceHandler);
IMPLEMENT_LOCKING(KagulaResourceHandler);
};
KagulaResourceHandler.cpp清单
#include <assert.h>
#include "KagulaResourceHandler.h"
#include "client_handler.h"
#include "KagulaUrlRequestClient.h"
bool KagulaResourceHandler::ProcessRequest(CefRefPtr<CefRequest> request,
CefRefPtr<CefCallback> callback)
{
//1. Start the request using WebRequest
//2. Return True to handle the request
//3. Once response headers are ready call
// callback.Continue()
_responseHeadersReadyCallback = callback;
_webRequestClient = new KagulaUrlRequestClient(_frame);
_webRequestClient->_resourceHandler = this;
request->SetFlags(UR_FLAG_ALLOW_CACHED_CREDENTIALS | UR_FLAG_ALLOW_COOKIES);
//To skip cache :
//| request.SetFlags(cefpython.Request.Flags["SkipCache"])
//Must keep a strong reference to the WebRequest() object.
_webRequest = CefURLRequest::Create(request, _webRequestClient.get());
return true;
}
void KagulaResourceHandler::GetResponseHeaders(CefRefPtr<CefResponse> response,
int64& response_length, CefString& redirectUrl)
{
assert(CefCurrentlyOn(TID_IO));
//if (this->mimeType)
//{
// response->SetMimeType(CefString(this->mimeType));
// response->SetStatus(200);
//}
//else
//{
// response->SetStatus(500);
//}
CefRefPtr<CefResponse> webResponse = _webRequestClient->_response;
if (webResponse!=nullptr)
{
CefResponse::HeaderMap headerMap;
webResponse->GetHeaderMap(headerMap);
response->SetHeaderMap(headerMap);
response->SetStatus(webResponse->GetStatus());
response->SetStatusText(webResponse->GetStatusText());
CefString cefstr = webResponse->GetMimeType();
if (!cefstr.empty())
{
response->SetMimeType(webResponse->GetMimeType());
}
}
response_length = _content.size();
_offset = 0;
}
void KagulaResourceHandler::Cancel()
{
}
bool KagulaResourceHandler::ReadResponse(void* data_out, int bytes_to_read,
int& bytes_read, CefRefPtr<CefCallback> callback)
{
//here fill what response data will be return!
size_t size = _content.size();
if (_offset < size) {
int transfer_size = min(bytes_to_read, static_cast<int>(size - _offset));
memcpy(data_out, _content.c_str() + _offset, transfer_size);
_offset += transfer_size;
bytes_read = transfer_size;//output
char *pDataOut = (char*)data_out;
return true;
}
return false;
}
KagulaUrlRequestClient.h清单
#pragma once
#include <include/cef_app.h>
#include <include/cef_urlrequest.h>
#include "KagulaResourceHandler.h"
#include <string>
#include <map>
class KagulaUrlRequestClient : public CefURLRequestClient
{
public:
KagulaUrlRequestClient(CefRefPtr<CefFrame> _frame):_dataLength(0)
{}
// CefURLRequestClient methods
virtual void OnRequestComplete(CefRefPtr<CefURLRequest> request) OVERRIDE;
virtual void OnUploadProgress(CefRefPtr<CefURLRequest> request, uint64 current, uint64 total) OVERRIDE;
virtual void OnDownloadData(CefRefPtr<CefURLRequest> request, const void* data, size_t data_length) OVERRIDE;
virtual void OnDownloadProgress(CefRefPtr<CefURLRequest> request, uint64 current, uint64 total) OVERRIDE;
virtual bool GetAuthCredentials(bool isProxy, const CefString& host, int port, const CefString& realm, const CefString& scheme, CefRefPtr<CefAuthCallback> callback) OVERRIDE;
public:
CefRefPtr<CefResponse> _response;
CefRefPtr<KagulaResourceHandler> _resourceHandler;
std::string _data;
size_t _dataLength;
private:
IMPLEMENT_REFCOUNTING(KagulaUrlRequestClient);
};
KagulaUrlRequestClient.cpp清单
#include "KagulaUrlRequestClient.h"
#include "client_handler.h"
void KagulaUrlRequestClient::OnRequestComplete(CefRefPtr<CefURLRequest> request)
{
std::string statusText = "Unknown";
std::map<int,std::string> mqpReqStatus;
mqpReqStatus[0]="Unknown";
mqpReqStatus[1]="Success";
mqpReqStatus[2]="Pending";
mqpReqStatus[3]="Canceled";
mqpReqStatus[4]="Failed";
if (mqpReqStatus.find(request->GetRequestStatus()) != mqpReqStatus.end())
statusText = mqpReqStatus[request->GetRequestStatus()];
_response = request->GetResponse();
_data = _resourceHandler->_clientHandler->_OnResourceResponse(
_resourceHandler->_browser,
_resourceHandler->_frame,
request->GetRequest(),
request->GetRequestStatus(),
request->GetRequestError(),
request->GetResponse(),
_data);
_dataLength = _data.length();
//ResourceHandler.GetResponseHeaders() will get called
//after _responseHeadersReadyCallback.Continue() is called.
_resourceHandler->_content = _data;
_resourceHandler->_responseHeadersReadyCallback->Continue();
}
void KagulaUrlRequestClient::OnUploadProgress(CefRefPtr<CefURLRequest> request, uint64 current, uint64 total)
{
}
void KagulaUrlRequestClient::OnDownloadData(CefRefPtr<CefURLRequest> request, const void* data, size_t data_length)
{
char* buf = new char[data_length + 1];
if (buf!=nullptr)
{
memset(buf, 0, data_length + 1);
memcpy(buf, data, data_length);
_data += buf;
delete buf;
}
}
void KagulaUrlRequestClient::OnDownloadProgress(CefRefPtr<CefURLRequest> request, uint64 current, uint64 total)
{
}
bool KagulaUrlRequestClient::GetAuthCredentials(bool isProxy, const CefString& host, int port, const CefString& realm, const CefString& scheme, CefRefPtr<CefAuthCallback> callback)
{
return true;
}
第三步:
std::string ClientHandler::_OnResourceResponse(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request,
CefURLRequest::Status status, CefURLRequest::ErrorCode errorCode, CefRefPtr<CefResponse> response, std::string data)
{
std::string _data = data;
std::string strPostData;
std::wstring wsR = L"url=>";
wsR.append(frame->GetURL().ToWString());
wsR.append(L"post data=>");
{
CefRefPtr<CefPostData> postData = request->GetPostData();
if (postData != NULL) {
CefPostData::ElementVector elements;
postData->GetElements(elements);
if (elements.size() > 0) {
std::wstring queryString;
// it looks like the whole query string is in this first post data element?
CefRefPtr<CefPostDataElement> query = elements[0];
if (query->GetType() == PDE_TYPE_BYTES || query->GetType() == PDE_TYPE_FILE) {
const unsigned int buffSize = query->GetBytesCount() >= 1024 ? 1024 : query->GetBytesCount() + 1;
char *buff = new char[buffSize];
if (buff!=nullptr)
{
//Get Post Data
memset(buff, 0, buffSize);
query->GetBytes(query->GetBytesCount() >= buffSize ? buffSize-1 : query->GetBytesCount(), buff);
strPostData = buff;
wsR.append(kagula::s2ws_FromUTF8(strPostData));
delete[] buff;
}
}
}
}
}
wsR.append(L"content=>");
wsR.append(kagula::s2ws_FromUTF8(data));
LOG_TRACE(wsR.c_str());
//
CefString url = frame->GetURL();
//send to my main window!
std::vector<std::string> vecStr;
vecStr.push_back(url.ToString());
vecStr.push_back(strPostData);
vecStr.push_back(data);
CIPCData::SetVecStr(vecStr);
HWND hwnd = (HWND)(CIPCData::GetMainHWND());
SendMessage(hwnd, WM_XMLHttpRequest, NULL, NULL);
return _data;
}
第四步:
LRESULT Ccat8637_BrandDlg::OnXMLHttpRequest(WPARAM wParam, LPARAM lParam)
{
std::vector<std::string> vecS;
CIPCData::GetVecStr(vecS);
if (vecS.size() == 3)
{
#ifdef _DEBUG
std::wstring strMsg = L"OnXMLHttpRequest=>";
strMsg.append(kagula::s2ws_FromUTF8(vecS[2]));
LOG_TRACE(strMsg);
#endif
}
return S_OK;
}