标题: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; }