Merge lp:~chrisccoulson/oxide/lp1504853 into lp:~oxide-developers/oxide/oxide.trunk

Proposed by Chris Coulson
Status: Merged
Merged at revision: 1232
Proposed branch: lp:~chrisccoulson/oxide/lp1504853
Merge into: lp:~oxide-developers/oxide/oxide.trunk
Diff against target: 2354 lines (+1100/-732)
22 files modified
qt/core/api/oxideqcertificateerror.cc (+3/-3)
qt/core/browser/oxide_qt_web_view.cc (+16/-9)
qt/core/browser/oxide_qt_web_view.h (+5/-1)
qt/tests/qmltests/ssl/tst_CertificateError.qml (+329/-217)
qt/tests/qmltests/ssl/tst_CertificateError_initial.html (+5/-0)
shared/browser/oxide_content_browser_client.cc (+21/-21)
shared/browser/oxide_web_frame_tree.cc (+6/-0)
shared/browser/oxide_web_view.cc (+28/-80)
shared/browser/oxide_web_view.h (+0/-26)
shared/browser/oxide_web_view_client.cc (+0/-2)
shared/browser/oxide_web_view_client.h (+0/-2)
shared/browser/oxide_web_view_contents_helper.cc (+7/-1)
shared/browser/ssl/oxide_certificate_error.cc (+50/-268)
shared/browser/ssl/oxide_certificate_error.h (+20/-100)
shared/browser/ssl/oxide_certificate_error_dispatcher.cc (+196/-0)
shared/browser/ssl/oxide_certificate_error_dispatcher.h (+77/-0)
shared/browser/ssl/oxide_certificate_error_dispatcher_client.h (+36/-0)
shared/browser/ssl/oxide_certificate_error_placeholder_page.cc (+58/-0)
shared/browser/ssl/oxide_certificate_error_placeholder_page.h (+64/-0)
shared/browser/ssl/oxide_certificate_error_proxy.cc (+105/-0)
shared/browser/ssl/oxide_certificate_error_proxy.h (+65/-0)
shared/shared.gyp (+9/-2)
To merge this branch: bzr merge lp:~chrisccoulson/oxide/lp1504853
Reviewer Review Type Date Requested Status
Chris Coulson Pending
Review via email: mp+274525@code.launchpad.net
To post a comment you must log in.
lp:~chrisccoulson/oxide/lp1504853 updated
1218. By Chris Coulson

Remove spurious printf

1219. By Chris Coulson

Add missing file

1220. By Chris Coulson

Add missing file

1221. By Chris Coulson

Merge from trunk

1222. By Chris Coulson

Merge from trunk

1223. By Chris Coulson

Merge from trunk

1224. By Chris Coulson

Remove unnecessary DCHECK

1225. By Chris Coulson

Fix a test crash

1226. By Chris Coulson

Merge from trunk

1227. By Chris Coulson

Merge from trunk

1228. By Chris Coulson

