Merge lp:~zaspire/oxide/lp_1259219 into lp:~oxide-developers/oxide/oxide.trunk

Proposed by Maxim Ermilov
Status: Merged
Merged at revision: 449
Proposed branch: lp:~zaspire/oxide/lp_1259219
Merge into: lp:~oxide-developers/oxide/oxide.trunk
Diff against target: 270 lines (+140/-1)
11 files modified
qt/core/glue/oxide_qt_web_view_adapter.h (+1/-0)
qt/core/glue/private/oxide_qt_web_view_adapter_p.cc (+25/-0)
qt/core/glue/private/oxide_qt_web_view_adapter_p.h (+3/-0)
qt/quick/api/oxideqquickwebview.cc (+9/-0)
qt/quick/api/oxideqquickwebview_p.h (+25/-0)
qt/quick/api/oxideqquickwebview_p_p.h (+1/-0)
qt/quick/oxide_qml_plugin.cc (+2/-0)
qt/tests/qmltests/api/tst_WebView_navigation_request.qml (+59/-0)
qt/tests/qmltests/api/tst_WebView_navigation_request1.html (+12/-0)
shared/browser/oxide_web_view.cc (+2/-0)
shared/browser/oxide_web_view.h (+1/-1)
To merge this branch: bzr merge lp:~zaspire/oxide/lp_1259219
Reviewer Review Type Date Requested Status
Chris Coulson Needs Fixing
Olivier Tilloy Pending
Review via email: mp+212330@code.launchpad.net
To post a comment you must log in.
lp:~zaspire/oxide/lp_1259219 updated
435. By Chris Coulson

BrowserContext::GetCachePath() and BrowserContext::GetPath() no longer return an empty path for OTR contexts, and BrowserContext::IsOffTheRecord() always returns false for the main context, since r432

436. By Olivier Tilloy

Implement a dummy AccessTokenStore to prevent geolocation requests from crashing the renderer.

437. By Chris Coulson

Update exclude list for tarball

438. By Chris Coulson

This provides some improvements to the changes in r425-r431. It:
- Makes IOThreadGlobals::Data publically available as Globals, and renames
  IOThreadGlobals to IOThread. This provides a proper API split for accessing
  things that belong to the IO thread
- Reverts the change that made IOThread a singleton - we want to control when
  to destroy it
