341 lines
13 KiB
C#
341 lines
13 KiB
C#
using CefSharp;
|
|
using NaiBa.Util.Extension;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Specialized;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Security.Cryptography.X509Certificates;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace AllBase
|
|
{
|
|
public class RequestHandler : IRequestHandler
|
|
{
|
|
public List<string> IgnoreList = new List<string>();
|
|
public List<string> NotIgnoreList = new List<string>();
|
|
public string UserAgent = string.Empty;
|
|
public List<Cookie> CookieList = new List<Cookie>(); // 留作测试使用
|
|
|
|
public event Action<string, string, string> ResourceLoadComplete; // requestUrl, postData, responseData
|
|
public event Action<string, string, string> ResourceRedirect; // requestUrl, postData, redirectUrl
|
|
|
|
bool IRequestHandler.OnBeforeBrowse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, bool isRedirect)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool IRequestHandler.OnOpenUrlFromTab(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture)
|
|
{
|
|
return OnOpenUrlFromTab(browserControl, browser, frame, targetUrl, targetDisposition, userGesture);
|
|
}
|
|
|
|
protected virtual bool OnOpenUrlFromTab(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool IRequestHandler.OnCertificateError(IWebBrowser browserControl, IBrowser browser, CefErrorCode errorCode, string requestUrl, ISslInfo sslInfo, IRequestCallback callback)
|
|
{
|
|
//NOTE: If you do not wish to implement this method returning false is the default behaviour
|
|
// We also suggest you explicitly Dispose of the callback as it wraps an unmanaged resource.
|
|
//callback.Dispose();
|
|
//return false;
|
|
|
|
//NOTE: When executing the callback in an async fashion need to check to see if it's disposed
|
|
if (!callback.IsDisposed)
|
|
{
|
|
using (callback)
|
|
{
|
|
//To allow certificate
|
|
//callback.Continue(true);
|
|
//return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void IRequestHandler.OnPluginCrashed(IWebBrowser browserControl, IBrowser browser, string pluginPath)
|
|
{
|
|
// TODO: Add your own code here for handling scenarios where a plugin crashed, for one reason or another.
|
|
}
|
|
|
|
CefReturnValue IRequestHandler.OnBeforeResourceLoad(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback)
|
|
{
|
|
if (NotIgnoreList.Any())
|
|
{
|
|
if (NotIgnoreList.Where(p => request.Url.Contains(p)).Any())
|
|
{
|
|
return CefReturnValue.Continue;
|
|
}
|
|
}
|
|
if (IgnoreList.Any())
|
|
{
|
|
if (IgnoreList.Where(p => request.Url.Contains(p)).Any())
|
|
{
|
|
return CefReturnValue.Cancel;
|
|
}
|
|
}
|
|
NameValueCollection headers = request.Headers;
|
|
if (!string.IsNullOrEmpty(UserAgent))
|
|
{
|
|
headers["User-Agent"] = UserAgent;
|
|
}
|
|
request.Headers = headers;
|
|
return CefReturnValue.Continue;
|
|
}
|
|
|
|
bool IRequestHandler.GetAuthCredentials(IWebBrowser browserControl, IBrowser browser, IFrame frame, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback)
|
|
{
|
|
//NOTE: If you do not wish to implement this method returning false is the default behaviour
|
|
// We also suggest you explicitly Dispose of the callback as it wraps an unmanaged resource.
|
|
|
|
callback.Dispose();
|
|
return false;
|
|
}
|
|
|
|
bool IRequestHandler.OnSelectClientCertificate(IWebBrowser browserControl, IBrowser browser, bool isProxy, string host, int port, X509Certificate2Collection certificates, ISelectClientCertificateCallback callback)
|
|
{
|
|
//NOTE: If you do not wish to implement this method returning false is the default behaviour
|
|
// We also suggest you explicitly Dispose of the callback as it wraps an unmanaged resource.
|
|
|
|
return OnSelectClientCertificate(browserControl, browser, isProxy, host, port, certificates, callback);
|
|
}
|
|
|
|
protected virtual bool OnSelectClientCertificate(IWebBrowser browserControl, IBrowser browser, bool isProxy, string host, int port, X509Certificate2Collection certificates, ISelectClientCertificateCallback callback)
|
|
{
|
|
callback.Dispose();
|
|
return false;
|
|
}
|
|
|
|
void IRequestHandler.OnRenderProcessTerminated(IWebBrowser browserControl, IBrowser browser, CefTerminationStatus status)
|
|
{
|
|
// TODO: Add your own code here for handling scenarios where the Render Process terminated for one reason or another.
|
|
// browserControl.Load(CefExample.RenderProcessCrashedUrl);
|
|
}
|
|
|
|
bool IRequestHandler.OnQuotaRequest(IWebBrowser browserControl, IBrowser browser, string originUrl, long newSize, IRequestCallback callback)
|
|
{
|
|
//NOTE: If you do not wish to implement this method returning false is the default behaviour
|
|
// We also suggest you explicitly Dispose of the callback as it wraps an unmanaged resource.
|
|
//callback.Dispose();
|
|
//return false;
|
|
|
|
//NOTE: When executing the callback in an async fashion need to check to see if it's disposed
|
|
if (!callback.IsDisposed)
|
|
{
|
|
using (callback)
|
|
{
|
|
//Accept Request to raise Quota
|
|
//callback.Continue(true);
|
|
//return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void IRequestHandler.OnResourceRedirect(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response, ref string newUrl)
|
|
{
|
|
if (ResourceRedirect != null)
|
|
{
|
|
string postData = GetPostData(request);
|
|
ResourceRedirect.Invoke(request.Url, postData, newUrl);
|
|
}
|
|
}
|
|
|
|
bool IRequestHandler.OnProtocolExecution(IWebBrowser browserControl, IBrowser browser, string url)
|
|
{
|
|
return url.StartsWith("mailto");
|
|
}
|
|
|
|
void IRequestHandler.OnRenderViewReady(IWebBrowser browserControl, IBrowser browser)
|
|
{
|
|
}
|
|
|
|
bool IRequestHandler.OnResourceResponse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)
|
|
{
|
|
//NOTE: You cannot modify the response, only the request
|
|
// You can now access the headers
|
|
//var headers = response.ResponseHeaders;
|
|
return false;
|
|
}
|
|
|
|
IResponseFilter IRequestHandler.GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)
|
|
{
|
|
string cookie = response.ResponseHeaders["Set-Cookie"].ParseToString();
|
|
if (!string.IsNullOrEmpty(cookie))
|
|
{
|
|
SetCookie(cookie);
|
|
}
|
|
string contentType = response.ResponseHeaders["Content-Type"];
|
|
if (string.IsNullOrEmpty(contentType))
|
|
{
|
|
return null;
|
|
}
|
|
if (contentType.Contains("application/json") || contentType.Contains("text/javascript"))
|
|
{
|
|
if (ResourceLoadComplete != null)
|
|
{
|
|
IResponseFilter filter = FilterManager.CreateFilter(request.Identifier.ToString());
|
|
return filter;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
void IRequestHandler.OnResourceLoadComplete(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response, UrlRequestStatus status, long receivedContentLength)
|
|
{
|
|
string contentType = response.ResponseHeaders["Content-Type"];
|
|
if (string.IsNullOrEmpty(contentType))
|
|
{
|
|
return;
|
|
}
|
|
if (contentType.Contains("application/json") || contentType.Contains("text/javascript"))
|
|
{
|
|
if (ResourceLoadComplete != null)
|
|
{
|
|
JsonFilter jsonFilter = FilterManager.GetFileter(request.Identifier.ToString()) as JsonFilter;
|
|
if (jsonFilter != null)
|
|
{
|
|
UTF8Encoding encoding = new UTF8Encoding();
|
|
string responseData = encoding.GetString(jsonFilter.DataAll.ToArray());
|
|
string postData = GetPostData(request);
|
|
ResourceLoadComplete.Invoke(request.Url, postData, responseData);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
private void SetCookie(string cookie)
|
|
{
|
|
string[] commaArr = cookie.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
|
|
foreach (string comma in commaArr)
|
|
{
|
|
string[] semicolonArr = comma.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
|
|
foreach (string semicolon in semicolonArr)
|
|
{
|
|
string temp = semicolon.ParseToString().Trim();
|
|
if (string.IsNullOrEmpty(temp))
|
|
{
|
|
continue;
|
|
}
|
|
if (!temp.Contains("="))
|
|
{
|
|
continue;
|
|
}
|
|
if (temp.ToLower().StartsWith("path=") || temp.ToLower().StartsWith("expires=") || temp.ToLower().StartsWith("domain="))
|
|
{
|
|
continue;
|
|
}
|
|
string[] keyValue = temp.Split('=');
|
|
Cookie cookieObj = CookieList.Where(p => p.Name == keyValue[0]).FirstOrDefault();
|
|
if (cookieObj == null)
|
|
{
|
|
cookieObj = new Cookie
|
|
{
|
|
Name = keyValue[0],
|
|
Value = keyValue[1]
|
|
};
|
|
CookieList.Add(cookieObj);
|
|
}
|
|
else
|
|
{
|
|
cookieObj.Value = keyValue[1];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private string GetPostData(IRequest request)
|
|
{
|
|
string postData = string.Empty;
|
|
if (request.PostData != null && request.PostData.Elements.Any())
|
|
{
|
|
UTF8Encoding encoding = new UTF8Encoding();
|
|
postData = encoding.GetString(request.PostData.Elements[0].Bytes);
|
|
postData = GetHtml.UrlDecode(postData);
|
|
}
|
|
return postData;
|
|
}
|
|
}
|
|
|
|
public class JsonFilter : IResponseFilter
|
|
{
|
|
public List<byte> DataAll = new List<byte>();
|
|
|
|
public FilterStatus Filter(Stream dataIn, out long dataInRead, Stream dataOut, out long dataOutWritten)
|
|
{
|
|
try
|
|
{
|
|
if (dataIn == null || dataIn.Length == 0)
|
|
{
|
|
dataInRead = 0;
|
|
dataOutWritten = 0;
|
|
|
|
return FilterStatus.Done;
|
|
}
|
|
|
|
dataInRead = dataIn.Length;
|
|
dataOutWritten = Math.Min(dataInRead, dataOut.Length);
|
|
|
|
dataIn.CopyTo(dataOut);
|
|
dataIn.Seek(0, SeekOrigin.Begin);
|
|
byte[] bs = new byte[dataIn.Length];
|
|
dataIn.Read(bs, 0, bs.Length);
|
|
DataAll.AddRange(bs);
|
|
|
|
dataInRead = dataIn.Length;
|
|
dataOutWritten = dataIn.Length;
|
|
|
|
return FilterStatus.NeedMoreData;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
dataInRead = dataIn.Length;
|
|
dataOutWritten = dataIn.Length;
|
|
|
|
return FilterStatus.Done;
|
|
}
|
|
}
|
|
|
|
public bool InitFilter()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
|
|
}
|
|
}
|
|
|
|
public class FilterManager
|
|
{
|
|
private static Dictionary<string, IResponseFilter> dataList = new Dictionary<string, IResponseFilter>();
|
|
|
|
public static IResponseFilter CreateFilter(string guid)
|
|
{
|
|
lock (dataList)
|
|
{
|
|
var filter = new JsonFilter();
|
|
dataList.Add(guid, filter);
|
|
|
|
return filter;
|
|
}
|
|
}
|
|
|
|
public static IResponseFilter GetFileter(string guid)
|
|
{
|
|
lock (dataList)
|
|
{
|
|
return dataList[guid];
|
|
}
|
|
}
|
|
}
|
|
}
|