Clean up WebFrameTreeObserver

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'qt/core/api/oxideqcertificateerror.cc'
2--- qt/core/api/oxideqcertificateerror.cc 2015-07-02 15:53:48 +0000
3+++ qt/core/api/oxideqcertificateerror.cc 2015-10-21 20:26:37 +0000
4@@ -27,8 +27,8 @@
5 #include "base/macros.h"
6 #include "net/cert/x509_certificate.h"
7
8-#include "shared/browser/oxide_certificate_error.h"
9 #include "shared/browser/oxide_security_types.h"
10+#include "shared/browser/ssl/oxide_certificate_error.h"
11
12 #include "oxideqsslcertificate_p.h"
13
14@@ -58,7 +58,7 @@
15 return;
16 }
17
18- if (error_->is_cancelled()) {
19+ if (error_->IsCancelled()) {
20 qWarning() << "Cannot respond to a CertificateError that has been cancelled";
21 return;
22 }
23@@ -138,7 +138,7 @@
24 bool OxideQCertificateError::isCancelled() const {
25 Q_D(const OxideQCertificateError);
26
27- return d->error_->is_cancelled();
28+ return d->error_->IsCancelled();
29 }
30
31 bool OxideQCertificateError::isMainFrame() const {
32
33=== modified file 'qt/core/browser/oxide_qt_web_view.cc'
34--- qt/core/browser/oxide_qt_web_view.cc 2015-10-21 17:09:06 +0000
35+++ qt/core/browser/oxide_qt_web_view.cc 2015-10-21 20:26:37 +0000
36@@ -81,6 +81,8 @@
37 #include "shared/browser/oxide_web_view.h"
38 #include "shared/browser/permissions/oxide_permission_request.h"
39 #include "shared/browser/permissions/oxide_permission_request_dispatcher.h"
40+#include "shared/browser/ssl/oxide_certificate_error.h"
41+#include "shared/browser/ssl/oxide_certificate_error_dispatcher.h"
42 #include "shared/common/oxide_enum_flags.h"
43
44 #include "oxide_qt_file_picker.h"
45@@ -408,6 +410,8 @@
46 void WebView::CommonInit(OxideQFindController* find_controller) {
47 content::WebContents* contents = view_->GetWebContents();
48
49+ oxide::CertificateErrorDispatcher::FromWebContents(
50+ contents)->set_client(this);
51 oxide::PermissionRequestDispatcher::FromWebContents(
52 contents)->set_client(this);
53 OxideQSecurityStatusPrivate::get(security_status_)->view = this;
54@@ -854,14 +858,6 @@
55 OxideQSecurityStatusPrivate::get(security_status_)->Update(old);
56 }
57
58-void WebView::OnCertificateError(scoped_ptr<oxide::CertificateError> error) {
59- scoped_ptr<OxideQCertificateError> qerror(
60- OxideQCertificateErrorPrivate::Create(error.Pass()));
61-
62- // Embedder takes ownership of qerror
63- client_->CertificateError(qerror.release());
64-}
65-
66 void WebView::ContentBlocked() {
67 client_->ContentBlocked();
68 }
69@@ -952,6 +948,14 @@
70 f->client()->LoadCommitted();
71 }
72
73+void WebView::OnCertificateError(scoped_ptr<oxide::CertificateError> error) {
74+ scoped_ptr<OxideQCertificateError> qerror(
75+ OxideQCertificateErrorPrivate::Create(error.Pass()));
76+
77+ // Embedder takes ownership of qerror
78+ client_->CertificateError(qerror.release());
79+}
80+
81 QUrl WebView::url() const {
82 return QUrl(QString::fromStdString(view_->GetURL().spec()));
83 }
84@@ -1428,12 +1432,15 @@
85 }
86
87 WebView::~WebView() {
88+ content::WebContents* contents = view_->GetWebContents();
89+ oxide::CertificateErrorDispatcher::FromWebContents(
90+ contents)->set_client(nullptr);
91 DCHECK(frame_tree_torn_down_);
92
93 input_method_context_->DetachClient();
94
95 oxide::PermissionRequestDispatcher::FromWebContents(
96- view_->GetWebContents())->set_client(nullptr);
97+ contents)->set_client(nullptr);
98 }
99
100 // static
101
102=== modified file 'qt/core/browser/oxide_qt_web_view.h'
103--- qt/core/browser/oxide_qt_web_view.h 2015-10-21 16:44:08 +0000
104+++ qt/core/browser/oxide_qt_web_view.h 2015-10-21 20:26:37 +0000
105@@ -34,6 +34,7 @@
106 #include "shared/browser/oxide_web_view_client.h"
107 #include "shared/browser/oxide_web_frame_tree_observer.h"
108 #include "shared/browser/permissions/oxide_permission_request_dispatcher_client.h"
109+#include "shared/browser/ssl/oxide_certificate_error_dispatcher_client.h"
110
111 QT_BEGIN_NAMESPACE
112 class QFocusEvent;
113@@ -61,6 +62,7 @@
114 public oxide::WebViewClient,
115 public oxide::PermissionRequestDispatcherClient,
116 public oxide::WebFrameTreeObserver,
117+ public oxide::CertificateErrorDispatcherClient,
118 public WebViewProxy {
119 public:
120 WebView(WebViewProxyClient* client,
121@@ -166,7 +168,6 @@
122 oxide::InputMethodContext* GetInputMethodContext() const override;
123 void UpdateCursor(const content::WebCursor& cursor) override;
124 void SecurityStatusChanged(const oxide::SecurityStatus& old) override;
125- void OnCertificateError(scoped_ptr<oxide::CertificateError> error) override;
126 void ContentBlocked() override;
127 void PrepareToCloseResponseReceived(bool proceed) override;
128 void CloseRequested() override;
129@@ -189,6 +190,9 @@
130 void FrameDeleted(oxide::WebFrame* frame) override;
131 void LoadCommittedInFrame(oxide::WebFrame* frame) override;
132
133+ // oxide::CertificateErrorDispatcherClient implementation
134+ void OnCertificateError(scoped_ptr<oxide::CertificateError> error) override;
135+
136 // WebViewProxy implementation
137 QUrl url() const override;
138 void setUrl(const QUrl& url) override;
139
140=== modified file 'qt/tests/qmltests/ssl/tst_CertificateError.qml'
141--- qt/tests/qmltests/ssl/tst_CertificateError.qml 2015-06-22 22:57:01 +0000
142+++ qt/tests/qmltests/ssl/tst_CertificateError.qml 2015-10-21 20:26:37 +0000
143@@ -19,11 +19,22 @@
144 signalName: "cancelled"
145 }
146
147+ SignalSpy {
148+ id: urlSpy
149+ target: webView
150+ signalName: "urlChanged"
151+ }
152+
153+ SignalSpy {
154+ id: titleSpy
155+ target: webView
156+ signalName: "titleChanged"
157+ }
158+
159 property var certError: null
160
161 onCertificateError: {
162 if (certError) {
163- error.allow();
164 return;
165 }
166 certError = error;
167@@ -38,23 +49,16 @@
168 spy.clear();
169 cancelSpy.target = null;
170 cancelSpy.clear();
171+ urlSpy.clear();
172+ titleSpy.clear();
173 certError = null;
174 webView.clearLoadEventCounters();
175 }
176
177- function test_CertificateError1_denials_data() {
178+ function test_CertificateError1_subresource_deny_data() {
179 function _verify_1() {
180 // This verifies that either there is no document or it is an error page
181 try {
182- compare(webView.getTestApi().documentURI, "data:text/html,chromewebdata");
183- } catch(e) {
184- compare(e.error, ScriptMessageRequest.ErrorDestinationNotFound);
185- }
186- }
187-
188- function _verify_2() {
189- // This verifies that either there is no document or it is an error page
190- try {
191 compare(webView.getTestApiForFrame(webView.rootFrame.childFrames[0]).documentURI,
192 "data:text/html,chromewebdata");
193 } catch(e) {
194@@ -62,15 +66,15 @@
195 }
196 }
197
198+ function _verify_2() {
199+ var colour = webView.getTestApi().evaluateCode("
200+var elem = document.getElementById(\"foo\");
201+var style = window.getComputedStyle(elem);
202+return style.getPropertyValue(\"color\");", true);
203+ compare(colour, "rgb(0, 0, 0)");
204+ }
205+
206 function _verify_3() {
207- var colour = webView.getTestApi().evaluateCode("
208-var elem = document.getElementById(\"foo\");
209-var style = window.getComputedStyle(elem);
210-return style.getPropertyValue(\"color\");", true);
211- compare(colour, "rgb(0, 0, 0)");
212- }
213-
214- function _verify_4() {
215 var colour = webView.getTestApiForFrame(webView.rootFrame.childFrames[0]).evaluateCode("
216 var elem = document.getElementById(\"foo\");
217 var style = window.getComputedStyle(elem);
218@@ -81,234 +85,342 @@
219 // FIXME: Test overridable and strictEnforcement properties
220 return [
221 {
222- loadUrl: "https://expired.testsuite/tst_CertificateError_broken_iframe.html",
223- url: "https://expired.testsuite/tst_CertificateError_broken_iframe.html",
224- mainframe: true, subresource: false, overridable: true,
225- strictEnforcement: false, error: CertificateError.ErrorExpired,
226- certificate: "df17c8da033e2d5ed64d1f187fdf419e1fc68e47",
227- verifyFunc: _verify_1
228- },
229- {
230 loadUrl: "https://testsuite/tst_CertificateError_broken_iframe.html",
231 url: "https://selfsigned.testsuite/empty.html",
232- mainframe: false, subresource: false, overridable: false,
233+ mainframe: false, subresource: false,
234 strictEnforcement: false, error: CertificateError.ErrorAuthorityInvalid,
235 certificate: "f0357f544e27adaa51211663a28cc8d64b057e63",
236+ verifyFunc: _verify_1
237+ },
238+ {
239+ loadUrl: "https://testsuite/tst_CertificateError_broken_subresource.html",
240+ url: "https://badidentity.testsuite/tst_CertificateError_broken_subresource.css",
241+ mainframe: true, subresource: true,
242+ strictEnforcement: false, error: CertificateError.ErrorBadIdentity,
243+ certificate: "89c5760286e897ad32b9dd500d70755e1e026588",
244 verifyFunc: _verify_2
245 },
246 {
247- loadUrl: "https://testsuite/tst_CertificateError_broken_subresource.html",
248+ loadUrl: "https://testsuite/tst_CertificateError_broken_subresource_in_iframe.html",
249 url: "https://badidentity.testsuite/tst_CertificateError_broken_subresource.css",
250- mainframe: true, subresource: true, overridable: false,
251+ mainframe: false, subresource: true,
252 strictEnforcement: false, error: CertificateError.ErrorBadIdentity,
253 certificate: "89c5760286e897ad32b9dd500d70755e1e026588",
254 verifyFunc: _verify_3
255- },
256- {
257- loadUrl: "https://testsuite/tst_CertificateError_broken_subresource_in_iframe.html",
258- url: "https://badidentity.testsuite/tst_CertificateError_broken_subresource.css",
259- mainframe: false, subresource: true, overridable: false,
260- strictEnforcement: false, error: CertificateError.ErrorBadIdentity,
261- certificate: "89c5760286e897ad32b9dd500d70755e1e026588",
262- verifyFunc: _verify_4
263 }
264 ];
265 }
266
267- // Verify that CertificateError.deny() works correctly, and check that other
268- // properties behave as expected
269- function test_CertificateError1_denials(data) {
270+ // This tests CertificateError for various subresource errors, and verifies
271+ // that those subresources are always blocked
272+ function test_CertificateError1_subresource_deny(data) {
273 webView.url = data.loadUrl;
274+ verify(webView.waitForLoadSucceeded());
275+
276 spy.wait();
277
278+ if (!data.mainframe) {
279+ // This is a bit of a hack, but we don't have another event we can
280+ // fire off for subframe loads
281+ wait(100);
282+ }
283+
284 compare(certError.url, data.url);
285 verify(!certError.isCancelled);
286 compare(certError.isMainFrame, data.mainframe);
287 compare(certError.isSubresource, data.subresource);
288+ compare(certError.overridable, false);
289+ compare(certError.strictEnforcement, data.strictEnforcement);
290+ compare(certError.certError, data.error);
291+ compare(certError.certificate.fingerprintSHA1, data.certificate);
292+
293+ compare(webView.url, data.loadUrl);
294+
295+ compare(webView.securityStatus.securityLevel,SecurityStatus.SecurityLevelSecure);
296+ compare(webView.securityStatus.contentStatus, SecurityStatus.ContentStatusNormal);
297+ compare(webView.securityStatus.certStatus, SecurityStatus.CertStatusOk);
298+
299+ data.verifyFunc();
300+
301+ // There's nothing to deny, but it shouldn't crash
302+ certError.deny();
303+ }
304+
305+ function test_CertificateError2_mainframe_deny_data() {
306+ function _verify_1() {
307+ // This verifies that the old document still exists
308+ compare(webView.getTestApi().documentURI, "https://testsuite/tst_CertificateError_initial.html");
309+ }
310+
311+ // FIXME: Test non-overridable errors too
312+ return [
313+ {
314+ loadUrl: "https://expired.testsuite/empty.html",
315+ overridable: true,
316+ strictEnforcement: false, error: CertificateError.ErrorExpired,
317+ certificate: "df17c8da033e2d5ed64d1f187fdf419e1fc68e47",
318+ verifyFunc: _verify_1
319+ },
320+ ];
321+
322+ }
323+
324+ // This test CertificateError for main frame errors, and verifies that
325+ // calling deny() blocks them
326+ function test_CertificateError2_mainframe_deny(data) {
327+ webView.url = "https://testsuite/tst_CertificateError_initial.html";
328+ verify(webView.waitForLoadSucceeded());
329+
330+ compare(webView.title, "Test");
331+
332+ webView.clearLoadEventCounters();
333+ titleSpy.clear();
334+
335+ webView.url = data.loadUrl;
336+ spy.wait();
337+ titleSpy.wait();
338+ if (!data.overridable) {
339+ verify(webView.waitForLoadStopped());
340+ }
341+
342+ compare(certError.url, data.loadUrl);
343+ verify(!certError.isCancelled);
344+ compare(certError.isMainFrame, true);
345+ compare(certError.isSubresource, false);
346 compare(certError.overridable, data.overridable);
347 compare(certError.strictEnforcement, data.strictEnforcement);
348 compare(certError.certError, data.error);
349 compare(certError.certificate.fingerprintSHA1, data.certificate);
350
351+ compare(webView.loadsStartedCount, 1);
352+ compare(webView.loadsCommittedCount, 0);
353+ compare(webView.loadsFailedCount, 0);
354+ compare(webView.loadsSucceededCount, 0);
355+
356+ // WebView.url should indicate the URL of the failing resource even for
357+ // non-overridable errors, as we show a placeholder transient page
358+ compare(webView.url, data.loadUrl);
359+ compare(webView.title, data.loadUrl);
360+
361+ data.verifyFunc();
362+
363+ urlSpy.clear();
364+ titleSpy.clear();
365+
366 certError.deny();
367
368- if (data.mainframe && !data.subresource) {
369- verify(webView.waitForLoadStopped());
370- compare(webView.loadsFailedCount, 0);
371- compare(webView.loadsStoppedCount, 1);
372- compare(webView.loadsSucceededCount, 0);
373- } else {
374+ if (data.overridable) {
375+ verify(webView.waitForLoadStopped());
376+ }
377+ urlSpy.wait();
378+ titleSpy.wait();
379+
380+ compare(webView.url, "https://testsuite/tst_CertificateError_initial.html");
381+ compare(webView.title, "Test");
382+
383+ data.verifyFunc();
384+ }
385+
386+ function test_CertificateError3_subresource_allow_data() {
387+ function _verify_1() {
388+ // This verifies that either there is no document or it is an error page
389+ try {
390+ compare(webView.getTestApiForFrame(webView.rootFrame.childFrames[0]).documentURI,
391+ "data:text/html,chromewebdata");
392+ } catch(e) {
393+ compare(e.error, ScriptMessageRequest.ErrorDestinationNotFound);
394+ }
395+ }
396+
397+ function _verify_2() {
398+ var colour = webView.getTestApi().evaluateCode("
399+var elem = document.getElementById(\"foo\");
400+var style = window.getComputedStyle(elem);
401+return style.getPropertyValue(\"color\");", true);
402+ compare(colour, "rgb(0, 0, 0)");
403+ }
404+
405+ function _verify_3() {
406+ var colour = webView.getTestApiForFrame(webView.rootFrame.childFrames[0]).evaluateCode("
407+var elem = document.getElementById(\"foo\");
408+var style = window.getComputedStyle(elem);
409+return style.getPropertyValue(\"color\");", true);
410+ compare(colour, "rgb(0, 0, 0)");
411+ }
412+
413+ return [
414+ {
415+ loadUrl: "https://testsuite/tst_CertificateError_broken_iframe.html",
416+ verifyFunc: _verify_1
417+ },
418+ {
419+ loadUrl: "https://testsuite/tst_CertificateError_broken_subresource.html",
420+ verifyFunc: _verify_2
421+ },
422+ {
423+ loadUrl: "https://testsuite/tst_CertificateError_broken_subresource_in_iframe.html",
424+ verifyFunc: _verify_3
425+ }
426+ ];
427+ }
428+
429+ // Verifies that calling allow() on subresource errors cannot override
430+ // them
431+ function test_CertificateError3_subresource_allow(data) {
432+ webView.url = data.loadUrl;
433+ verify(webView.waitForLoadSucceeded());
434+
435+ spy.wait();
436+
437+ certError.allow();
438+
439+ // This is a bit of a hack, but we don't have another event we can fire off
440+ wait(100);
441+
442+ data.verifyFunc();
443+ }
444+
445+ function test_CertificateError4_mainframe_allow_data() {
446+ function _verify_1() {
447+ compare(webView.getTestApi().documentURI, "https://expired.testsuite/empty.html");
448+ }
449+
450+ // FIXME: Test non-overridable errors too
451+ return [
452+ {
453+ loadUrl: "https://expired.testsuite/empty.html",
454+ overridable: true, verifyFunc: _verify_1
455+ },
456+ ];
457+ }
458+
459+ // Verifies that calling allow() on overridable main frame errors allows
460+ // the page to continue loading
461+ function test_CertificateError4_mainframe_allow(data) {
462+ webView.url = "https://testsuite/tst_CertificateError_initial.html";
463+ verify(webView.waitForLoadSucceeded());
464+
465+ webView.clearLoadEventCounters();
466+
467+ webView.url = data.loadUrl;
468+ spy.wait();
469+ if (!data.overridable) {
470+ verify(webView.waitForLoadStopped());
471+ }
472+
473+ compare(webView.loadsStartedCount, 1);
474+ compare(webView.loadsCommittedCount, 0);
475+ compare(webView.loadsFailedCount, 0);
476+ compare(webView.loadsSucceededCount, 0);
477+
478+ certError.allow();
479+
480+ if (data.overridable) {
481 verify(webView.waitForLoadSucceeded());
482- if (!data.mainframe) {
483- // This is a bit of a hack, but we don't have another event we can
484- // fire off for subframe loads
485- wait(100);
486- }
487- }
488-
489- compare(webView.securityStatus.securityLevel,
490- data.mainframe && !data.subresource ?
491- SecurityStatus.SecurityLevelNone : SecurityStatus.SecurityLevelSecure);
492- compare(webView.securityStatus.contentStatus, SecurityStatus.ContentStatusNormal);
493- compare(webView.securityStatus.certStatus, SecurityStatus.CertStatusOk);
494-
495- data.verifyFunc();
496- }
497-
498- function test_CertificateError2_allow_data() {
499- function _verify_1() {
500- compare(webView.getTestApi().documentURI, "https://expired.testsuite/tst_CertificateError_broken_iframe.html");
501- }
502-
503- function _verify_2() {
504- // This verifies that either there is no document or it is an error page
505- try {
506- compare(webView.getTestApiForFrame(webView.rootFrame.childFrames[0]).documentURI,
507- "data:text/html,chromewebdata");
508- } catch(e) {
509- compare(e.error, ScriptMessageRequest.ErrorDestinationNotFound);
510- }
511- }
512-
513- function _verify_3() {
514- var colour = webView.getTestApi().evaluateCode("
515-var elem = document.getElementById(\"foo\");
516-var style = window.getComputedStyle(elem);
517-return style.getPropertyValue(\"color\");", true);
518- compare(colour, "rgb(0, 0, 0)");
519- }
520-
521- function _verify_4() {
522- var colour = webView.getTestApiForFrame(webView.rootFrame.childFrames[0]).evaluateCode("
523-var elem = document.getElementById(\"foo\");
524-var style = window.getComputedStyle(elem);
525-return style.getPropertyValue(\"color\");", true);
526- compare(colour, "rgb(0, 0, 0)");
527- }
528-
529- return [
530- {
531- loadUrl: "https://expired.testsuite/tst_CertificateError_broken_iframe.html",
532- mainframe: true, overridable: true, verifyFunc: _verify_1
533- },
534- {
535- loadUrl: "https://testsuite/tst_CertificateError_broken_iframe.html",
536- mainframe: false, overridable: false, verifyFunc: _verify_2
537- },
538- {
539- loadUrl: "https://testsuite/tst_CertificateError_broken_subresource.html",
540- mainframe: false, overridable: false, verifyFunc: _verify_3
541- },
542- {
543- loadUrl: "https://testsuite/tst_CertificateError_broken_subresource_in_iframe.html",
544- mainframe: false, overridable: false, verifyFunc: _verify_4
545- }
546- ];
547- }
548-
549- // Verify that CertificateError.allow works correctly for overridable errors
550- function test_CertificateError2_allow(data) {
551- webView.url = data.loadUrl;
552- spy.wait();
553-
554- certError.allow();
555-
556- verify(webView.waitForLoadSucceeded());
557-
558- if (data.mainframe) {
559- compare(webView.loadsFailedCount, 0);
560- compare(webView.loadsStoppedCount, 0);
561- compare(webView.loadsSucceededCount, 1);
562- } else {
563- // This is a bit of a hack, but we don't have another event we can fire off
564- wait(100);
565- }
566-
567- data.verifyFunc();
568- }
569-
570- function test_CertificateError3_cancellation_data() {
571- // Test that starting a new load cancels pending frame errors
572- function _action_1() {
573- webView.url = "http://testsuite/empty.html";
574- verify(webView.waitForLoadStarted());
575- }
576-
577- // Test that stopping a load cancels pending frame errors
578- function _action_2() {
579- webView.stop();
580- verify(webView.waitForLoadStopped());
581- }
582-
583- // Test that committing a load cancels non-overridable frame errors
584- function _action_3() {
585- var frame = webView.rootFrame.childFrames[0];
586- webView.getTestApiForFrame(frame).evaluateCode(
587- "window.location = \"https://testsuite/empty.html\";",
588- true);
589- TestUtils.waitFor(function() { return frame.url == "https://testsuite/empty.html" });
590- }
591-
592- // Test that deleting a frame cancels errors
593- function _action_4() {
594- var frame = webView.rootFrame.childFrames[0];
595- var obs = Utils.createDestructionObserver(frame);
596- webView.getTestApi().evaluateCode("
597-var f = document.getElementsByTagName(\"iframe\")[0];
598-f.parentElement.removeChild(f);", true);
599- TestUtils.waitFor(function() { return obs.destroyed; });
600- }
601-
602- // Test that interrupting a load before it's committed doesn't cancel
603- // subresource errors
604- function _action_5() {
605- var savedError = certError;
606- certError = null;
607-
608- webView.url = "https://expired.testsuite/empty.html";
609- spy.wait();
610- webView.stop();
611- verify(webView.waitForLoadStopped());
612-
613- certError = savedError;
614- }
615-
616- // Test that committing a load cancels subresource errors
617- function _action_6() {
618- webView.url = "https://testsuite/empty.html";
619- verify(webView.waitForLoadCommitted());
620- }
621-
622- return [
623- { url: "https://expired.testsuite/tst_CertificateError_broken_iframe.html",
624- action: _action_1, expectCancel: true },
625- { url: "https://expired.testsuite/tst_CertificateError_broken_iframe.html",
626- action: _action_2, expectCancel: true },
627- { url: "https://testsuite/tst_CertificateError_broken_iframe.html",
628- action: _action_3, expectCancel: true },
629- { url: "https://testsuite/tst_CertificateError_broken_iframe.html",
630- action: _action_4, expectCancel: true },
631- { url: "https://testsuite/tst_CertificateError_broken_subresource.html",
632- action: _action_5, expectCancel: false },
633- { url: "https://testsuite/tst_CertificateError_broken_subresource.html",
634- action: _action_6, expectCancel: true }
635- ];
636- }
637-
638- // Verify that CertificateError cancellation works as expected
639- function test_CertificateError3_cancellation(data) {
640- webView.url = data.url;
641- spy.wait();
642-
643- verify(!certError.isCancelled);
644-
645- cancelSpy.target = certError;
646-
647- webView.clearLoadEventCounters();
648- data.action();
649-
650- compare(certError.isCancelled, data.expectCancel);
651- compare(cancelSpy.count, data.expectCancel ? 1 : 0);
652+ }
653+
654+ data.verifyFunc();
655+ }
656+
657+ function test_CertificateError5_cancellation_browser_initiated_navigation_data() {
658+ // Test non-overridable too
659+ return [
660+ { loadUrl: "https://badidentity.testsuite/empty.html", overridable: true }
661+ ];
662+ }
663+
664+ // Verify that main frame errors are cancelled on a browser-initiated navigation
665+ function test_CertificateError5_cancellation_browser_initiated_navigation(data) {
666+ webView.url = "https://testsuite/empty.html";
667+ verify(webView.waitForLoadSucceeded());
668+
669+ webView.url = data.loadUrl;
670+ spy.wait();
671+ if (!data.overridable) {
672+ verify(webView.waitForLoadStopped());
673+ }
674+
675+ cancelSpy.target = certError;
676+ verify(!certError.isCancelled);
677+
678+ webView.clearLoadEventCounters();
679+
680+ webView.url = "https://foo.testsuite/empty.html";
681+ verify(webView.waitForLoadCommitted());
682+
683+ compare(cancelSpy.count, 1);
684+ verify(certError.isCancelled);
685+
686+ verify(webView.waitForLoadSucceeded());
687+ compare(webView.url, "https://foo.testsuite/empty.html");
688+ }
689+
690+ function test_CertificateError6_cancellation_history_navigation_data() {
691+ return test_CertificateError5_cancellation_browser_initiated_navigation_data();
692+ }
693+
694+ function test_CertificateError6_cancellation_history_navigation(data) {
695+ webView.url = "https://testsuite/empty.html";
696+ verify(webView.waitForLoadSucceeded());
697+
698+ webView.url = data.loadUrl;
699+ spy.wait();
700+ if (!data.overridable) {
701+ verify(webView.waitForLoadStopped());
702+ }
703+
704+ cancelSpy.target = certError;
705+ verify(!certError.isCancelled);
706+
707+ urlSpy.clear();
708+
709+ // FIXME(chrisccoulson): The test fails without the delay - cancellation
710+ // never happens. I suspect this is because we go back before getting
711+ // the commit from the renderer, which means that the interstitial is
712+ // not attached to the WebContents and DontProceed doesn't get called
713+ wait(100);
714+
715+ webView.goBack();
716+ // There's no new load here, so just wait for the URL to change back
717+ urlSpy.wait();
718+ cancelSpy.wait();
719+
720+ compare(cancelSpy.count, 1);
721+ verify(certError.isCancelled);
722+ compare(webView.url, "https://testsuite/empty.html");
723+ }
724+
725+ function test_CertificateError7_content_initiated_navigation_data() {
726+ return test_CertificateError5_cancellation_browser_initiated_navigation_data();
727+ }
728+
729+ function test_CertificateError7_content_initiated_navigation(data) {
730+ webView.url = "https://testsuite/tst_CertificateError_initial.html";
731+ verify(webView.waitForLoadSucceeded());
732+
733+ urlSpy.clear();
734+ titleSpy.clear();
735+ webView.clearLoadEventCounters();
736+
737+ webView.getTestApi().evaluateCode("window.location = \"" + data.loadUrl + "\";");
738+ spy.wait();
739+ urlSpy.wait();
740+ titleSpy.wait();
741+ if (!data.overridable) {
742+ verify(webView.waitForLoadStopped());
743+ }
744+
745+ compare(webView.loadsStartedCount, 1);
746+ compare(webView.loadsCommittedCount, 0);
747+ compare(webView.loadsFailedCount, 0);
748+ compare(webView.loadsSucceededCount, 0);
749+
750+ compare(webView.url, data.loadUrl);
751+ compare(webView.loadsStartedCount, 1);
752+ compare(webView.loadsCommittedCount, 0);
753+ compare(webView.loadsFailedCount, 0);
754+ compare(webView.loadsSucceededCount, 0);
755+ compare(webView.title, data.loadUrl);
756 }
757 }
758 }
759
760=== added file 'qt/tests/qmltests/ssl/tst_CertificateError_initial.html'
761--- qt/tests/qmltests/ssl/tst_CertificateError_initial.html 1970-01-01 00:00:00 +0000
762+++ qt/tests/qmltests/ssl/tst_CertificateError_initial.html 2015-10-21 20:26:37 +0000
763@@ -0,0 +1,5 @@
764+<html>
765+<head>
766+ <title>Test</title>
767+</head>
768+</html>
769
770=== modified file 'shared/browser/oxide_content_browser_client.cc'
771--- shared/browser/oxide_content_browser_client.cc 2015-10-07 01:36:57 +0000
772+++ shared/browser/oxide_content_browser_client.cc 2015-10-21 20:26:37 +0000
773@@ -36,6 +36,7 @@
774 #include "shared/browser/compositor/oxide_compositor_utils.h"
775 #include "shared/browser/media/oxide_media_capture_devices_dispatcher.h"
776 #include "shared/browser/notifications/oxide_platform_notification_service.h"
777+#include "shared/browser/ssl/oxide_certificate_error_dispatcher.h"
778 #include "shared/common/oxide_constants.h"
779 #include "shared/common/oxide_content_client.h"
780 #include "shared/common/oxide_form_factor.h"
781@@ -169,25 +170,16 @@
782 bool expired_previous_decision,
783 const base::Callback<void(bool)>& callback,
784 content::CertificateRequestResultType* result) {
785- DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
786-
787- content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(
788- render_process_id, render_frame_id);
789- if (!rfh) {
790- *result = content::CERTIFICATE_REQUEST_RESULT_TYPE_CANCEL;
791- return;
792- }
793-
794- WebView* webview = WebView::FromRenderFrameHost(rfh);
795- if (!webview) {
796- *result = content::CERTIFICATE_REQUEST_RESULT_TYPE_CANCEL;
797- return;
798- }
799-
800- webview->AllowCertificateError(rfh, cert_error, ssl_info, request_url,
801- resource_type, overridable,
802- strict_enforcement, callback,
803- result);
804+ CertificateErrorDispatcher::AllowCertificateError(render_process_id,
805+ render_frame_id,
806+ cert_error,
807+ ssl_info,
808+ request_url,
809+ resource_type,
810+ overridable,
811+ strict_enforcement,
812+ callback,
813+ result);
814 }
815
816 content::MediaObserver* ContentBrowserClient::GetMediaObserver() {
817@@ -241,7 +233,13 @@
818 WebViewContentsHelper* contents_helper =
819 WebViewContentsHelper::FromRenderViewHost(render_view_host);
820
821- WebPreferences* web_prefs = contents_helper->GetWebPreferences();
822+ WebPreferences* web_prefs = nullptr;
823+ if (contents_helper) {
824+ // If RVH is for an InterstitialPage, we can't map to WebContents
825+ // XXX: If we ever expose transient pages in the public API, we should find
826+ // a way around this, so that transient pages get the same preferences
827+ web_prefs = contents_helper->GetWebPreferences();
828+ }
829 if (!web_prefs) {
830 web_prefs = WebPreferences::GetFallback();
831 }
832@@ -253,7 +251,9 @@
833 prefs->device_supports_touch = platform_integration_->IsTouchSupported();
834
835 prefs->javascript_can_open_windows_automatically =
836- !contents_helper->GetBrowserContext()->IsPopupBlockerEnabled();
837+ !BrowserContext::FromContent(
838+ render_view_host->GetProcess()->GetBrowserContext())
839+ ->IsPopupBlockerEnabled();
840
841 FormFactor form_factor = GetFormFactorHint();
842 if (form_factor == FORM_FACTOR_TABLET || form_factor == FORM_FACTOR_PHONE) {
843
844=== modified file 'shared/browser/oxide_web_frame_tree.cc'
845--- shared/browser/oxide_web_frame_tree.cc 2015-10-16 21:36:30 +0000
846+++ shared/browser/oxide_web_frame_tree.cc 2015-10-21 20:26:37 +0000
847@@ -83,6 +83,12 @@
848 return;
849 }
850
851+ if (!content::WebContents::FromRenderFrameHost(old_host)) {
852+ // This is from an interstitial
853+ // XXX(chrisccoulson): Is there a better way to detect this?
854+ return;
855+ }
856+
857 WebFrame* frame = WebFrame::FromRenderFrameHost(old_host);
858 DCHECK(frame);
859
860
861=== modified file 'shared/browser/oxide_web_view.cc'
862--- shared/browser/oxide_web_view.cc 2015-10-21 20:14:13 +0000
863+++ shared/browser/oxide_web_view.cc 2015-10-21 20:26:37 +0000
864@@ -75,6 +75,7 @@
865 #include "shared/browser/media/oxide_media_capture_devices_dispatcher.h"
866 #include "shared/browser/permissions/oxide_permission_request_dispatcher.h"
867 #include "shared/browser/permissions/oxide_temporary_saved_permission_context.h"
868+#include "shared/browser/ssl/oxide_certificate_error_dispatcher.h"
869 #include "shared/common/oxide_content_client.h"
870 #include "shared/common/oxide_enum_flags.h"
871 #include "shared/common/oxide_messages.h"
872@@ -137,6 +138,7 @@
873 void CreateHelpers(content::WebContents* contents,
874 content::WebContents* opener = nullptr) {
875 new WebViewContentsHelper(contents, opener);
876+ CertificateErrorDispatcher::CreateForWebContents(contents);
877 PermissionRequestDispatcher::CreateForWebContents(contents);
878 ScriptMessageContentsHelper::CreateForWebContents(contents);
879 #if defined(ENABLE_MEDIAHUB)
880@@ -850,22 +852,6 @@
881 return status == TEMPORARY_SAVED_PERMISSION_STATUS_ALLOWED;
882 }
883
884-void WebView::RenderFrameDeleted(content::RenderFrameHost* render_frame_host) {
885- // XXX(chrisccoulson): Make CertificateErrorManager a WebContentsObserver so
886- // that we can get rid of this
887- certificate_error_manager_.FrameDetached(render_frame_host);
888-}
889-
890-void WebView::RenderFrameHostChanged(content::RenderFrameHost* old_host,
891- content::RenderFrameHost* new_host) {
892- // XXX(chrisccoulson): Make CertificateErrorManager a WebContentsObserver so
893- // that we can get rid of this
894- if (!old_host) {
895- return;
896- }
897- certificate_error_manager_.FrameDetached(old_host);
898-}
899-
900 void WebView::RenderViewReady() {
901 client_->CrashedStatusChanged();
902 }
903@@ -951,14 +937,11 @@
904 return;
905 }
906
907- if (!render_frame_host->GetParent()) {
908- client_->LoadStarted(validated_url);
909+ if (render_frame_host->GetParent()) {
910+ return;
911 }
912
913- // XXX(chrisccoulson): Make CertificateErrorManager a WebContentsObserver so
914- // that we can get rid of this
915- certificate_error_manager_.DidStartProvisionalLoadForFrame(
916- render_frame_host);
917+ client_->LoadStarted(validated_url);
918 }
919
920 void WebView::DidCommitProvisionalLoadForFrame(
921@@ -982,18 +965,15 @@
922 int error_code,
923 const base::string16& error_description,
924 bool was_ignored_by_handler) {
925- if (!render_frame_host->GetParent() &&
926- validated_url.spec() != content::kUnreachableWebDataURL) {
927- DispatchLoadFailed(validated_url, error_code, error_description, true);
928- }
929-
930- if (error_code != net::ERR_ABORTED) {
931- return;
932- }
933-
934- // XXX(chrisccoulson): Make CertificateErrorManager a WebContentsObserverso
935- // that we can get rid of this
936- certificate_error_manager_.DidStopProvisionalLoadForFrame(render_frame_host);
937+ if (render_frame_host->GetParent()) {
938+ return;
939+ }
940+
941+ if (validated_url.spec() == content::kUnreachableWebDataURL) {
942+ return;
943+ }
944+
945+ DispatchLoadFailed(validated_url, error_code, error_description, true);
946 }
947
948 void WebView::DidNavigateMainFrame(
949@@ -1010,18 +990,6 @@
950 }
951 }
952
953-void WebView::DidNavigateAnyFrame(
954- content::RenderFrameHost* render_frame_host,
955- const content::LoadCommittedDetails& details,
956- const content::FrameNavigateParams& params) {
957- // XXX(chrisccoulson): Make CertificateErrorManager a WebContentsObserver
958- if (details.is_in_page) {
959- return;
960- }
961-
962- certificate_error_manager_.DidNavigateFrame(render_frame_host);
963-}
964-
965 void WebView::DidGetRedirectForResourceRequest(
966 content::RenderFrameHost* render_frame_host,
967 const content::ResourceRedirectDetails& details) {
968@@ -1205,12 +1173,24 @@
969
970 // static
971 WebView* WebView::FromRenderViewHost(content::RenderViewHost* rvh) {
972- return FromWebContents(content::WebContents::FromRenderViewHost(rvh));
973+ content::WebContents* contents =
974+ content::WebContents::FromRenderViewHost(rvh);
975+ if (!contents) {
976+ return nullptr;
977+ }
978+
979+ return FromWebContents(contents);
980 }
981
982 // static
983 WebView* WebView::FromRenderFrameHost(content::RenderFrameHost* rfh) {
984- return FromWebContents(content::WebContents::FromRenderFrameHost(rfh));
985+ content::WebContents* contents =
986+ content::WebContents::FromRenderFrameHost(rfh);
987+ if (!contents) {
988+ return nullptr;
989+ }
990+
991+ return FromWebContents(contents);
992 }
993
994 const GURL& WebView::GetURL() const {
995@@ -1663,38 +1643,6 @@
996 web_contents_->DispatchBeforeUnload(false);
997 }
998
999-void WebView::AllowCertificateError(
1000- content::RenderFrameHost* rfh,
1001- int cert_error,
1002- const net::SSLInfo& ssl_info,
1003- const GURL& request_url,
1004- content::ResourceType resource_type,
1005- bool overridable,
1006- bool strict_enforcement,
1007- const base::Callback<void(bool)>& callback,
1008- content::CertificateRequestResultType* result) {
1009- // We can't safely allow the embedder to override errors for subresources or
1010- // subframes because they don't always result in the API indicating a
1011- // degraded security level. Mark these non-overridable for now and just
1012- // deny them outright
1013- // See https://launchpad.net/bugs/1368385
1014- if (!overridable || resource_type != content::RESOURCE_TYPE_MAIN_FRAME) {
1015- overridable = false;
1016- *result = content::CERTIFICATE_REQUEST_RESULT_TYPE_DENY;
1017- }
1018-
1019- scoped_ptr<CertificateError> error(new CertificateError(
1020- &certificate_error_manager_,
1021- rfh,
1022- cert_error,
1023- ssl_info,
1024- request_url,
1025- resource_type,
1026- strict_enforcement,
1027- overridable ? callback : base::Callback<void(bool)>()));
1028- client_->OnCertificateError(error.Pass());
1029-}
1030-
1031 void WebView::HandleKeyEvent(const content::NativeWebKeyboardEvent& event) {
1032 content::RenderViewHost* rvh = GetRenderViewHost();
1033 if (!rvh) {
1034
1035=== modified file 'shared/browser/oxide_web_view.h'
1036--- shared/browser/oxide_web_view.h 2015-10-21 20:14:13 +0000
1037+++ shared/browser/oxide_web_view.h 2015-10-21 20:26:37 +0000
1038@@ -29,14 +29,12 @@
1039 #include "base/strings/string16.h"
1040 #include "cc/output/compositor_frame_metadata.h"
1041 #include "components/sessions/core/serialized_navigation_entry.h"
1042-#include "content/public/browser/certificate_request_result_type.h"
1043 #include "content/public/browser/navigation_controller.h"
1044 #include "content/public/browser/notification_observer.h"
1045 #include "content/public/browser/notification_registrar.h"
1046 #include "content/public/browser/web_contents_delegate.h"
1047 #include "content/public/browser/web_contents_observer.h"
1048 #include "content/public/common/javascript_message_type.h"
1049-#include "content/public/common/resource_type.h"
1050 #include "third_party/WebKit/public/platform/WebScreenInfo.h"
1051 #include "third_party/WebKit/public/platform/WebTopControlsState.h"
1052 #include "ui/gfx/geometry/point.h"
1053@@ -46,7 +44,6 @@
1054 #include "shared/browser/compositor/oxide_compositor_client.h"
1055 #include "shared/browser/compositor/oxide_compositor_observer.h"
1056 #include "shared/browser/input/oxide_input_method_context_observer.h"
1057-#include "shared/browser/oxide_certificate_error.h"
1058 #include "shared/browser/oxide_content_types.h"
1059 #include "shared/browser/oxide_render_widget_host_view_container.h"
1060 #include "shared/browser/oxide_script_message_target.h"
1061@@ -85,10 +82,6 @@
1062 class Size;
1063 }
1064
1065-namespace net {
1066-class SSLInfo;
1067-}
1068-
1069 namespace ui {
1070 class TouchEvent;
1071 }
1072@@ -261,16 +254,6 @@
1073
1074 void PrepareToClose();
1075
1076- void AllowCertificateError(content::RenderFrameHost* rfh,
1077- int cert_error,
1078- const net::SSLInfo& ssl_info,
1079- const GURL& request_url,
1080- content::ResourceType resource_type,
1081- bool overridable,
1082- bool strict_enforcement,
1083- const base::Callback<void(bool)>& callback,
1084- content::CertificateRequestResultType* result);
1085-
1086 void HandleKeyEvent(const content::NativeWebKeyboardEvent& event);
1087 void HandleMouseEvent(const blink::WebMouseEvent& event);
1088 void HandleTouchEvent(const ui::TouchEvent& event);
1089@@ -434,9 +417,6 @@
1090 content::MediaStreamType type) final;
1091
1092 // content::WebContentsObserver implementation
1093- void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) final;
1094- void RenderFrameHostChanged(content::RenderFrameHost* old_host,
1095- content::RenderFrameHost* new_host) final;
1096 void RenderViewReady() final;
1097 void RenderProcessGone(base::TerminationStatus status) final;
1098 void RenderViewHostChanged(content::RenderViewHost* old_host,
1099@@ -468,10 +448,6 @@
1100 void DidNavigateMainFrame(
1101 const content::LoadCommittedDetails& details,
1102 const content::FrameNavigateParams& params) final;
1103- void DidNavigateAnyFrame(
1104- content::RenderFrameHost* render_frame_host,
1105- const content::LoadCommittedDetails& details,
1106- const content::FrameNavigateParams& params) final;
1107 void DidGetRedirectForResourceRequest(
1108 content::RenderFrameHost* render_frame_host,
1109 const content::ResourceRedirectDetails& details) final;
1110@@ -510,8 +486,6 @@
1111 base::WeakPtr<WebPopupMenu> active_popup_menu_;
1112 base::WeakPtr<FilePicker> active_file_picker_;
1113
1114- CertificateErrorManager certificate_error_manager_;
1115-
1116 ContentType blocked_content_;
1117
1118 cc::CompositorFrameMetadata pending_compositor_frame_metadata_;
1119
1120=== modified file 'shared/browser/oxide_web_view_client.cc'
1121--- shared/browser/oxide_web_view_client.cc 2015-10-21 15:17:02 +0000
1122+++ shared/browser/oxide_web_view_client.cc 2015-10-21 20:26:37 +0000
1123@@ -141,8 +141,6 @@
1124
1125 void WebViewClient::SecurityStatusChanged(const SecurityStatus& old) {}
1126
1127-void WebViewClient::OnCertificateError(scoped_ptr<CertificateError> error) {}
1128-
1129 void WebViewClient::ContentBlocked() {}
1130
1131 void WebViewClient::PrepareToCloseResponseReceived(bool proceed) {}
1132
1133=== modified file 'shared/browser/oxide_web_view_client.h'
1134--- shared/browser/oxide_web_view_client.h 2015-10-21 15:17:02 +0000
1135+++ shared/browser/oxide_web_view_client.h 2015-10-21 20:26:37 +0000
1136@@ -173,8 +173,6 @@
1137 // TODO(chrisccoulson): Get rid of |old| and add |changed_flags|
1138 virtual void SecurityStatusChanged(const SecurityStatus& old);
1139
1140- virtual void OnCertificateError(scoped_ptr<CertificateError> error);
1141-
1142 // TODO(chrisccoulson): Rename to BlockedContentChanged or something
1143 // TODO(chrisccoulson): Move content tracking to a separate class with its
1144 // own delegate, as this is going to be expanded with content settings
1145
1146=== modified file 'shared/browser/oxide_web_view_contents_helper.cc'
1147--- shared/browser/oxide_web_view_contents_helper.cc 2015-09-24 15:53:36 +0000
1148+++ shared/browser/oxide_web_view_contents_helper.cc 2015-10-21 20:26:37 +0000
1149@@ -111,7 +111,13 @@
1150 // static
1151 WebViewContentsHelper* WebViewContentsHelper::FromRenderViewHost(
1152 content::RenderViewHost* rvh) {
1153- return FromWebContents(content::WebContents::FromRenderViewHost(rvh));
1154+ content::WebContents* contents =
1155+ content::WebContents::FromRenderViewHost(rvh);
1156+ if (!contents) {
1157+ return nullptr;
1158+ }
1159+
1160+ return FromWebContents(contents);
1161 }
1162
1163 content::WebContents* WebViewContentsHelper::GetWebContents() const {
1164
1165=== added directory 'shared/browser/ssl'
1166=== renamed file 'shared/browser/oxide_certificate_error.cc' => 'shared/browser/ssl/oxide_certificate_error.cc'
1167--- shared/browser/oxide_certificate_error.cc 2015-10-07 17:20:23 +0000
1168+++ shared/browser/ssl/oxide_certificate_error.cc 2015-10-21 20:26:37 +0000
1169@@ -17,293 +17,75 @@
1170
1171 #include "oxide_certificate_error.h"
1172
1173-#include <algorithm>
1174-
1175 #include "base/logging.h"
1176-#include "content/public/browser/render_frame_host.h"
1177-#include "net/base/net_errors.h"
1178 #include "net/cert/x509_certificate.h"
1179-#include "net/ssl/ssl_info.h"
1180+
1181+#include "oxide_certificate_error_proxy.h"
1182
1183 namespace oxide {
1184
1185-namespace {
1186-
1187-CertError ToCertError(int error, net::X509Certificate* cert) {
1188- DCHECK(net::IsCertificateError(error));
1189-
1190- switch (error) {
1191- case net::ERR_CERT_COMMON_NAME_INVALID:
1192- return CERT_ERROR_BAD_IDENTITY;
1193- case net::ERR_CERT_DATE_INVALID: {
1194- if (cert && cert->HasExpired()) {
1195- return CERT_ERROR_EXPIRED;
1196- }
1197- return CERT_ERROR_DATE_INVALID;
1198- }
1199- case net::ERR_CERT_AUTHORITY_INVALID:
1200- return CERT_ERROR_AUTHORITY_INVALID;
1201- case net::ERR_CERT_CONTAINS_ERRORS:
1202- case net::ERR_CERT_INVALID:
1203- case net::ERR_CERT_VALIDITY_TOO_LONG:
1204- return CERT_ERROR_INVALID;
1205- case net::ERR_CERT_REVOKED:
1206- return CERT_ERROR_REVOKED;
1207- case net::ERR_CERT_WEAK_SIGNATURE_ALGORITHM:
1208- case net::ERR_CERT_WEAK_KEY:
1209- return CERT_ERROR_INSECURE;
1210- //case net::ERR_CERT_NO_REVOCATION_MECHANISM:
1211- //case net::ERR_CERT_UNABLE_TO_CHECK_REVOCATION:
1212- //case net::ERR_CERT_NON_UNIQUE_NAME:
1213- //case net::ERR_CERT_NAME_CONSTRAINT_VIOLATION:
1214- default:
1215- return CERT_ERROR_GENERIC;
1216- }
1217-}
1218-
1219-}
1220-
1221-class CertificateErrorManager::IteratorGuard {
1222- public:
1223- IteratorGuard(CertificateErrorManager* manager);
1224- ~IteratorGuard();
1225-
1226- private:
1227- base::WeakPtr<CertificateErrorManager> manager_;
1228- bool iterating_original_;
1229-
1230- DISALLOW_COPY_AND_ASSIGN(IteratorGuard);
1231-};
1232-
1233-CertificateErrorManager::IteratorGuard::IteratorGuard(
1234- CertificateErrorManager* manager)
1235- : manager_(manager->weak_factory_.GetWeakPtr()),
1236- iterating_original_(manager->iterating_) {
1237- manager->iterating_ = true;
1238-}
1239-
1240-CertificateErrorManager::IteratorGuard::~IteratorGuard() {
1241- if (!manager_) {
1242- return;
1243- }
1244-
1245- manager_->iterating_ = iterating_original_;
1246- if (!manager_->iterating_) {
1247- manager_->Compact();
1248- }
1249-}
1250-
1251-void CertificateErrorManager::AddError(CertificateError* error) {
1252- DCHECK_EQ(error->manager_, this);
1253- DCHECK(std::find(errors_.begin(), errors_.end(), error) == errors_.end());
1254-
1255- errors_.push_back(error);
1256-}
1257-
1258-void CertificateErrorManager::RemoveError(CertificateError* error) {
1259- auto it = std::find(errors_.begin(), errors_.end(), error);
1260- DCHECK(it != errors_.end());
1261- if (iterating_) {
1262- *it = nullptr;
1263- } else {
1264- errors_.erase(it);
1265- }
1266-
1267- error->manager_ = nullptr;
1268-}
1269-
1270-void CertificateErrorManager::Compact() {
1271- DCHECK(!iterating_);
1272-
1273- errors_.erase(
1274- std::remove(errors_.begin(), errors_.end(), nullptr),
1275- errors_.end());
1276-}
1277-
1278-void CertificateErrorManager::CancelPendingFrameErrorsForFrame(
1279- content::RenderFrameHost* frame) {
1280- RenderFrameHostID frame_id = RenderFrameHostID::FromHost(frame);
1281-
1282- IteratorGuard guard(this);
1283-
1284- for (auto it = errors_.begin(); it != errors_.end(); ++it) {
1285- CertificateError* error = *it;
1286- if (!error) {
1287- continue;
1288- }
1289-
1290- if (error->frame_id_ != frame_id) {
1291- continue;
1292- }
1293-
1294- if (error->is_subresource()) {
1295- continue;
1296- }
1297-
1298- if (error->non_overridable_frame_error_committed_) {
1299- continue;
1300- }
1301-
1302- RemoveError(error);
1303- error->Cancel();
1304- }
1305-}
1306-
1307-CertificateErrorManager::CertificateErrorManager()
1308- : iterating_(false),
1309- weak_factory_(this) {}
1310-
1311-CertificateErrorManager::~CertificateErrorManager() {
1312- IteratorGuard guard(this);
1313- for (auto it = errors_.begin(); it != errors_.end(); ++it) {
1314- CertificateError* error = *it;
1315- if (!error) {
1316- continue;
1317- }
1318-
1319- RemoveError(error);
1320- error->Cancel();
1321- }
1322-}
1323-
1324-void CertificateErrorManager::DidStartProvisionalLoadForFrame(
1325- content::RenderFrameHost* frame) {
1326- DCHECK(frame);
1327- CancelPendingFrameErrorsForFrame(frame);
1328-}
1329-
1330-void CertificateErrorManager::DidNavigateFrame(
1331- content::RenderFrameHost* frame) {
1332- DCHECK(frame);
1333-
1334- RenderFrameHostID frame_id = RenderFrameHostID::FromHost(frame);
1335-
1336- IteratorGuard guard(this);
1337-
1338- for (auto it = errors_.begin(); it != errors_.end(); ++it) {
1339- CertificateError* error = *it;
1340- if (!error) {
1341- continue;
1342- }
1343-
1344- if (error->frame_id_ != frame_id) {
1345- continue;
1346- }
1347-
1348- if (!error->is_subresource() &&
1349- !error->non_overridable_frame_error_committed_) {
1350- error->non_overridable_frame_error_committed_ = true;
1351- continue;
1352- }
1353-
1354- RemoveError(error);
1355- error->Cancel();
1356- }
1357-}
1358-
1359-void CertificateErrorManager::DidStopProvisionalLoadForFrame(
1360- content::RenderFrameHost* frame) {
1361- DCHECK(frame);
1362- CancelPendingFrameErrorsForFrame(frame);
1363-}
1364-
1365-void CertificateErrorManager::FrameDetached(content::RenderFrameHost* frame) {
1366- DCHECK(frame);
1367-
1368- RenderFrameHostID frame_id = RenderFrameHostID::FromHost(frame);
1369-
1370- IteratorGuard guard(this);
1371-
1372- for (auto it = errors_.begin(); it != errors_.end(); ++it) {
1373- CertificateError* error = *it;
1374- if (!error) {
1375- continue;
1376- }
1377-
1378- if (error->frame_id_ != frame_id) {
1379- continue;
1380- }
1381-
1382- RemoveError(error);
1383- error->Cancel();
1384- }
1385-}
1386-
1387-void CertificateError::Cancel() {
1388- DCHECK(!is_cancelled_);
1389- DCHECK(!callback_.is_null() || !overridable_);
1390-
1391- is_cancelled_ = true;
1392-
1393- if (!callback_.is_null()) {
1394- callback_.Run(false);
1395- callback_.Reset();
1396- }
1397-
1398- if (!cancel_callback_.is_null()) {
1399- cancel_callback_.Run();
1400- cancel_callback_.Reset();
1401- }
1402-}
1403-
1404-CertificateError::CertificateError(
1405- CertificateErrorManager* manager,
1406- content::RenderFrameHost* frame,
1407- int cert_error,
1408- const net::SSLInfo& ssl_info,
1409- const GURL& url,
1410- content::ResourceType resource_type,
1411- bool strict_enforcement,
1412- const base::Callback<void(bool)>& callback)
1413- : manager_(manager),
1414- frame_id_(RenderFrameHostID::FromHost(frame)),
1415- is_main_frame_(!frame->GetParent()),
1416- is_subresource_(!content::IsResourceTypeFrame(resource_type)),
1417- cert_error_(ToCertError(cert_error, ssl_info.cert.get())),
1418- cert_(ssl_info.cert),
1419+CertificateError::CertificateError(bool is_main_frame,
1420+ bool is_subresource,
1421+ CertError cert_error,
1422+ net::X509Certificate* cert,
1423+ const GURL& url,
1424+ bool strict_enforcement,
1425+ bool overridable,
1426+ CertificateErrorProxy* proxy)
1427+ : is_main_frame_(is_main_frame),
1428+ is_subresource_(is_subresource),
1429+ cert_error_(cert_error),
1430+ cert_(cert),
1431 url_(url),
1432- overridable_(!callback.is_null()),
1433 strict_enforcement_(strict_enforcement),
1434- callback_(callback),
1435- is_cancelled_(false),
1436- non_overridable_frame_error_committed_(false) {
1437- DCHECK(manager_);
1438- DCHECK(frame);
1439- CHECK(!overridable_ || !strict_enforcement_) <<
1440- "overridable and strict_enforcement are expected to be mutually exclusive";
1441-
1442- manager_->AddError(this);
1443-}
1444+ overridable_(overridable),
1445+ proxy_(proxy) {}
1446
1447 CertificateError::~CertificateError() {
1448- if (!callback_.is_null()) {
1449- Deny();
1450- } else if (manager_) {
1451- manager_->RemoveError(this);
1452+ if (!proxy_->did_respond() && !proxy_->is_cancelled()) {
1453+ proxy_->Deny();
1454 }
1455 }
1456
1457+bool CertificateError::IsCancelled() const {
1458+ return proxy_->is_cancelled();
1459+}
1460+
1461 void CertificateError::SetCancelCallback(const base::Closure& callback) {
1462- DCHECK(!is_cancelled_);
1463- cancel_callback_ = callback;
1464+ proxy_->set_cancel_callback(callback);
1465 }
1466
1467 void CertificateError::Allow() {
1468- DCHECK(!callback_.is_null());
1469-
1470- callback_.Run(true);
1471- callback_.Reset();
1472-
1473- manager_->RemoveError(this);
1474+ if (!overridable()) {
1475+ LOG(WARNING) << "Can't override a non-overridable error";
1476+ return;
1477+ }
1478+
1479+ if (proxy_->is_cancelled()) {
1480+ LOG(WARNING) << "Can't override an error that's been cancelled";
1481+ return;
1482+ }
1483+
1484+ if (proxy_->did_respond()) {
1485+ LOG(WARNING) << "Can't respond more than once to a CertificateError";
1486+ return;
1487+ }
1488+
1489+ proxy_->Allow();
1490 }
1491
1492 void CertificateError::Deny() {
1493- DCHECK(!callback_.is_null());
1494-
1495- callback_.Run(false);
1496- callback_.Reset();
1497-
1498- manager_->RemoveError(this);
1499+ if (proxy_->is_cancelled()) {
1500+ LOG(WARNING) << "Can't override an error that's been cancelled";
1501+ return;
1502+ }
1503+
1504+ if (proxy_->did_respond()) {
1505+ LOG(WARNING) << "Can't respond more than once to a CertificateError";
1506+ return;
1507+ }
1508+
1509+ proxy_->Deny();
1510 }
1511
1512 } // namespace oxide
1513
1514=== renamed file 'shared/browser/oxide_certificate_error.h' => 'shared/browser/ssl/oxide_certificate_error.h'
1515--- shared/browser/oxide_certificate_error.h 2015-10-07 17:20:23 +0000
1516+++ shared/browser/ssl/oxide_certificate_error.h 2015-10-21 20:26:37 +0000
1517@@ -15,96 +15,36 @@
1518 // License along with this library; if not, write to the Free Software
1519 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1520
1521-#ifndef _OXIDE_SHARED_BROWSER_CERTIFICATE_ERROR_H_
1522-#define _OXIDE_SHARED_BROWSER_CERTIFICATE_ERROR_H_
1523-
1524-#include <vector>
1525+#ifndef _OXIDE_SHARED_BROWSER_SSL_CERTIFICATE_ERROR_H_
1526+#define _OXIDE_SHARED_BROWSER_SSL_CERTIFICATE_ERROR_H_
1527
1528 #include "base/callback.h"
1529 #include "base/macros.h"
1530 #include "base/memory/ref_counted.h"
1531-#include "base/memory/weak_ptr.h"
1532-#include "content/public/common/resource_type.h"
1533 #include "url/gurl.h"
1534
1535-#include "shared/browser/oxide_render_frame_host_id.h"
1536 #include "shared/browser/oxide_security_types.h"
1537
1538-namespace content {
1539-class RenderFrameHost;
1540-}
1541-
1542 namespace net {
1543-class SSLInfo;
1544 class X509Certificate;
1545 }
1546
1547 namespace oxide {
1548
1549-class CertificateError;
1550-
1551-// This class tracks CertificateErrors
1552-class CertificateErrorManager {
1553- public:
1554- CertificateErrorManager();
1555- ~CertificateErrorManager();
1556-
1557- // Cancels any pending frame errors for |frame|
1558- void DidStartProvisionalLoadForFrame(content::RenderFrameHost* frame);
1559-
1560- // Cancels any errors for |frame| with the exception of
1561- // non-overridable frame errors if this is the corresponding error page
1562- void DidNavigateFrame(content::RenderFrameHost* frame);
1563-
1564- // Cancels any pending frame errors for |frame|
1565- void DidStopProvisionalLoadForFrame(content::RenderFrameHost* frame);
1566-
1567- // Cancels all errors for frame
1568- void FrameDetached(content::RenderFrameHost* frame);
1569-
1570- private:
1571- friend class CertificateError;
1572- class IteratorGuard;
1573-
1574- // Add a CertificateError
1575- void AddError(CertificateError* error);
1576-
1577- // Remove a CertificateError, clearing its pointers to this
1578- // and the frame that generated the error
1579- void RemoveError(CertificateError* error);
1580-
1581- // Remove empty slots from errors_
1582- void Compact();
1583-
1584- void CancelPendingFrameErrorsForFrame(content::RenderFrameHost* frame);
1585-
1586- typedef std::vector<CertificateError*> CertErrorVector;
1587-
1588- // Used to indicate that errors_ is being iterated over, and
1589- // will prevent RemoveError from removing entries from it
1590- bool iterating_;
1591-
1592- // The list of CertificateErrors
1593- CertErrorVector errors_;
1594-
1595- base::WeakPtrFactory<CertificateErrorManager> weak_factory_;
1596-
1597- DISALLOW_COPY_AND_ASSIGN(CertificateErrorManager);
1598-};
1599+class CertificateErrorProxy;
1600
1601 // Represents a SSL certificate error. It provides access to the relevant
1602 // information about the error, as well as methods to accept or deny it
1603 class CertificateError {
1604 public:
1605- CertificateError(
1606- CertificateErrorManager* manager,
1607- content::RenderFrameHost* frame,
1608- int cert_error,
1609- const net::SSLInfo& ssl_info,
1610- const GURL& url,
1611- content::ResourceType resource_type,
1612- bool strict_enforcement,
1613- const base::Callback<void(bool)>& callback);
1614+ CertificateError(bool is_main_frame,
1615+ bool is_subresource,
1616+ CertError cert_error,
1617+ net::X509Certificate* cert,
1618+ const GURL& url,
1619+ bool strict_enforcement,
1620+ bool overridable,
1621+ CertificateErrorProxy* proxy);
1622 ~CertificateError();
1623
1624 // If the error is from the main frame
1625@@ -128,55 +68,35 @@
1626 // Whether the error was generated from a URL that uses HSTS
1627 bool strict_enforcement() const { return strict_enforcement_; }
1628
1629- // Whether the error has been cancelled by Oxide. A cancelled error is no
1630- // longer relevant. This can happen if the frame navigates or goes away
1631- bool is_cancelled() const { return is_cancelled_; }
1632+ // Whether the error has been cancelled by Oxide. This is only relevant
1633+ // for main frame errors (is_main_frame_ && !is_subresource_) and is used
1634+ // to signal to the application when it should hide its certificate error UI
1635+ bool IsCancelled() const;
1636
1637 // Set a callback to be invoked when this error is cancelled
1638 void SetCancelCallback(const base::Closure& callback);
1639
1640 // Allow the request that generated the error to continue, ignoring the
1641- // error. Only possible if overridable() returns true
1642+ // error. Only possible if IsOverridable() returns true
1643 void Allow();
1644
1645 // Cancel the request that generated the error
1646 void Deny();
1647
1648 private:
1649- friend class CertificateErrorManager;
1650-
1651- // Cancel the request that generated the error and run the cancel callback.
1652- // This is only called from CertificateErrorManager
1653- void Cancel();
1654-
1655- CertificateErrorManager* manager_;
1656-
1657- // The ID of the frame the generated this error
1658- RenderFrameHostID frame_id_;
1659-
1660 bool is_main_frame_;
1661 bool is_subresource_;
1662 CertError cert_error_;
1663 scoped_refptr<net::X509Certificate> cert_;
1664 GURL url_;
1665+ bool strict_enforcement_;
1666 bool overridable_;
1667- bool strict_enforcement_;
1668-
1669- // The callback provided by Chromium, which we use to respond to the error
1670- base::Callback<void(bool)> callback_;
1671-
1672- bool is_cancelled_;
1673- base::Closure cancel_callback_;
1674-
1675- // Subresource errors are cancelled when a frame is committed.
1676- // However, non-overridable frame errors should persist beyond the error
1677- // page commit for this failed load and then be cancelled on a subsequent
1678- // commit. This is used for tracking that
1679- bool non_overridable_frame_error_committed_;
1680+
1681+ scoped_refptr<CertificateErrorProxy> proxy_;
1682
1683 DISALLOW_COPY_AND_ASSIGN(CertificateError);
1684 };
1685
1686 } // namespace oxide
1687
1688-#endif // _OXIDE_SHARED_BROWSER_CERTIFICATE_ERROR_H_
1689+#endif // _OXIDE_SHARED_BROWSER_SSL_CERTIFICATE_ERROR_H_
1690
1691=== added file 'shared/browser/ssl/oxide_certificate_error_dispatcher.cc'
1692--- shared/browser/ssl/oxide_certificate_error_dispatcher.cc 1970-01-01 00:00:00 +0000
1693+++ shared/browser/ssl/oxide_certificate_error_dispatcher.cc 2015-10-21 20:26:37 +0000
1694@@ -0,0 +1,196 @@
1695+// vim:expandtab:shiftwidth=2:tabstop=2:
1696+// Copyright (C) 2015 Canonical Ltd.
1697+
1698+// This library is free software; you can redistribute it and/or
1699+// modify it under the terms of the GNU Lesser General Public
1700+// License as published by the Free Software Foundation; either
1701+// version 2.1 of the License, or (at your option) any later version.
1702+
1703+// This library is distributed in the hope that it will be useful,
1704+// but WITHOUT ANY WARRANTY; without even the implied warranty of
1705+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1706+// Lesser General Public License for more details.
1707+
1708+// You should have received a copy of the GNU Lesser General Public
1709+// License along with this library; if not, write to the Free Software
1710+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1711+
1712+#include "oxide_certificate_error_dispatcher.h"
1713+
1714+#include "base/logging.h"
1715+#include "base/memory/ref_counted.h"
1716+#include "content/public/browser/browser_thread.h"
1717+#include "content/public/browser/certificate_request_result_type.h"
1718+#include "content/public/browser/render_frame_host.h"
1719+#include "content/public/browser/web_contents.h"
1720+#include "net/base/net_errors.h"
1721+#include "net/cert/x509_certificate.h"
1722+#include "net/ssl/ssl_info.h"
1723+#include "url/gurl.h"
1724+
1725+#include "shared/browser/oxide_security_types.h"
1726+
1727+#include "oxide_certificate_error.h"
1728+#include "oxide_certificate_error_dispatcher_client.h"
1729+#include "oxide_certificate_error_placeholder_page.h"
1730+#include "oxide_certificate_error_proxy.h"
1731+
1732+namespace oxide {
1733+
1734+namespace {
1735+
1736+CertError ToCertError(int error, net::X509Certificate* cert) {
1737+ DCHECK(net::IsCertificateError(error));
1738+
1739+ switch (error) {
1740+ case net::ERR_CERT_COMMON_NAME_INVALID:
1741+ return CERT_ERROR_BAD_IDENTITY;
1742+ case net::ERR_CERT_DATE_INVALID: {
1743+ if (cert && cert->HasExpired()) {
1744+ return CERT_ERROR_EXPIRED;
1745+ }
1746+ return CERT_ERROR_DATE_INVALID;
1747+ }
1748+ case net::ERR_CERT_AUTHORITY_INVALID:
1749+ return CERT_ERROR_AUTHORITY_INVALID;
1750+ case net::ERR_CERT_CONTAINS_ERRORS:
1751+ case net::ERR_CERT_INVALID:
1752+ case net::ERR_CERT_VALIDITY_TOO_LONG:
1753+ return CERT_ERROR_INVALID;
1754+ case net::ERR_CERT_REVOKED:
1755+ return CERT_ERROR_REVOKED;
1756+ case net::ERR_CERT_WEAK_SIGNATURE_ALGORITHM:
1757+ case net::ERR_CERT_WEAK_KEY:
1758+ return CERT_ERROR_INSECURE;
1759+ //case net::ERR_CERT_NO_REVOCATION_MECHANISM:
1760+ //case net::ERR_CERT_UNABLE_TO_CHECK_REVOCATION:
1761+ //case net::ERR_CERT_NON_UNIQUE_NAME:
1762+ //case net::ERR_CERT_NAME_CONSTRAINT_VIOLATION:
1763+ default:
1764+ return CERT_ERROR_GENERIC;
1765+ }
1766+}
1767+
1768+}
1769+
1770+DEFINE_WEB_CONTENTS_USER_DATA_KEY(CertificateErrorDispatcher);
1771+
1772+CertificateErrorDispatcher::CertificateErrorDispatcher()
1773+ : client_(nullptr) {}
1774+
1775+bool CertificateErrorDispatcher::CanDispatch() const {
1776+ return !!client_;
1777+}
1778+
1779+void CertificateErrorDispatcher::Dispatch(scoped_ptr<CertificateError> error) {
1780+ client_->OnCertificateError(error.Pass());
1781+}
1782+
1783+CertificateErrorDispatcher::~CertificateErrorDispatcher() {}
1784+
1785+// static
1786+void CertificateErrorDispatcher::CreateForWebContents(
1787+ content::WebContents* contents) {
1788+ DCHECK(contents);
1789+ if (!FromWebContents(contents)) {
1790+ contents->SetUserData(UserDataKey(), new CertificateErrorDispatcher());
1791+ }
1792+}
1793+
1794+// static
1795+void CertificateErrorDispatcher::AllowCertificateError(
1796+ int render_process_id,
1797+ int render_frame_id,
1798+ int cert_error,
1799+ const net::SSLInfo& ssl_info,
1800+ const GURL& request_url,
1801+ content::ResourceType resource_type,
1802+ bool overridable,
1803+ bool strict_enforcement,
1804+ const base::Callback<void(bool)>& callback,
1805+ content::CertificateRequestResultType* result) {
1806+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
1807+ DCHECK_IMPLIES(strict_enforcement, !overridable);
1808+
1809+ // Note, CANCEL will stop the resource load associated with the error, and
1810+ // DENY will fail it, resulting in an error page being loaded if it's
1811+ // for the document request
1812+
1813+ content::RenderFrameHost* rfh =
1814+ content::RenderFrameHost::FromID(render_process_id, render_frame_id);
1815+ if (!rfh) {
1816+ *result = content::CERTIFICATE_REQUEST_RESULT_TYPE_CANCEL;
1817+ return;
1818+ }
1819+
1820+ content::WebContents* contents =
1821+ content::WebContents::FromRenderFrameHost(rfh);
1822+ if (!contents) {
1823+ *result = content::CERTIFICATE_REQUEST_RESULT_TYPE_CANCEL;
1824+ return;
1825+ }
1826+
1827+ CertificateErrorDispatcher* dispatcher = FromWebContents(contents);
1828+
1829+ if (!dispatcher->CanDispatch()) {
1830+ *result = content::CERTIFICATE_REQUEST_RESULT_TYPE_DENY;
1831+ return;
1832+ }
1833+
1834+ if (resource_type != content::RESOURCE_TYPE_MAIN_FRAME) {
1835+ // Only errors for main frame document resources are overridable, as it's
1836+ // the only case where we can guarantee that the security status for the
1837+ // webview is correct (see https://launchpad.net/bugs/1368385), and it's
1838+ // the only case where we trust the application to be able to display a
1839+ // meaningful UI
1840+ overridable = false;
1841+ *result = content::CERTIFICATE_REQUEST_RESULT_TYPE_DENY;
1842+ } else if (!overridable) {
1843+ // Don't load an error page for main frame document errors, as we're going
1844+ // to load a placeholder transient page
1845+ *result = content::CERTIFICATE_REQUEST_RESULT_TYPE_CANCEL;
1846+ }
1847+
1848+
1849+ scoped_refptr<CertificateErrorProxy> proxy =
1850+ new CertificateErrorProxy(
1851+ overridable ? callback : base::Callback<void(bool)>());
1852+ scoped_ptr<CertificateError> error(
1853+ new CertificateError(!rfh->GetParent(),
1854+ !content::IsResourceTypeFrame(resource_type),
1855+ ToCertError(cert_error, ssl_info.cert.get()),
1856+ ssl_info.cert.get(),
1857+ request_url,
1858+ strict_enforcement,
1859+ overridable,
1860+ proxy.get()));
1861+
1862+ dispatcher->Dispatch(error.Pass());
1863+
1864+ if (proxy->did_respond()) {
1865+ // If the application responded explicitly or by CertificateError being
1866+ // destroyed, there's nothing more to do
1867+ return;
1868+ }
1869+
1870+ if (resource_type != content::RESOURCE_TYPE_MAIN_FRAME) {
1871+ // If this error isn't for a main frame document resource, there's nothing
1872+ // more to do
1873+ return;
1874+ }
1875+
1876+ // For main frame document resources, we insert a placeholder transient page
1877+ // as long as CertificateError is alive and not responded to. This is
1878+ // intended to help the embedder when it displays a certificate error UI by
1879+ // ensuring the visible URL is correct, navigation history is consistent, the
1880+ // webview is marked as not loading and the back button behaves correctly
1881+ // (should dismiss the error via the cancel callback and go back to the last
1882+ // committed page)
1883+
1884+ // This gets owned by the |contents|
1885+ new CertificateErrorPlaceholderPage(contents,
1886+ request_url,
1887+ proxy.get());
1888+}
1889+
1890+} // namespace oxide
1891
1892=== added file 'shared/browser/ssl/oxide_certificate_error_dispatcher.h'
1893--- shared/browser/ssl/oxide_certificate_error_dispatcher.h 1970-01-01 00:00:00 +0000
1894+++ shared/browser/ssl/oxide_certificate_error_dispatcher.h 2015-10-21 20:26:37 +0000
1895@@ -0,0 +1,77 @@
1896+// vim:expandtab:shiftwidth=2:tabstop=2:
1897+// Copyright (C) 2015 Canonical Ltd.
1898+
1899+// This library is free software; you can redistribute it and/or
1900+// modify it under the terms of the GNU Lesser General Public
1901+// License as published by the Free Software Foundation; either
1902+// version 2.1 of the License, or (at your option) any later version.
1903+
1904+// This library is distributed in the hope that it will be useful,
1905+// but WITHOUT ANY WARRANTY; without even the implied warranty of
1906+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1907+// Lesser General Public License for more details.
1908+
1909+// You should have received a copy of the GNU Lesser General Public
1910+// License along with this library; if not, write to the Free Software
1911+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1912+
1913+#ifndef _OXIDE_SHARED_BROWSER_SSL_CERTIFICATE_ERROR_DISPATCHER_H_
1914+#define _OXIDE_SHARED_BROWSER_SSL_CERTIFICATE_ERROR_DISPATCHER_H_
1915+
1916+#include "base/callback.h"
1917+#include "base/macros.h"
1918+#include "content/public/browser/certificate_request_result_type.h"
1919+#include "content/public/browser/web_contents_user_data.h"
1920+#include "content/public/common/resource_type.h"
1921+
1922+class GURL;
1923+
1924+namespace net {
1925+class SSLInfo;
1926+}
1927+
1928+namespace oxide {
1929+
1930+class CertificateError;
1931+class CertificateErrorDispatcherClient;
1932+
1933+// A helper class for dispatching certificate errors from Chromium to
1934+// CertificateErrorDispatcherClient
1935+class CertificateErrorDispatcher
1936+ : public content::WebContentsUserData<CertificateErrorDispatcher> {
1937+ public:
1938+ ~CertificateErrorDispatcher();
1939+
1940+ static void CreateForWebContents(content::WebContents* contents);
1941+
1942+ // Entry point from Chromium
1943+ static void AllowCertificateError(
1944+ int render_process_id,
1945+ int render_frame_id,
1946+ int cert_error,
1947+ const net::SSLInfo& ssl_info,
1948+ const GURL& request_url,
1949+ content::ResourceType resource_type,
1950+ bool overridable,
1951+ bool strict_enforcement,
1952+ const base::Callback<void(bool)>& callback,
1953+ content::CertificateRequestResultType* result);
1954+
1955+ void set_client(CertificateErrorDispatcherClient* client) {
1956+ client_ = client;
1957+ }
1958+
1959+ private:
1960+ CertificateErrorDispatcher();
1961+
1962+ bool CanDispatch() const;
1963+ void Dispatch(scoped_ptr<CertificateError> error);
1964+
1965+ CertificateErrorDispatcherClient* client_;
1966+
1967+ DISALLOW_COPY_AND_ASSIGN(CertificateErrorDispatcher);
1968+};
1969+
1970+} // namespace oxide
1971+
1972+#endif // _OXIDE_SHARED_BROWSER_SSL_CERTIFICATE_ERROR_DISPATCHER_H_
1973
1974=== added file 'shared/browser/ssl/oxide_certificate_error_dispatcher_client.h'
1975--- shared/browser/ssl/oxide_certificate_error_dispatcher_client.h 1970-01-01 00:00:00 +0000
1976+++ shared/browser/ssl/oxide_certificate_error_dispatcher_client.h 2015-10-21 20:26:37 +0000
1977@@ -0,0 +1,36 @@
1978+// vim:expandtab:shiftwidth=2:tabstop=2:
1979+// Copyright (C) 2015 Canonical Ltd.
1980+
1981+// This library is free software; you can redistribute it and/or
1982+// modify it under the terms of the GNU Lesser General Public
1983+// License as published by the Free Software Foundation; either
1984+// version 2.1 of the License, or (at your option) any later version.
1985+
1986+// This library is distributed in the hope that it will be useful,
1987+// but WITHOUT ANY WARRANTY; without even the implied warranty of
1988+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1989+// Lesser General Public License for more details.
1990+
1991+// You should have received a copy of the GNU Lesser General Public
1992+// License along with this library; if not, write to the Free Software
1993+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1994+
1995+#ifndef _OXIDE_SHARED_BROWSER_SSL_CERTIFICATE_ERROR_DISPATCHER_CLIENT_H_
1996+#define _OXIDE_SHARED_BROWSER_SSL_CERTIFICATE_ERROR_DISPATCHER_CLIENT_H_
1997+
1998+#include "base/memory/scoped_ptr.h"
1999+
2000+namespace oxide {
2001+
2002+class CertificateError;
2003+
2004+class CertificateErrorDispatcherClient {
2005+ public:
2006+ virtual ~CertificateErrorDispatcherClient() {}
2007+
2008+ virtual void OnCertificateError(scoped_ptr<CertificateError> error) = 0;
2009+};
2010+
2011+} // namespace oxide
2012+
2013+#endif // _OXIDE_SHARED_BROWSER_SSL_CERTIFICATE_ERROR_DISPATCHER_CLIENT_H_
2014
2015=== added file 'shared/browser/ssl/oxide_certificate_error_placeholder_page.cc'
2016--- shared/browser/ssl/oxide_certificate_error_placeholder_page.cc 1970-01-01 00:00:00 +0000
2017+++ shared/browser/ssl/oxide_certificate_error_placeholder_page.cc 2015-10-21 20:26:37 +0000
2018@@ -0,0 +1,58 @@
2019+// vim:expandtab:shiftwidth=2:tabstop=2:
2020+// Copyright (C) 2015 Canonical Ltd.
2021+
2022+// This library is free software; you can redistribute it and/or
2023+// modify it under the terms of the GNU Lesser General Public
2024+// License as published by the Free Software Foundation; either
2025+// version 2.1 of the License, or (at your option) any later version.
2026+
2027+// This library is distributed in the hope that it will be useful,
2028+// but WITHOUT ANY WARRANTY; without even the implied warranty of
2029+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2030+// Lesser General Public License for more details.
2031+
2032+// You should have received a copy of the GNU Lesser General Public
2033+// License along with this library; if not, write to the Free Software
2034+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2035+
2036+#include "oxide_certificate_error_placeholder_page.h"
2037+
2038+#include "base/logging.h"
2039+#include "content/public/browser/interstitial_page.h"
2040+
2041+#include "oxide_certificate_error_proxy.h"
2042+
2043+namespace oxide {
2044+
2045+CertificateErrorPlaceholderPage::~CertificateErrorPlaceholderPage() {}
2046+
2047+std::string CertificateErrorPlaceholderPage::GetHTMLContents() {
2048+ return "<html></html>";
2049+}
2050+
2051+void CertificateErrorPlaceholderPage::OnDontProceed() {
2052+ error_->Cancel();
2053+}
2054+
2055+CertificateErrorPlaceholderPage::CertificateErrorPlaceholderPage(
2056+ content::WebContents* contents,
2057+ const GURL& request_url,
2058+ CertificateErrorProxy* error)
2059+ : interstitial_(content::InterstitialPage::Create(contents,
2060+ true,
2061+ request_url,
2062+ this)),
2063+ error_(error) {
2064+ error_->SetPlaceholderPage(this);
2065+ interstitial_->Show();
2066+}
2067+
2068+void CertificateErrorPlaceholderPage::Proceed() {
2069+ interstitial_->Proceed();
2070+}
2071+
2072+void CertificateErrorPlaceholderPage::DontProceed() {
2073+ interstitial_->DontProceed();
2074+}
2075+
2076+} // namespace oxide
2077
2078=== added file 'shared/browser/ssl/oxide_certificate_error_placeholder_page.h'
2079--- shared/browser/ssl/oxide_certificate_error_placeholder_page.h 1970-01-01 00:00:00 +0000
2080+++ shared/browser/ssl/oxide_certificate_error_placeholder_page.h 2015-10-21 20:26:37 +0000
2081@@ -0,0 +1,64 @@
2082+// vim:expandtab:shiftwidth=2:tabstop=2:
2083+// Copyright (C) 2015 Canonical Ltd.
2084+
2085+// This library is free software; you can redistribute it and/or
2086+// modify it under the terms of the GNU Lesser General Public
2087+// License as published by the Free Software Foundation; either
2088+// version 2.1 of the License, or (at your option) any later version.
2089+
2090+// This library is distributed in the hope that it will be useful,
2091+// but WITHOUT ANY WARRANTY; without even the implied warranty of
2092+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2093+// Lesser General Public License for more details.
2094+
2095+// You should have received a copy of the GNU Lesser General Public
2096+// License along with this library; if not, write to the Free Software
2097+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2098+
2099+#ifndef _OXIDE_SHARED_BROWSER_SSL_CERTIFICATE_ERROR_PLACEHOLDER_PAGE_H_
2100+#define _OXIDE_SHARED_BROWSER_SSL_CERTIFICATE_ERROR_PLACEHOLDER_PAGE_H_
2101+
2102+#include "base/macros.h"
2103+#include "base/memory/ref_counted.h"
2104+#include "content/public/browser/interstitial_page_delegate.h"
2105+
2106+class GURL;
2107+
2108+namespace content {
2109+class InterstitialPage;
2110+class WebContents;
2111+}
2112+
2113+namespace oxide {
2114+
2115+class CertificateErrorProxy;
2116+
2117+// This class inserts a placeholder transient page in to a WebContents'
2118+// navigation list whilst an application displays a certificate error UI
2119+class CertificateErrorPlaceholderPage
2120+ : public content::InterstitialPageDelegate {
2121+ public:
2122+ CertificateErrorPlaceholderPage(content::WebContents* contents,
2123+ const GURL& request_url,
2124+ CertificateErrorProxy* error);
2125+
2126+ void Proceed();
2127+ void DontProceed();
2128+
2129+ private:
2130+ ~CertificateErrorPlaceholderPage() override;
2131+
2132+ // content::InterstitialPageDelegate implementation
2133+ std::string GetHTMLContents() override;
2134+ void OnDontProceed() override;
2135+
2136+ content::InterstitialPage* interstitial_; // This owns us
2137+
2138+ scoped_refptr<CertificateErrorProxy> error_;
2139+
2140+ DISALLOW_COPY_AND_ASSIGN(CertificateErrorPlaceholderPage);
2141+};
2142+
2143+} // namespace oxide
2144+
2145+#endif // _OXIDE_SHARED_BROWSER_SSL_CERTIFICATE_ERROR_PLACEHOLDER_PAGE_H_
2146
2147=== added file 'shared/browser/ssl/oxide_certificate_error_proxy.cc'
2148--- shared/browser/ssl/oxide_certificate_error_proxy.cc 1970-01-01 00:00:00 +0000
2149+++ shared/browser/ssl/oxide_certificate_error_proxy.cc 2015-10-21 20:26:37 +0000
2150@@ -0,0 +1,105 @@
2151+// vim:expandtab:shiftwidth=2:tabstop=2:
2152+// Copyright (C) 2015 Canonical Ltd.
2153+
2154+// This library is free software; you can redistribute it and/or
2155+// modify it under the terms of the GNU Lesser General Public
2156+// License as published by the Free Software Foundation; either
2157+// version 2.1 of the License, or (at your option) any later version.
2158+
2159+// This library is distributed in the hope that it will be useful,
2160+// but WITHOUT ANY WARRANTY; without even the implied warranty of
2161+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2162+// Lesser General Public License for more details.
2163+
2164+// You should have received a copy of the GNU Lesser General Public
2165+// License along with this library; if not, write to the Free Software
2166+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2167+
2168+#include "oxide_certificate_error_proxy.h"
2169+
2170+#include "base/logging.h"
2171+
2172+#include "oxide_certificate_error_placeholder_page.h"
2173+
2174+namespace oxide {
2175+
2176+CertificateErrorProxy::~CertificateErrorProxy() {
2177+ DCHECK(did_respond_ || is_cancelled_);
2178+}
2179+
2180+CertificateErrorProxy::CertificateErrorProxy(
2181+ const base::Callback<void(bool)>& callback)
2182+ : callback_(callback),
2183+ is_cancelled_(false),
2184+ did_respond_(false),
2185+ placeholder_page_(nullptr) {}
2186+
2187+void CertificateErrorProxy::Allow() {
2188+ DCHECK(!did_respond_);
2189+ DCHECK(!is_cancelled_);
2190+ DCHECK(!callback_.is_null());
2191+
2192+ did_respond_ = true;
2193+
2194+ callback_.Run(true);
2195+ callback_.Reset();
2196+
2197+ if (placeholder_page_) {
2198+ placeholder_page_->Proceed();
2199+ placeholder_page_ = nullptr;
2200+ }
2201+}
2202+
2203+void CertificateErrorProxy::Deny() {
2204+ DCHECK(!did_respond_);
2205+ DCHECK(!is_cancelled_);
2206+
2207+ did_respond_ = true;
2208+
2209+ if (!callback_.is_null()) {
2210+ callback_.Run(false);
2211+ callback_.Reset();
2212+ }
2213+
2214+ if (placeholder_page_) {
2215+ placeholder_page_->DontProceed();
2216+ placeholder_page_ = nullptr;
2217+ }
2218+}
2219+
2220+void CertificateErrorProxy::Cancel() {
2221+ DCHECK(!is_cancelled_);
2222+
2223+ if (did_respond_) {
2224+ // Calling Deny() ends up re-entering here via
2225+ // InterstitialPageDelegate::OnDontProceed
2226+ return;
2227+ }
2228+
2229+ // Chromium can call in to us after we've responded, if we responded
2230+ // before the interstitial navigation was committed. This is why this check
2231+ // is here, and not higher up
2232+ DCHECK(placeholder_page_);
2233+
2234+ is_cancelled_ = true;
2235+ placeholder_page_ = nullptr;
2236+
2237+ if (!callback_.is_null()) {
2238+ callback_.Run(false);
2239+ callback_.Reset();
2240+ }
2241+
2242+ if (!cancel_callback_.is_null()) {
2243+ cancel_callback_.Run();
2244+ cancel_callback_.Reset();
2245+ }
2246+}
2247+
2248+void CertificateErrorProxy::SetPlaceholderPage(
2249+ CertificateErrorPlaceholderPage* placeholder) {
2250+ DCHECK(!did_respond_);
2251+ DCHECK(!is_cancelled_);
2252+ placeholder_page_ = placeholder;
2253+}
2254+
2255+} // namespace oxide
2256
2257=== added file 'shared/browser/ssl/oxide_certificate_error_proxy.h'
2258--- shared/browser/ssl/oxide_certificate_error_proxy.h 1970-01-01 00:00:00 +0000
2259+++ shared/browser/ssl/oxide_certificate_error_proxy.h 2015-10-21 20:26:37 +0000
2260@@ -0,0 +1,65 @@
2261+// vim:expandtab:shiftwidth=2:tabstop=2:
2262+// Copyright (C) 2015 Canonical Ltd.
2263+
2264+// This library is free software; you can redistribute it and/or
2265+// modify it under the terms of the GNU Lesser General Public
2266+// License as published by the Free Software Foundation; either
2267+// version 2.1 of the License, or (at your option) any later version.
2268+
2269+// This library is distributed in the hope that it will be useful,
2270+// but WITHOUT ANY WARRANTY; without even the implied warranty of
2271+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2272+// Lesser General Public License for more details.
2273+
2274+// You should have received a copy of the GNU Lesser General Public
2275+// License along with this library; if not, write to the Free Software
2276+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2277+
2278+#ifndef _OXIDE_SHARED_BROWSER_SSL_CERTIFICATE_ERROR_PROXY_H_
2279+#define _OXIDE_SHARED_BROWSER_SSL_CERTIFICATE_ERROR_PROXY_H_
2280+
2281+#include "base/callback.h"
2282+#include "base/macros.h"
2283+#include "base/memory/ref_counted.h"
2284+
2285+namespace oxide {
2286+
2287+class CertificateErrorPlaceholderPage;
2288+
2289+// This class sits between CertificateError and CertificateErrorPlaceholderPage
2290+class CertificateErrorProxy : public base::RefCounted<CertificateErrorProxy> {
2291+ public:
2292+ CertificateErrorProxy(const base::Callback<void(bool)>& callback);
2293+
2294+ bool is_cancelled() const { return is_cancelled_; }
2295+ bool did_respond() const { return did_respond_; }
2296+
2297+ void set_cancel_callback(const base::Closure& cancel_callback) {
2298+ cancel_callback_ = cancel_callback;
2299+ }
2300+
2301+ void Allow();
2302+ void Deny();
2303+
2304+ void Cancel();
2305+
2306+ void SetPlaceholderPage(CertificateErrorPlaceholderPage* placeholder);
2307+
2308+ private:
2309+ friend class base::RefCounted<CertificateErrorProxy>;
2310+ ~CertificateErrorProxy();
2311+
2312+ base::Callback<void(bool)> callback_;
2313+
2314+ bool is_cancelled_;
2315+ bool did_respond_;
2316+ base::Closure cancel_callback_;
2317+
2318+ CertificateErrorPlaceholderPage* placeholder_page_;
2319+
2320+ DISALLOW_COPY_AND_ASSIGN(CertificateErrorProxy);
2321+};
2322+
2323+} // namespace oxide
2324+
2325+#endif // _OXIDE_SHARED_BROWSER_SSL_CERTIFICATE_ERROR_PROXY_H_
2326
2327=== modified file 'shared/shared.gyp'
2328--- shared/shared.gyp 2015-10-21 17:07:17 +0000
2329+++ shared/shared.gyp 2015-10-21 20:26:37 +0000
2330@@ -352,8 +352,6 @@
2331 'browser/oxide_browser_platform_integration_observer.h',
2332 'browser/oxide_browser_process_main.cc',
2333 'browser/oxide_browser_process_main.h',
2334- 'browser/oxide_certificate_error.cc',
2335- 'browser/oxide_certificate_error.h',
2336 'browser/oxide_content_browser_client.cc',
2337 'browser/oxide_content_browser_client.h',
2338 'browser/oxide_content_types.h',
2339@@ -475,6 +473,15 @@
2340 'browser/permissions/oxide_permission_request_response.h',
2341 'browser/permissions/oxide_temporary_saved_permission_context.cc',
2342 'browser/permissions/oxide_temporary_saved_permission_context.h',
2343+ 'browser/ssl/oxide_certificate_error.cc',
2344+ 'browser/ssl/oxide_certificate_error.h',
2345+ 'browser/ssl/oxide_certificate_error_dispatcher.cc',
2346+ 'browser/ssl/oxide_certificate_error_dispatcher.h',
2347+ 'browser/ssl/oxide_certificate_error_dispatcher_client.h',
2348+ 'browser/ssl/oxide_certificate_error_placeholder_page.cc',
2349+ 'browser/ssl/oxide_certificate_error_placeholder_page.h',
2350+ 'browser/ssl/oxide_certificate_error_proxy.cc',
2351+ 'browser/ssl/oxide_certificate_error_proxy.h',
2352 'common/oxide_constants.cc',
2353 'common/oxide_constants.h',
2354 'common/oxide_content_client.cc',

Subscribers

People subscribed via source and target branches