main_view_browser_handler.cpp
17.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
#include "stdafx.h"
#include "etradeclient/browser/main_view_browser_handler.h"
#include <stdio.h>
#include <algorithm>
#include <set>
#include <sstream>
#include <string>
#include <vector>
#include "include/cef_browser.h"
#include "include/cef_frame.h"
#include "include/cef_path_util.h"
#include "include/cef_process_util.h"
#include "include/cef_trace.h"
#include "include/base/cef_lock.h"
#include "include/wrapper/cef_helpers.h"
#include "etradeclient/browser/browser_util.h"
#include "etradeclient/browser/render_delegate.h"
#include "etradeclient/utility/session.h"
#include "etradeclient/browser/error_page.h"
#include "etradeclient/browser/async_js_callback_handler.h"
#include "etradeclient/utility/win_msg_define.h"
#include "etradeclient/utility/string_converter.h"
MainViewBrowserHandler::MainViewBrowserHandler()
{}
MainViewBrowserHandler::~MainViewBrowserHandler()
{}
//@{ CefClient methods
bool MainViewBrowserHandler::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefProcessId source_process, CefRefPtr<CefProcessMessage> message)
{
CEF_REQUIRE_UI_THREAD();
if(m_browser_msg_router->OnProcessMessageReceived(browser, source_process, message))
return true;
return false;
}
//@}
//@{ CefLifeSpanHandler methods
void MainViewBrowserHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser)
{
CEF_REQUIRE_UI_THREAD();
if(!m_browser_msg_router)
{
// Create the browser-side router for query handling.
CefMessageRouterConfig config;
m_browser_msg_router = CefMessageRouterBrowserSide::Create(config);
//Create other message handlers here.
AsyncJSCallbackHandler::HW_Create(m_msg_handlers);
// Register handlers with the router.
for (const auto& handler : m_msg_handlers)
m_browser_msg_router->AddHandler(handler, false);
}
auto is_popup = browser->IsPopup(); // @todo remove
// get browser ID
INT nBrowserId = browser->GetIdentifier();
// The frame window will be the parent of the browser window
HWND hWindow = GetParent(browser->GetHost()->GetWindowHandle());
// Send msg to View to hold reference to this browser
::SendMessage(hWindow, WM_CEF_NEW_BROWSER, (WPARAM)nBrowserId, (LPARAM)browser.get());
// call parent
CefLifeSpanHandler::OnAfterCreated(browser);
}
bool MainViewBrowserHandler::DoClose(CefRefPtr<CefBrowser> browser)
{
CEF_REQUIRE_UI_THREAD();
HWND hwnd = GetParent(browser->GetHost()->GetWindowHandle()); // The frame window will be the parent of the browser window
::SendMessage(hwnd, WM_CEF_CLOSE_BROWSER, (WPARAM)browser.get(), (LPARAM)NULL); // send close browser notification.
// Allow the close. For windowed browsers this will result in the OS close
// event being sent.
return false;
}
void MainViewBrowserHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser)
{
CEF_REQUIRE_UI_THREAD();
m_browser_msg_router->OnBeforeClose(browser);
// All browser windows have closed.
// Remove and delete message router handlers.
for (const auto& handler : m_msg_handlers)
m_browser_msg_router->RemoveHandler(handler);
m_msg_handlers.clear();
m_browser_msg_router = NULL;
CefLifeSpanHandler::OnBeforeClose(browser); // call parent
}
bool MainViewBrowserHandler::OnBeforePopup(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& target_url,
const CefString& target_frame_name,
cef_window_open_disposition_t target_disposition,
bool user_gesture,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings,
bool* no_javascript_access)
{
CEF_REQUIRE_IO_THREAD();
if(browser->GetHost()->IsWindowRenderingDisabled())
return true; // Cancel popups in off-screen rendering mode.
// The frame window will be the parent of the browser window
HWND hWindow = GetParent( browser->GetHost()->GetWindowHandle() );
// send message
LPCTSTR lpszURL(target_url.c_str());
if( ::SendMessage( hWindow, WM_CEF_WINDOW_CHECK, (WPARAM)&popupFeatures, (LPARAM)lpszURL) == S_FALSE )
return true;
// send message
if( ::SendMessage( hWindow, WM_CEF_NEW_WINDOW, (WPARAM)&popupFeatures, (LPARAM)&windowInfo) == S_FALSE )
return true;
// call parent, The |client| and |settings| values will default to the source browser's values.
return CefLifeSpanHandler::OnBeforePopup(browser, frame, target_url, target_frame_name, target_disposition, user_gesture, popupFeatures, windowInfo, client, settings, no_javascript_access);
}
// @}
//@{ CefContextMenuHandler methods
void MainViewBrowserHandler::OnBeforeContextMenu(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefContextMenuParams> params, CefRefPtr<CefMenuModel> model)
{
#ifndef _DEBUG
// Block the context menu for safety consideration. !!!BUT we should still allow context menu for "selection" & "editable" items.
if ((params->GetTypeFlags() & (CM_TYPEFLAG_SELECTION | CM_TYPEFLAG_EDITABLE)) == 0)
{
model->Clear();
return;
}
#endif // !_DEBUG
// call parent to get the default behavior.
CefContextMenuHandler::OnBeforeContextMenu(browser, frame, params, model);
}
bool MainViewBrowserHandler::OnContextMenuCommand(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefContextMenuParams> params, int command_id, EventFlags event_flags)
{
// call parent to get the default behavior.
return CefContextMenuHandler::OnContextMenuCommand(browser, frame, params, command_id, event_flags);
}
//@}
//@{ CefLoadHandler methods
void MainViewBrowserHandler::OnLoadingStateChange(CefRefPtr<CefBrowser> browser, bool is_loading, bool can_go_back, bool can_go_forward)
{
CEF_REQUIRE_UI_THREAD();
INT state = 0;
// set state
if( is_loading )
state |= CEF_BIT_IS_LOADING;
if( can_go_back )
state |= CEF_BIT_CAN_GO_BACK;
if( can_go_forward )
state |= CEF_BIT_CAN_GO_FORWARD;
HWND hWindow = GetParent(browser->GetHost()->GetWindowHandle()); // The frame window will be the parent of the browser window.
::SendMessage(hWindow, WM_CEF_STATE_CHANGE, (WPARAM)state, NULL); // send message.
CefLoadHandler::OnLoadingStateChange(browser, is_loading, can_go_back, can_go_forward); // call parent.
}
//@}
//@{ CefDisplayHandler methods
void MainViewBrowserHandler::OnAddressChange(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, const CefString& url)
{
CEF_REQUIRE_UI_THREAD();
HWND hWindow = GetParent(browser->GetHost()->GetWindowHandle()); // The frame window will be the parent of the browser window.
LPCTSTR pszURL(url.c_str());
::SendMessage( hWindow, WM_CEF_ADDRESS_CHANGE, (WPARAM)pszURL, NULL );
CefDisplayHandler::OnAddressChange(browser, frame, url); // call parent.
}
void MainViewBrowserHandler::OnTitleChange(CefRefPtr<CefBrowser> browser, const CefString& title)
{
CEF_REQUIRE_UI_THREAD();
HWND hWindow = GetParent(browser->GetHost()->GetWindowHandle()); // The frame window will be the parent of the browser window.
LPCTSTR pszTitle(title.c_str());
::SendMessage( hWindow, WM_CEF_TITLE_CHANGE, (WPARAM)pszTitle, NULL );
CefDisplayHandler::OnTitleChange(browser, title); // call parent.
}
void MainViewBrowserHandler::OnStatusMessage(CefRefPtr<CefBrowser> browser, const CefString& value)
{
CEF_REQUIRE_UI_THREAD();
#if _DEBUG
SendStatusToMainWnd(browser, value);
#endif // _DEBUG
CefDisplayHandler::OnStatusMessage(browser, value); // call parent.
}
bool MainViewBrowserHandler::OnConsoleMessage(CefRefPtr<CefBrowser> browser,
cef_log_severity_t level,
const CefString& message,
const CefString& source,
int line)
{
CEF_REQUIRE_UI_THREAD();
return TRUE;
}
//@}
//@{ CefDownloadHandler methods
void MainViewBrowserHandler::OnBeforeDownload(CefRefPtr<CefBrowser> browser, CefRefPtr<CefDownloadItem> download_item, const CefString& suggested_name, CefRefPtr<CefBeforeDownloadCallback> callback)
{
CEF_REQUIRE_UI_THREAD();
// Continue the download and show the "Save As" dialog.
callback->Continue(GetDownloadPath(suggested_name), true);
}
void MainViewBrowserHandler::OnDownloadUpdated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefDownloadItem> download_item, CefRefPtr<CefDownloadItemCallback> callback)
{
CEF_REQUIRE_UI_THREAD();
CEFDownloadItemValues values;
values.bIsValid = download_item->IsValid();
values.bIsInProgress = download_item->IsInProgress();
values.bIsComplete = download_item->IsComplete();
values.bIsCanceled = download_item->IsCanceled();
values.nProgress = download_item->GetPercentComplete();
values.nSpeed = download_item->GetCurrentSpeed();
values.nReceived = download_item->GetReceivedBytes();
values.nTotal = download_item->GetTotalBytes();
CefString& szDispo = download_item->GetContentDisposition();
// The frame window will be the parent of the browser window
HWND hWindow = GetParent( browser->GetHost()->GetWindowHandle() );
// send message
::SendMessage( hWindow, WM_CEF_DOWNLOAD_UPDATE, (WPARAM)&values, NULL );
}
//@}
//@{ CefLoadHandler methods
void MainViewBrowserHandler::OnLoadStart(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
TransitionType transition_type)
{
CEF_REQUIRE_UI_THREAD();
// The frame window will be the parent of the browser window
HWND hWindow = GetParent( browser->GetHost()->GetWindowHandle() );
::SendMessage(hWindow, WM_CEF_LOAD_START, NULL, NULL);
SendStatusToMainWnd(browser, L"页面加载中...");
CefLoadHandler::OnLoadStart(browser, frame, transition_type); // call parent
}
void MainViewBrowserHandler::OnLoadEnd(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, int http_status_code)
{
CEF_REQUIRE_UI_THREAD();
static const int kHttpCode_OK = 200; // @TODO 统一定义这些值
static const int kFileCode_OK = 0; // code of loading local file
// The frame window will be the parent of the browser window
HWND hWindow = GetParent( browser->GetHost()->GetWindowHandle() );
CefString url = frame->GetURL();
LPCTSTR url_(url.c_str()); // WARNNING:LPCTSTR url_( frame->GetURL().c_str()) will get an incorrect string, don't do this way!
::SendMessage(hWindow, WM_CEF_LOAD_END, http_status_code, (LPARAM)url_);
if (kHttpCode_OK == http_status_code || kFileCode_OK == http_status_code)
SendStatusToMainWnd(browser, L"页面加载完成!");
else
SendStatusToMainWnd(browser, L"页面加载出错!");
CefLoadHandler::OnLoadEnd(browser, frame, http_status_code); // call parent
}
void MainViewBrowserHandler::OnLoadError(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, ErrorCode error_code, const CefString& error_text, const CefString& failed_url)
{
CEF_REQUIRE_UI_THREAD();
SendStatusToMainWnd(browser, L"页面加载结束!");
// Don't display an error for if request aborted.
if (error_code == ERR_ABORTED)
return;
// The frame window will be the parent of the browser window
HWND hWindow = GetParent(browser->GetHost()->GetWindowHandle());
LPCTSTR failed_url_(failed_url.c_str());
CefString error_code_str = ErrorPage::ToErrorString(error_code);
::SendMessage(hWindow, WM_CEF_LOAD_ERROR, (WPARAM)failed_url_, (LPARAM)error_code_str.c_str());
// Don't display an error for external protocols that we allow the OS to handle. See OnProtocolExecution().
if (error_code == ERR_UNKNOWN_URL_SCHEME)
{
std::string urlStr = frame->GetURL();
if (urlStr.find("spotify:") == 0)
return;
}
frame->LoadURL(ErrorPage::Url(failed_url, error_code, error_text)); // Load the error page.
}
//@}
//@{ CefRequestHandler methods
CefRefPtr<CefResourceHandler> MainViewBrowserHandler::GetResourceHandler(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request)
{
CEF_REQUIRE_IO_THREAD();
return NULL;
}
bool MainViewBrowserHandler::GetAuthCredentials(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, bool isProxy, const CefString& host, int port, const CefString& realm, const CefString& scheme, CefRefPtr<CefAuthCallback> callback)
{
// The frame window will be the parent of the browser window
HWND hWindow = GetParent( browser->GetHost()->GetWindowHandle() );
CEFAuthenticationValues values;
values.lpszHost = host.c_str();
values.lpszRealm = realm.c_str();
// send info
if(::SendMessage( hWindow, WM_CEF_AUTHENTICATE, (WPARAM)&values, (LPARAM)NULL ) == S_OK)
{
callback->Continue( values.szUserName, values.szUserPass );
return TRUE;
}
// canceled
return FALSE;
}
bool MainViewBrowserHandler::OnQuotaRequest(CefRefPtr<CefBrowser> browser, const CefString& origin_url, int64 new_size, CefRefPtr<CefRequestCallback> callback)
{
static const int64 max_size = 1024 * 1024 * 20; // 20mb.
// Grant the quota request if the size is reasonable.
callback->Continue(new_size <= max_size);
// call parent
return CefRequestHandler::OnQuotaRequest(browser, origin_url, new_size, callback);
}
void MainViewBrowserHandler::OnProtocolExecution(CefRefPtr<CefBrowser> browser, const CefString& url, bool& allow_os_execution)
{
// do default
CefRequestHandler::OnProtocolExecution(browser, url, allow_os_execution);
}
bool MainViewBrowserHandler::OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
bool user_gesture,
bool is_redirect)
{
CEF_REQUIRE_UI_THREAD();
if (Session::Instance().IsExpired()) // Return true to cancel the navigation if the session is already expired.
return true;
m_browser_msg_router->OnBeforeBrowse(browser, frame);
CefString url = request->GetURL(); // get URL requested
LPCTSTR url_(url.c_str()); // WARNNING:LPCTSTR url_( frame->GetURL().c_str()) will get an incorrect string, don't do this way!
HWND hWindow = GetParent(browser->GetHost()->GetWindowHandle()); // The frame window will be the parent of the browser window。
if (::SendMessage(hWindow, WM_CEF_BEFORE_BROWSE, (WPARAM)url_, (LPARAM)is_redirect) == S_FALSE)
{
// cancel navigation
return true;
}
SendStatusToMainWnd(browser, L"开始加载页面...");
return CefRequestHandler::OnBeforeBrowse(browser, frame, request, user_gesture, is_redirect); // call parent
}
bool MainViewBrowserHandler::OnCertificateError(CefRefPtr<CefBrowser> browser, cef_errorcode_t cert_error, const CefString& request_url, CefRefPtr<CefSSLInfo> ssl_info, CefRefPtr<CefRequestCallback> callback)
{
std::wstringstream text;
// no file, or empty, show the default
text << "The site's security certificate is not trusted!\n\n";
text << "You attempted to reach: " << request_url.c_str() << " \n";
text << "But the server presented a certificate issued by an entity that is not trusted by your computer's operating system.";
text << "This may mean that the server has generated its own security credentials, ";
text << "which Chrome cannot rely on for identity information, or an attacker may be ";
text << "trying to intercept your communications.\n\n";
text << "You should not proceed, especially if you have never seen this warning before for this site.";
if (MessageBox(NULL, text.str().c_str(), L"The site's security certificate is not trusted:", MB_YESNO) == IDNO)
return FALSE;
// continue
callback->Continue(true);
return TRUE;
}
CefRequestHandler::ReturnValue MainViewBrowserHandler::OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request, CefRefPtr<CefRequestCallback> callback)
{
// do defulat
return CefRequestHandler::OnBeforeResourceLoad(browser, frame, request, callback);
}
bool MainViewBrowserHandler::OnResourceResponse(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request, CefRefPtr<CefResponse> response)
{
CEF_REQUIRE_IO_THREAD();
const CefString kTimeoutHeader("sessionStatus");
const CefString kTimeout("expired");
auto& url = request->GetURL();
CefRequest::HeaderMap headerMap;
response->GetHeaderMap(headerMap);
if (0 == response->GetHeader(kTimeoutHeader).compare(kTimeout)) // If timeout.
{
if (!Session::Instance().IsExpired())// Avoid repeating post message to handle the session expired.
{
Session::Instance().OnExpired();
// AfxGetMainWnd() will return NULL if called from an other thread (has to do with thread local storage).
// That's why we use AfxGetApp()->GetMainWnd() instead of AfxGetMainWnd().
PostMessage(AfxGetApp()->GetMainWnd()->GetSafeHwnd(), WM_CEF_SESSION_EXPIRED, NULL, NULL); // Post message to CMainFrame to try re-login.
}
if (RT_XHR != request->GetResourceType()) // RT_XHR means "XMLHttpRequest", don't redirect request if it is "XMLHttpRequest".
{
request->Set("about:blank", "GET", nullptr, CefRequest::HeaderMap()); // Redirect the URL to trigger another "OnBeforeBrowse".
return true; // Return true to redirect.
}
}
return false;
}
void MainViewBrowserHandler::OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser, TerminationStatus status)
{
CEF_REQUIRE_UI_THREAD();
m_browser_msg_router->OnRenderProcessTerminated(browser);
return CefRequestHandler::OnRenderProcessTerminated(browser, status);
}
void MainViewBrowserHandler::OnPluginCrashed(CefRefPtr<CefBrowser> browser, const CefString& plugin_path)
{
return CefRequestHandler::OnPluginCrashed(browser, plugin_path);
}
//@}
//@{ CefJSDialogHandler methods
bool MainViewBrowserHandler::OnBeforeUnloadDialog(CefRefPtr<CefBrowser> browser, const CefString& message_text, bool is_reload, CefRefPtr<CefJSDialogCallback> callback)
{
// do defulat
return FALSE;
}
void MainViewBrowserHandler::OnDialogClosed(CefRefPtr<CefBrowser> browser)
{
}
void MainViewBrowserHandler::OnResetDialogState(CefRefPtr<CefBrowser> browser)
{
}
//@}
std::string MainViewBrowserHandler::GetDownloadPath(const std::string& file_name)
{
TCHAR szFolderPath[MAX_PATH];
std::string path;
// Save the file in the user's "My Documents" folder.
if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL | CSIDL_FLAG_CREATE,
NULL, 0, szFolderPath))) {
path = CefString(szFolderPath);
path += "\\" + file_name;
}
return path;
}
void MainViewBrowserHandler::SendStatusToMainWnd(CefRefPtr<CefBrowser> browser, const std::wstring& status)
{
if (!status.empty())
{
// The frame window will be the parent of the browser window
HWND hWindow = GetParent(browser->GetHost()->GetWindowHandle());
LPCTSTR status_(status.c_str());
::SendMessage(hWindow, WM_CEF_STATUS_MESSAGE, (WPARAM)status_, NULL);
}
}