CEF3中如何截获XMLHttpRequest(XHR)的笔记

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


你可能感兴趣的:(CEF3中如何截获XMLHttpRequest(XHR)的笔记)