OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "extensions/browser/guest_view/web_view/web_view_guest.h" | 5 #include "extensions/browser/guest_view/web_view/web_view_guest.h" |
6 | 6 |
7 #include "base/message_loop/message_loop.h" | 7 #include "base/message_loop/message_loop.h" |
8 #include "base/strings/stringprintf.h" | 8 #include "base/strings/stringprintf.h" |
9 #include "base/strings/utf_string_conversions.h" | 9 #include "base/strings/utf_string_conversions.h" |
10 #include "content/public/browser/browser_context.h" | 10 #include "content/public/browser/browser_context.h" |
(...skipping 857 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
868 return &javascript_dialog_helper_; | 868 return &javascript_dialog_helper_; |
869 } | 869 } |
870 | 870 |
871 void WebViewGuest::NavigateGuest(const std::string& src, | 871 void WebViewGuest::NavigateGuest(const std::string& src, |
872 bool force_navigation) { | 872 bool force_navigation) { |
873 if (src.empty()) | 873 if (src.empty()) |
874 return; | 874 return; |
875 | 875 |
876 GURL url = ResolveURL(src); | 876 GURL url = ResolveURL(src); |
877 | 877 |
878 // Do not allow navigating a guest to schemes other than known safe schemes. | 878 LoadURLWithParams(url, content::Referrer(), |
879 // This will block the embedder trying to load unwanted schemes, e.g. | |
880 // chrome://settings. | |
881 bool scheme_is_blocked = | |
882 (!content::ChildProcessSecurityPolicy::GetInstance()->IsWebSafeScheme( | |
883 url.scheme()) && | |
884 !url.SchemeIs(url::kAboutScheme)) || | |
885 url.SchemeIs(url::kJavaScriptScheme); | |
886 if (scheme_is_blocked || !url.is_valid()) { | |
887 LoadAbort(true /* is_top_level */, url, | |
888 net::ErrorToShortString(net::ERR_ABORTED)); | |
889 NavigateGuest(url::kAboutBlankURL, true /* force_navigation */); | |
890 return; | |
891 } | |
892 if (!force_navigation && (src_ == url)) | |
893 return; | |
894 | |
895 GURL validated_url(url); | |
896 web_contents()->GetRenderProcessHost()->FilterURL(false, &validated_url); | |
897 // As guests do not swap processes on navigation, only navigations to | |
898 // normal web URLs are supported. No protocol handlers are installed for | |
899 // other schemes (e.g., WebUI or extensions), and no permissions or bindings | |
900 // can be granted to the guest process. | |
901 LoadURLWithParams(validated_url, | |
902 content::Referrer(), | |
903 ui::PAGE_TRANSITION_AUTO_TOPLEVEL, | 879 ui::PAGE_TRANSITION_AUTO_TOPLEVEL, |
904 web_contents()); | 880 force_navigation); |
905 | |
906 src_ = validated_url; | |
907 } | 881 } |
908 | 882 |
909 bool WebViewGuest::HandleKeyboardShortcuts( | 883 bool WebViewGuest::HandleKeyboardShortcuts( |
910 const content::NativeWebKeyboardEvent& event) { | 884 const content::NativeWebKeyboardEvent& event) { |
911 // <webview> outside of Chrome Apps do not handle keyboard shortcuts. | 885 // <webview> outside of Chrome Apps do not handle keyboard shortcuts. |
912 if (!in_extension()) | 886 if (!in_extension()) |
913 return false; | 887 return false; |
914 | 888 |
915 if (event.type != blink::WebInputEvent::RawKeyDown) | 889 if (event.type != blink::WebInputEvent::RawKeyDown) |
916 return false; | 890 return false; |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1111 *was_blocked = false; | 1085 *was_blocked = false; |
1112 RequestNewWindowPermission(disposition, | 1086 RequestNewWindowPermission(disposition, |
1113 initial_rect, | 1087 initial_rect, |
1114 user_gesture, | 1088 user_gesture, |
1115 new_contents); | 1089 new_contents); |
1116 } | 1090 } |
1117 | 1091 |
1118 content::WebContents* WebViewGuest::OpenURLFromTab( | 1092 content::WebContents* WebViewGuest::OpenURLFromTab( |
1119 content::WebContents* source, | 1093 content::WebContents* source, |
1120 const content::OpenURLParams& params) { | 1094 const content::OpenURLParams& params) { |
1095 // There are two use cases to consider from a security perspective: | |
1096 // 1.) Renderer-initiated navigation to chrome:// must always be blocked even | |
1097 // if the <webview> is in WebUI. This is handled by | |
1098 // WebViewGuest::LoadURLWithParams. WebViewGuest::NavigateGuest will also | |
1099 // call LoadURLWithParams. CreateNewGuestWebViewWindow creates a new | |
1100 // WebViewGuest which will call NavigateGuest in DidInitialize. | |
1101 // 2.) The Language Settings context menu item should always work, both in | |
1102 // Chrome Apps and WebUI. This is a browser initiated request and so | |
1103 // we pass it along to the embedder's WebContentsDelegate to get the | |
1104 // browser to perform the action for the <webview>. | |
1105 if (!params.is_renderer_initiated) { | |
1106 if (!owner_web_contents()->GetDelegate()) | |
1107 return nullptr; | |
1108 return owner_web_contents()->GetDelegate()->OpenURLFromTab( | |
1109 owner_web_contents(), params); | |
1110 } | |
1111 | |
1121 // If the guest wishes to navigate away prior to attachment then we save the | 1112 // If the guest wishes to navigate away prior to attachment then we save the |
1122 // navigation to perform upon attachment. Navigation initializes a lot of | 1113 // navigation to perform upon attachment. Navigation initializes a lot of |
1123 // state that assumes an embedder exists, such as RenderWidgetHostViewGuest. | 1114 // state that assumes an embedder exists, such as RenderWidgetHostViewGuest. |
1124 // Navigation also resumes resource loading which we don't want to allow | 1115 // Navigation also resumes resource loading which we don't want to allow |
1125 // until attachment. | 1116 // until attachment. |
1126 if (!attached()) { | 1117 if (!attached()) { |
1127 WebViewGuest* opener = GetOpener(); | 1118 WebViewGuest* opener = GetOpener(); |
1128 auto it = opener->pending_new_windows_.find(this); | 1119 auto it = opener->pending_new_windows_.find(this); |
1129 if (it == opener->pending_new_windows_.end()) | 1120 if (it == opener->pending_new_windows_.end()) |
1130 return nullptr; | 1121 return nullptr; |
1131 const NewWindowInfo& info = it->second; | 1122 const NewWindowInfo& info = it->second; |
1132 NewWindowInfo new_window_info(params.url, info.name); | 1123 NewWindowInfo new_window_info(params.url, info.name); |
1133 new_window_info.changed = new_window_info.url != info.url; | 1124 new_window_info.changed = new_window_info.url != info.url; |
1134 it->second = new_window_info; | 1125 it->second = new_window_info; |
1135 return nullptr; | 1126 return nullptr; |
1136 } | 1127 } |
1128 | |
1129 // This code path is taken if RenderFrameImpl::DecidePolicyForNavigation | |
1130 // decides that a fork should happen. At the time of writing this comment, | |
1131 // the only way a well behaving guest could hit this code path is if it | |
1132 // navigates to a URL that's associated with the default search engine. | |
1133 // This list of URLs is generated by chrome::GetSearchURLs. Validity checks | |
1134 // are performed inside LoadURLWithParams such that if the guest attempts | |
1135 // to navigate to a URL that it is not allowed to navigate to, a 'loadabort' | |
1136 // event will fire in the embedder, and the guest will be navigated to | |
1137 // about:blank. | |
1137 if (params.disposition == CURRENT_TAB) { | 1138 if (params.disposition == CURRENT_TAB) { |
1138 // This can happen for cross-site redirects. | 1139 LoadURLWithParams(params.url, params.referrer, params.transition, |
1139 LoadURLWithParams(params.url, params.referrer, params.transition, source); | 1140 true /* force_navigation */); |
1140 return source; | 1141 return web_contents(); |
1141 } | 1142 } |
1142 | 1143 |
1144 // This code path is taken if Ctrl+Click, middle click or any of the | |
1145 // keyboard/mouse combinations are used to open a link in a new tab/window. | |
1146 // This code path is also taken on client-side redirects from about:blank. | |
1143 CreateNewGuestWebViewWindow(params); | 1147 CreateNewGuestWebViewWindow(params); |
1144 return nullptr; | 1148 return nullptr; |
1145 } | 1149 } |
1146 | 1150 |
1147 void WebViewGuest::WebContentsCreated(WebContents* source_contents, | 1151 void WebViewGuest::WebContentsCreated(WebContents* source_contents, |
1148 int opener_render_frame_id, | 1152 int opener_render_frame_id, |
1149 const base::string16& frame_name, | 1153 const base::string16& frame_name, |
1150 const GURL& target_url, | 1154 const GURL& target_url, |
1151 content::WebContents* new_contents) { | 1155 content::WebContents* new_contents) { |
1152 auto guest = WebViewGuest::FromWebContents(new_contents); | 1156 auto guest = WebViewGuest::FromWebContents(new_contents); |
1153 CHECK(guest); | 1157 CHECK(guest); |
1154 guest->SetOpener(this); | 1158 guest->SetOpener(this); |
1155 std::string guest_name = base::UTF16ToUTF8(frame_name); | 1159 std::string guest_name = base::UTF16ToUTF8(frame_name); |
1156 guest->name_ = guest_name; | 1160 guest->name_ = guest_name; |
1157 pending_new_windows_.insert( | 1161 pending_new_windows_.insert( |
1158 std::make_pair(guest, NewWindowInfo(target_url, guest_name))); | 1162 std::make_pair(guest, NewWindowInfo(target_url, guest_name))); |
1159 } | 1163 } |
1160 | 1164 |
1161 void WebViewGuest::LoadURLWithParams(const GURL& url, | 1165 void WebViewGuest::LoadURLWithParams(const GURL& url, |
1162 const content::Referrer& referrer, | 1166 const content::Referrer& referrer, |
1163 ui::PageTransition transition_type, | 1167 ui::PageTransition transition_type, |
1164 content::WebContents* web_contents) { | 1168 bool force_navigation) { |
1165 content::NavigationController::LoadURLParams load_url_params(url); | 1169 // Do not allow navigating a guest to schemes other than known safe schemes. |
1170 // This will block the embedder trying to load unwanted schemes, e.g. | |
1171 // chrome://settings. | |
Charlie Reis
2015/02/19 22:56:28
nit: chrome://
(settings isn't part of the scheme)
Fady Samuel
2015/02/20 00:33:06
Done.
| |
1172 bool scheme_is_blocked = | |
1173 (!content::ChildProcessSecurityPolicy::GetInstance()->IsWebSafeScheme( | |
1174 url.scheme()) && | |
1175 !url.SchemeIs(url::kAboutScheme)) || | |
1176 url.SchemeIs(url::kJavaScriptScheme); | |
1177 if (scheme_is_blocked || !url.is_valid()) { | |
1178 LoadAbort(true /* is_top_level */, url, | |
1179 net::ErrorToShortString(net::ERR_ABORTED)); | |
1180 NavigateGuest(url::kAboutBlankURL, true /* force_navigation */); | |
1181 return; | |
1182 } | |
1183 | |
1184 if (!force_navigation && (src_ == url)) | |
1185 return; | |
1186 | |
1187 GURL validated_url(url); | |
1188 web_contents()->GetRenderProcessHost()->FilterURL(false, &validated_url); | |
1189 // As guests do not swap processes on navigation, only navigations to | |
1190 // normal web URLs are supported. No protocol handlers are installed for | |
1191 // other schemes (e.g., WebUI or extensions), and no permissions or bindings | |
1192 // can be granted to the guest process. | |
1193 content::NavigationController::LoadURLParams load_url_params(validated_url); | |
1166 load_url_params.referrer = referrer; | 1194 load_url_params.referrer = referrer; |
1167 load_url_params.transition_type = transition_type; | 1195 load_url_params.transition_type = transition_type; |
1168 load_url_params.extra_headers = std::string(); | 1196 load_url_params.extra_headers = std::string(); |
1169 if (is_overriding_user_agent_) { | 1197 if (is_overriding_user_agent_) { |
1170 load_url_params.override_user_agent = | 1198 load_url_params.override_user_agent = |
1171 content::NavigationController::UA_OVERRIDE_TRUE; | 1199 content::NavigationController::UA_OVERRIDE_TRUE; |
1172 } | 1200 } |
1173 web_contents->GetController().LoadURLWithParams(load_url_params); | 1201 web_contents()->GetController().LoadURLWithParams(load_url_params); |
1202 | |
1203 src_ = validated_url; | |
1174 } | 1204 } |
1175 | 1205 |
1176 void WebViewGuest::RequestNewWindowPermission( | 1206 void WebViewGuest::RequestNewWindowPermission( |
1177 WindowOpenDisposition disposition, | 1207 WindowOpenDisposition disposition, |
1178 const gfx::Rect& initial_bounds, | 1208 const gfx::Rect& initial_bounds, |
1179 bool user_gesture, | 1209 bool user_gesture, |
1180 content::WebContents* new_contents) { | 1210 content::WebContents* new_contents) { |
1181 auto guest = WebViewGuest::FromWebContents(new_contents); | 1211 auto guest = WebViewGuest::FromWebContents(new_contents); |
1182 if (!guest) | 1212 if (!guest) |
1183 return; | 1213 return; |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1232 WebViewGuest::From(owner_web_contents()->GetRenderProcessHost()->GetID(), | 1262 WebViewGuest::From(owner_web_contents()->GetRenderProcessHost()->GetID(), |
1233 new_window_instance_id); | 1263 new_window_instance_id); |
1234 if (!guest) | 1264 if (!guest) |
1235 return; | 1265 return; |
1236 | 1266 |
1237 if (!allow) | 1267 if (!allow) |
1238 guest->Destroy(); | 1268 guest->Destroy(); |
1239 } | 1269 } |
1240 | 1270 |
1241 } // namespace extensions | 1271 } // namespace extensions |
OLD | NEW |