- Destroys the system URL request context before the IO thread has gone away
  (fixes LP: #1296668)
- Gets rid of URLRequestContextInitializer - this was overcomplicated. Now, we
  subclass URLRequestContextGetter instead
- Move the initialization for common paramters out of URLRequestContextGetter
  in to the constructor for URLRequestContext so that we don't need to rely
  on URLRequestContextGetter to create the request context. This was a bit
  weird anyway

Revision history for this message
Chris Coulson (chrisccoulson) wrote :
Download full text (3.6 KiB)

Hi,

Thanks for working on this. I do have some concerns with the current approach though.

First of all, on coding style:
- We try to stick with an 80 character line length where possible. I do use vertical splits in vim quite a bit, and longer lines makes the code quite difficult to read. Of course, we make exceptions where it's not really possible to stick within 80 characters. There's plenty of those already in the tree.

Some comments for the actual API:
- OxideQQuickNavigationRequest could probably go in qt/core/api (called OxideQNavigationRequest), as it seems like the sort of thing that could be shared with a QWidget implementation, should we decide to build one.
- It's not really obvious what shouldFork means, but I think that's probably because it's not really the correct API in chromium for this mechanism. More on that in a bit :)
- It's missing something akin to Chromium's PageTransition, which details what type of navigation it is - I wouldn't expose everything in PageTransition, but I'd probably start by looking at the types currently exposed by QtWebkit's NavigationType.
- It should probably also expose something based on the WindowOpenDisposition - ie, whether this navigation is requested in the current view or whether a new tab or window will be requested. At the moment, we don't handle creating new view's, but I'm currently working on that as part of bug 1240749 and that will also handle anchor elements with target="_blank".
- Whilst the initial implementation should only handle this for top-level frames, it might be prudent to future-proof it by either including a frame property, or perhaps just a boolean property which says whether this navigation is in a top-level frame. QtWebkit currently does the latter, and I think that would be fine.

For the general implementation:
- There are already 2 BrowserMessageFilter's handling single IPC messages. If we're going to add another one, I think that we should probably just merge these in to a single class (perhaps keeping ScriptMessageDispatcherBrowser separate, as that does contain all of the routing logic for script messages, so it's quite a special case). However, we probably don't need this class anyway.

- I'm not sure that ContentRendererClient::ShouldFork() is the right way of doing this. This is really for embedders to state that a navigation should be performed in a new process, rather than asking the embedder whether the navigation should be handled at all.

Currently, when returning true from ShouldFork() (which appears to be the value to reject the navigation), the renderer requests the browser to do the navigation anyway. This doesn't do anything because we don't implement WebContentsDelegate::OpenURLFromTab(), but I think we should.

The way I think this should probably work is:
- We set RendererPreferences::browser_handles_all_top_level_requests to true. This will make RenderFrameImpl::DecidePolicyForNavigation() delegate all top-level navigations to the browser process.
- We implement WebContentsDelegate::OpenURLFromTab() - from here, we can dispatch the onNavigationRequest, and then handle the actual navigation by using NavigationController::LoadURLWithParams(). Y...

Read more...

review: Needs Fixing
Revision history for this message
Chris Coulson (chrisccoulson) wrote :

Olivier, I added you as well just in case you have any feedback, particularly on the API design

lp:~zaspire/oxide/lp_1259219 updated
439. By Olivier Tilloy

Implement the JavaScriptDialogManager interface.

Revision history for this message
Olivier Tilloy (osomon) wrote :

I don’t have much to add to Chris’ thorough review. Just a couple of comments:

 - 'shouldFork' is indeed not self-explanatory as a property name, how about 'accept'? Or an enum instead of a boolean, as is done in QtWebKit?

 - Looking at QtWebKit’s implementation (it looks like it’s not implemented in QtWebEngine yet), the NavigationRequest object exposes more information (besides the 'isMainFrame' property suggested by Chris) including navigation type, mouse buttons and keyboard modifiers. I don’t know how relevant/useful those properties are though, just pointing them out in case we want to expose them too.

 - In OxideQQuickNavigationRequest, the 'url' property could be marked CONSTANT FINAL

lp:~zaspire/oxide/lp_1259219 updated
440. By Maxim Ermilov

add OxideQQuickWebView::navigationRequested

Revision history for this message
Maxim Ermilov (zaspire) wrote :

(branch updated)

Revision history for this message
Chris Coulson (chrisccoulson) wrote :

Thanks for the update. There are still some issues though:

A couple of fairly major ones:
- It looks like this will block navigations if the embedder doesn't implement onNavigationRequested. This seems wrong (and should break some of the existing automated tests too).
- It's not setting LoadURLParams::override_user_agent, meaning that we lose any custom user agent string (even the default that is set by WebContext.userAgent) after the first navigation.
- Setting LoadURLParams::should_replace_current_entry looks wrong. This will result in the new navigation always replacing the current entry in the back/forward list.

In addition to this, I have some other minor comments:
- WebContentsDelegate::OpenURLFromTab should be implemented in oxide::WebView really (then you wouldn't need to expose web_contents_ to derived classes).
- This doesn't address some of my other comments, particularly that the new API should probably go in qt/core/api and it doesn't expose the navigation type or whether the navigation is even going to happen in the current webview. Although, it doesn't look like Chromium gives us the navigation type at the moment, so we could probably leave that for now.

I'll merge this in to https://code.launchpad.net/~chrisccoulson/oxide/window-opening for now and fix up the remaining issues there, as I need this in order to finish off that work

Revision history for this message
Chris Coulson (chrisccoulson) wrote :

Ooh, one other thing I forgot to mention :)

Moving oxide::WebView::web_contents_ results in our reference to its BrowserContext being released before the WebContents is deleted, which results in a use-after-free. There did used to be a comment stating that the order of these members shouldn't be changed, but that seems to have disappeared at some point

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'qt/core/glue/oxide_qt_web_view_adapter.h'
2--- qt/core/glue/oxide_qt_web_view_adapter.h 2014-03-04 15:45:37 +0000
3+++ qt/core/glue/oxide_qt_web_view_adapter.h 2014-03-28 01:21:58 +0000
4@@ -99,6 +99,7 @@
5 virtual void NavigationEntryCommitted() = 0;
6 virtual void NavigationListPruned(bool from_front, int count) = 0;
7 virtual void NavigationEntryChanged(int index) = 0;
8+ virtual bool NavigationRequested(const QString &url) = 0;
9
10 virtual WebFrameAdapter* CreateWebFrame() = 0;
11
12
13=== modified file 'qt/core/glue/private/oxide_qt_web_view_adapter_p.cc'
14--- qt/core/glue/private/oxide_qt_web_view_adapter_p.cc 2014-03-26 21:25:15 +0000
15+++ qt/core/glue/private/oxide_qt_web_view_adapter_p.cc 2014-03-28 01:21:58 +0000
16@@ -22,6 +22,8 @@
17
18 #include "base/strings/utf_string_conversions.h"
19 #include "url/gurl.h"
20+#include "content/public/browser/navigation_controller.h"
21+#include "content/browser/web_contents/web_contents_impl.h"
22
23 #include "qt/core/api/oxideqloadevent.h"
24 #include "qt/core/api/oxideqloadevent_p.h"
25@@ -39,6 +41,29 @@
26 WebViewAdapterPrivate::WebViewAdapterPrivate(WebViewAdapter* adapter) :
27 a(adapter) {}
28
29+content::WebContents* WebViewAdapterPrivate::OpenURLFromTab(content::WebContents* source,
30+ const content::OpenURLParams& p) {
31+ if (a->NavigationRequested(QString::fromStdString(p.url.spec()))) {
32+ content::NavigationController& controller = web_contents_->GetController();
33+
34+ content::NavigationController::LoadURLParams params(p.url);
35+
36+ params.referrer = p.referrer;
37+ params.redirect_chain = p.redirect_chain;
38+ params.should_replace_current_entry = true;
39+ params.is_renderer_initiated = p.is_renderer_initiated;
40+ params.extra_headers = p.extra_headers;
41+ params.transition_type = p.transition;
42+ params.frame_tree_node_id = p.frame_tree_node_id;
43+ controller.LoadURLWithParams(params);
44+
45+ return web_contents_.get();
46+ }
47+
48+ return NULL;
49+}
50+
51+
52 void WebViewAdapterPrivate::OnURLChanged() {
53 a->URLChanged();
54 }
55
56=== modified file 'qt/core/glue/private/oxide_qt_web_view_adapter_p.h'
57--- qt/core/glue/private/oxide_qt_web_view_adapter_p.h 2014-03-04 15:45:37 +0000
58+++ qt/core/glue/private/oxide_qt_web_view_adapter_p.h 2014-03-28 01:21:58 +0000
59@@ -33,6 +33,9 @@
60 public:
61 static WebViewAdapterPrivate* Create(WebViewAdapter* adapter);
62
63+ content::WebContents* OpenURLFromTab(content::WebContents* source,
64+ const content::OpenURLParams& params) OVERRIDE;
65+
66 size_t GetScriptMessageHandlerCount() const FINAL;
67 oxide::ScriptMessageHandler* GetScriptMessageHandlerAt(
68 size_t index) const FINAL;
69
70=== modified file 'qt/quick/api/oxideqquickwebview.cc'
71--- qt/quick/api/oxideqquickwebview.cc 2014-03-20 12:04:34 +0000
72+++ qt/quick/api/oxideqquickwebview.cc 2014-03-28 01:21:58 +0000
73@@ -181,6 +181,15 @@
74 navigationHistory.onNavigationEntryChanged(index);
75 }
76
77+bool OxideQQuickWebViewPrivate::NavigationRequested(const QString &url) {
78+ Q_Q(OxideQQuickWebView);
79+
80+ OxideQQuickNavigationRequest request(url);
81+ emit q->navigationRequested(&request);
82+
83+ return request.accept();
84+}
85+
86 oxide::qt::WebFrameAdapter* OxideQQuickWebViewPrivate::CreateWebFrame() {
87 OxideQQuickWebFrame* frame = new OxideQQuickWebFrame();
88 QQmlEngine::setObjectOwnership(frame, QQmlEngine::CppOwnership);
89
90=== modified file 'qt/quick/api/oxideqquickwebview_p.h'
91--- qt/quick/api/oxideqquickwebview_p.h 2014-03-20 12:04:34 +0000
92+++ qt/quick/api/oxideqquickwebview_p.h 2014-03-28 01:21:58 +0000
93@@ -56,6 +56,30 @@
94 OxideQQuickWebView* view_;
95 };
96
97+class OxideQQuickNavigationRequest: public QObject {
98+ Q_OBJECT
99+ Q_PROPERTY(bool accept READ accept WRITE setAccept)
100+ Q_PROPERTY(QString url READ url)
101+ public:
102+ OxideQQuickNavigationRequest(const QString &url): accept_(false), url_(url) {}
103+
104+ bool accept() {
105+ return accept_;
106+ }
107+ void setAccept(bool value) {
108+ accept_ = value;
109+ }
110+
111+ const QString& url() {
112+ return url_;
113+ }
114+ private:
115+ bool accept_;
116+ const QString url_;
117+};
118+
119+QML_DECLARE_TYPE(OxideQQuickNavigationRequest)
120+
121 class OxideQQuickWebView : public QQuickItem {
122 Q_OBJECT
123 Q_PROPERTY(QUrl url READ url WRITE setUrl NOTIFY urlChanged)
124@@ -144,6 +168,7 @@
125 void urlChanged();
126 void titleChanged();
127 void navigationHistoryChanged();
128+ void navigationRequested(OxideQQuickNavigationRequest *request);
129 void loadingChanged(OxideQLoadEvent* loadEvent);
130 void loadProgressChanged();
131 void rootFrameChanged();
132
133=== modified file 'qt/quick/api/oxideqquickwebview_p_p.h'
134--- qt/quick/api/oxideqquickwebview_p_p.h 2014-03-20 12:04:34 +0000
135+++ qt/quick/api/oxideqquickwebview_p_p.h 2014-03-28 01:21:58 +0000
136@@ -68,6 +68,7 @@
137 void NavigationEntryCommitted() Q_DECL_FINAL;
138 void NavigationListPruned(bool from_front, int count) Q_DECL_FINAL;
139 void NavigationEntryChanged(int index) Q_DECL_FINAL;
140+ bool NavigationRequested(const QString &url) Q_DECL_FINAL;
141
142 oxide::qt::WebFrameAdapter* CreateWebFrame() Q_DECL_FINAL;
143
144
145=== modified file 'qt/quick/oxide_qml_plugin.cc'
146--- qt/quick/oxide_qml_plugin.cc 2014-03-17 15:59:29 +0000
147+++ qt/quick/oxide_qml_plugin.cc 2014-03-28 01:21:58 +0000
148@@ -70,6 +70,8 @@
149 qmlRegisterType<OxideQQuickWebContext>(uri, 0, 1, "WebContext");
150 qmlRegisterUncreatableType<OxideQQuickNavigationHistory>(uri, 0, 1, "NavigationHistory",
151 "Each WebView has a NavigationHistory automatically instantiated by Oxide");
152+ qmlRegisterUncreatableType<OxideQQuickNavigationRequest>(uri, 0, 1, "NavigationRequest",
153+ "Cannot create separate instance of NavigationRequest");
154 qmlRegisterType<OxideQWebPreferences>(uri, 0, 1, "WebPreferences");
155 qmlRegisterType<OxideQQuickWebView>(uri, 0, 1, "WebView");
156 qmlRegisterType<OxideQQuickWebContextDelegateWorker>(uri, 0, 1, "WebContextDelegateWorker");
157
158=== added file 'qt/tests/qmltests/api/tst_WebView_navigation_request.qml'
159--- qt/tests/qmltests/api/tst_WebView_navigation_request.qml 1970-01-01 00:00:00 +0000
160+++ qt/tests/qmltests/api/tst_WebView_navigation_request.qml 2014-03-28 01:21:58 +0000
161@@ -0,0 +1,59 @@
162+import QtQuick 2.0
163+import QtTest 1.0
164+import com.canonical.Oxide 0.1
165+import com.canonical.Oxide.Testing 0.1
166+
167+TestWebView {
168+ id: webView
169+ focus: true
170+ width: 200
171+ height: 200
172+
173+ SignalSpy {
174+ id: spy
175+ target: webView
176+ signalName: "navigationHistoryChanged"
177+ }
178+
179+ SignalSpy {
180+ id: urlSpy
181+ target: webView
182+ signalName: "urlChanged"
183+ }
184+
185+ onNavigationRequested: {
186+ request.accept = false;
187+ }
188+
189+ TestCase {
190+ id: test
191+ name: "WebView_navigation_request"
192+ when: windowShown
193+
194+ function init() {
195+ spy.clear();
196+ }
197+
198+ readonly property var initData: [
199+ { url: "http://localhost:8080/tst_WebView_navigation_request1.html", index: 0 }
200+ ]
201+
202+ function test_WebView_navigation_request1_init_data() {
203+ return initData;
204+ }
205+
206+ function test_WebView_navigation_request1_init(data) {
207+ webView.url = data.url;
208+
209+ verify(webView.waitForLoadSucceeded(),
210+ "Timed out waiting for load to finish");
211+
212+ compare(webView.url, data.url,
213+ "WebView.url is invalid after load");
214+ webView.waitForLoadSucceeded();
215+ compare(webView.url, data.url,
216+ "navigation request should be ignored");
217+ }
218+
219+ }
220+}
221
222=== added file 'qt/tests/qmltests/api/tst_WebView_navigation_request1.html'
223--- qt/tests/qmltests/api/tst_WebView_navigation_request1.html 1970-01-01 00:00:00 +0000
224+++ qt/tests/qmltests/api/tst_WebView_navigation_request1.html 2014-03-28 01:21:58 +0000
225@@ -0,0 +1,12 @@
226+<html>
227+<head>
228+ <title>Navigation test 1</title>
229+</head>
230+<body>
231+<script type="text/javascript">
232+ open('http://google.com', '_self');
233+</script>
234+
235+ <h1>Navigation test 1</h1>
236+</body>
237+</html>
238
239=== modified file 'shared/browser/oxide_web_view.cc'
240--- shared/browser/oxide_web_view.cc 2014-03-26 21:10:42 +0000
241+++ shared/browser/oxide_web_view.cc 2014-03-28 01:21:58 +0000
242@@ -339,6 +339,8 @@
243 // HttpUserAgentSettings::GetUserAgent()
244 web_contents_->SetUserAgentOverride(context->GetUserAgent());
245
246+ web_contents_->GetMutableRendererPrefs()->browser_handles_non_local_top_level_requests = true;
247+
248 registrar_.Add(this, content::NOTIFICATION_NAV_LIST_PRUNED,
249 content::NotificationService::AllBrowserContextsAndSources());
250 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_CHANGED,
251
252=== modified file 'shared/browser/oxide_web_view.h'
253--- shared/browser/oxide_web_view.h 2014-03-26 21:10:42 +0000
254+++ shared/browser/oxide_web_view.h 2014-03-28 01:21:58 +0000
255@@ -144,6 +144,7 @@
256 protected:
257 WebView();
258
259+ scoped_ptr<content::WebContentsImpl> web_contents_;
260 private:
261 void DispatchLoadFailed(const GURL& validated_url,
262 int error_code,
263@@ -248,7 +249,6 @@
264 virtual WebPopupMenu* CreatePopupMenu(content::RenderViewHost* rvh);
265
266 ScopedBrowserContext context_;
267- scoped_ptr<content::WebContentsImpl> web_contents_;
268 content::NotificationRegistrar registrar_;
269 scoped_ptr<WebFrame> root_frame_;
270 base::WeakPtr<WebPopupMenu> active_popup_menu_;

Subscribers

People subscribed via source and target branches