Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(561)

Side by Side Diff: chrome_frame/chrome_frame_activex.cc

Issue 218019: Initial import of the Chrome Frame codebase. Integration in chrome.gyp coming... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 11 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome_frame/chrome_frame_activex.h ('k') | chrome_frame/chrome_frame_activex.rgs » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome_frame/chrome_frame_activex.h"
6
7 #include <shdeprecated.h> // for IBrowserService2
8 #include <wininet.h>
9
10 #include <algorithm>
11
12 #include "base/basictypes.h"
13 #include "base/command_line.h"
14 #include "base/file_util.h"
15 #include "base/logging.h"
16 #include "base/path_service.h"
17 #include "base/process_util.h"
18 #include "base/scoped_bstr_win.h"
19 #include "base/string_util.h"
20 #include "chrome/common/chrome_constants.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "chrome/test/automation/tab_proxy.h"
23 #include "googleurl/src/gurl.h"
24 #include "chrome_frame/com_message_event.h"
25 #include "chrome_frame/utils.h"
26
27 ChromeFrameActivex::ChromeFrameActivex() {
28 }
29
30 HRESULT ChromeFrameActivex::FinalConstruct() {
31 HRESULT hr = Base::FinalConstruct();
32 if (FAILED(hr))
33 return hr;
34
35 // No need to call FireOnChanged at this point since nobody will be listening.
36 ready_state_ = READYSTATE_LOADING;
37 return S_OK;
38 }
39
40 ChromeFrameActivex::~ChromeFrameActivex() {
41 // We expect these to be released during a call to SetClientSite(NULL).
42 DCHECK(onmessage_.size() == 0);
43 DCHECK(onloaderror_.size() == 0);
44 DCHECK(onload_.size() == 0);
45 DCHECK(onreadystatechanged_.size() == 0);
46 }
47
48 LRESULT ChromeFrameActivex::OnCreate(UINT message, WPARAM wparam, LPARAM lparam,
49 BOOL& handled) {
50 Base::OnCreate(message, wparam, lparam, handled);
51 return 0;
52 }
53
54 void ChromeFrameActivex::OnAcceleratorPressed(int tab_handle,
55 const MSG& accel_message) {
56 DCHECK(m_spInPlaceSite != NULL);
57 // Allow our host a chance to handle the accelerator.
58 // This catches things like Ctrl+F, Ctrl+O etc, but not browser
59 // accelerators such as F11, Ctrl+T etc.
60 // (see AllowFrameToTranslateAccelerator for those).
61 HRESULT hr = TranslateAccelerator(const_cast<MSG*>(&accel_message));
62 if (hr != S_OK)
63 hr = AllowFrameToTranslateAccelerator(accel_message);
64
65 DLOG(INFO) << __FUNCTION__ << " browser response: "
66 << StringPrintf("0x%08x", hr);
67
68 // Last chance to handle the keystroke is to pass it to chromium.
69 // We do this last partially because there's no way for us to tell if
70 // chromium actually handled the keystroke, but also since the browser
71 // should have first dibs anyway.
72 if (hr != S_OK && automation_client_.get()) {
73 TabProxy* tab = automation_client_->tab();
74 if (tab) {
75 tab->ProcessUnhandledAccelerator(accel_message);
76 }
77 }
78 }
79
80 HRESULT ChromeFrameActivex::GetContainingDocument(IHTMLDocument2** doc) {
81 ScopedComPtr<IOleContainer> container;
82 HRESULT hr = m_spClientSite->GetContainer(container.Receive());
83 if (container)
84 hr = container.QueryInterface(doc);
85 return hr;
86 }
87
88 HRESULT ChromeFrameActivex::GetDocumentWindow(IHTMLWindow2** window) {
89 ScopedComPtr<IHTMLDocument2> document;
90 HRESULT hr = GetContainingDocument(document.Receive());
91 if (document)
92 hr = document->get_parentWindow(window);
93 return hr;
94 }
95
96 void ChromeFrameActivex::OnLoad(int tab_handle, const GURL& gurl) {
97 ScopedComPtr<IDispatch> event;
98 std::string url = gurl.spec();
99 if (SUCCEEDED(CreateDomEvent("event", url, "", event.Receive())))
100 Fire_onload(event);
101
102 FireEvent(onload_, url);
103
104 HRESULT hr = InvokeScriptFunction(onload_handler_, url);
105
106 if (ready_state_ < READYSTATE_COMPLETE) {
107 ready_state_ = READYSTATE_COMPLETE;
108 FireOnChanged(DISPID_READYSTATE);
109 }
110 }
111
112 void ChromeFrameActivex::OnLoadFailed(int error_code, const std::string& url) {
113 ScopedComPtr<IDispatch> event;
114 if (SUCCEEDED(CreateDomEvent("event", url, "", event.Receive())))
115 Fire_onloaderror(event);
116
117 FireEvent(onloaderror_, url);
118
119 HRESULT hr = InvokeScriptFunction(onerror_handler_, url);
120 }
121
122 void ChromeFrameActivex::OnMessageFromChromeFrame(int tab_handle,
123 const std::string& message,
124 const std::string& origin,
125 const std::string& target) {
126 DLOG(INFO) << __FUNCTION__;
127
128 if (target.compare("*") != 0) {
129 bool drop = true;
130
131 if (is_privileged_) {
132 // Forward messages if the control is in privileged mode.
133 ScopedComPtr<IDispatch> message_event;
134 if (SUCCEEDED(CreateDomEvent("message", message, origin,
135 message_event.Receive()))) {
136 ScopedBstr target_bstr(UTF8ToWide(target).c_str());
137 Fire_onprivatemessage(message_event, target_bstr);
138
139 FireEvent(onprivatemessage_, message_event, target_bstr);
140 }
141 } else {
142 if (HaveSameOrigin(target, document_url_)) {
143 drop = false;
144 } else {
145 DLOG(WARNING) << "Dropping posted message since target doesn't match "
146 "the current document's origin. target=" << target;
147 }
148 }
149
150 if (drop)
151 return;
152 }
153
154 ScopedComPtr<IDispatch> message_event;
155 if (SUCCEEDED(CreateDomEvent("message", message, origin,
156 message_event.Receive()))) {
157 Fire_onmessage(message_event);
158
159 FireEvent(onmessage_, message_event);
160
161 ScopedVariant event_var;
162 event_var.Set(static_cast<IDispatch*>(message_event));
163 InvokeScriptFunction(onmessage_handler_, event_var.AsInput());
164 }
165 }
166
167 void ChromeFrameActivex::OnAutomationServerLaunchFailed(
168 AutomationLaunchResult reason, const std::string& server_version) {
169 Base::OnAutomationServerLaunchFailed(reason, server_version);
170
171 if (reason == AUTOMATION_VERSION_MISMATCH) {
172 DisplayVersionMismatchWarning(m_hWnd, server_version);
173 }
174 }
175
176 HRESULT ChromeFrameActivex::InvokeScriptFunction(const VARIANT& script_object,
177 const std::string& param) {
178 ScopedVariant script_arg(UTF8ToWide(param.c_str()).c_str());
179 return InvokeScriptFunction(script_object, script_arg.AsInput());
180 }
181
182 HRESULT ChromeFrameActivex::InvokeScriptFunction(const VARIANT& script_object,
183 VARIANT* param) {
184 if (V_VT(&script_object) != VT_DISPATCH) {
185 return S_FALSE;
186 }
187
188 CComPtr<IDispatch> script(script_object.pdispVal);
189 HRESULT hr = script.Invoke1(static_cast<DISPID>(DISPID_VALUE), param);
190 // 0x80020101 == SCRIPT_E_REPORTED.
191 // When the script we're invoking has an error, we get this error back.
192 DLOG_IF(ERROR, FAILED(hr) && hr != 0x80020101) << "Failed to invoke script";
193
194 return hr;
195 }
196
197 HRESULT ChromeFrameActivex::OnDraw(ATL_DRAWINFO& draw_info) { // NO_LINT
198 HRESULT hr = S_OK;
199 int dc_type = ::GetObjectType(draw_info.hicTargetDev);
200 if (dc_type == OBJ_ENHMETADC) {
201 RECT print_bounds = {0};
202 print_bounds.left = draw_info.prcBounds->left;
203 print_bounds.right = draw_info.prcBounds->right;
204 print_bounds.top = draw_info.prcBounds->top;
205 print_bounds.bottom = draw_info.prcBounds->bottom;
206
207 automation_client_->Print(draw_info.hdcDraw, print_bounds);
208 } else {
209 hr = Base::OnDraw(draw_info);
210 }
211
212 return hr;
213 }
214
215 STDMETHODIMP ChromeFrameActivex::Load(IPropertyBag* bag, IErrorLog* error_log) {
216 DCHECK(bag);
217
218 const wchar_t* event_props[] = {
219 (L"onload"),
220 (L"onloaderror"),
221 (L"onmessage"),
222 (L"onreadystatechanged"),
223 };
224
225 ScopedComPtr<IHTMLObjectElement> obj_element;
226 GetObjectElement(obj_element.Receive());
227
228 ScopedBstr object_id;
229 GetObjectScriptId(obj_element, object_id.Receive());
230
231 ScopedComPtr<IHTMLElement2> element;
232 element.QueryFrom(obj_element);
233 HRESULT hr = S_OK;
234
235 for (int i = 0; SUCCEEDED(hr) && i < arraysize(event_props); ++i) {
236 ScopedBstr prop(event_props[i]);
237 ScopedVariant value;
238 if (SUCCEEDED(bag->Read(prop, value.Receive(), error_log))) {
239 if (value.type() != VT_BSTR ||
240 FAILED(hr = CreateScriptBlockForEvent(element, object_id,
241 V_BSTR(&value), prop))) {
242 DLOG(ERROR) << "Failed to create script block for " << prop
243 << StringPrintf(L"hr=0x%08X, vt=%i", hr, value.type());
244 } else {
245 DLOG(INFO) << "script block created for event " << prop <<
246 StringPrintf(" (0x%08X)", hr) << " connections: " <<
247 ProxyDIChromeFrameEvents<ChromeFrameActivex>::m_vec.GetSize();
248 }
249 } else {
250 DLOG(INFO) << "event property " << prop << " not in property bag";
251 }
252 }
253
254 ScopedVariant src;
255 if (SUCCEEDED(bag->Read(StackBstr(L"src"), src.Receive(), error_log))) {
256 if (src.type() == VT_BSTR) {
257 hr = put_src(V_BSTR(&src));
258 DCHECK(hr != E_UNEXPECTED);
259 }
260 }
261
262 ScopedVariant use_chrome_network;
263 if (SUCCEEDED(bag->Read(StackBstr(L"useChromeNetwork"),
264 use_chrome_network.Receive(), error_log))) {
265 VariantChangeType(use_chrome_network.AsInput(),
266 use_chrome_network.AsInput(),
267 0, VT_BOOL);
268 if (use_chrome_network.type() == VT_BOOL) {
269 hr = put_useChromeNetwork(V_BOOL(&use_chrome_network));
270 DCHECK(hr != E_UNEXPECTED);
271 }
272 }
273
274 DLOG_IF(ERROR, FAILED(hr))
275 << StringPrintf("Failed to load property bag: 0x%08X", hr);
276
277 return hr;
278 }
279
280 const wchar_t g_activex_mixed_content_error[] = {
281 L"data:text/html,<html><body><b>ChromeFrame Security Error<br><br>"
282 L"Cannot navigate to HTTP url when document URL is HTTPS</body></html>"};
283
284 STDMETHODIMP ChromeFrameActivex::put_src(BSTR src) {
285 GURL document_url(GetDocumentUrl());
286 if (document_url.SchemeIsSecure()) {
287 GURL source_url(src);
288 if (!source_url.SchemeIsSecure()) {
289 Base::put_src(ScopedBstr(g_activex_mixed_content_error));
290 return E_ACCESSDENIED;
291 }
292 }
293 return Base::put_src(src);
294 }
295
296 HRESULT ChromeFrameActivex::IOleObject_SetClientSite(
297 IOleClientSite* client_site) {
298 HRESULT hr = Base::IOleObject_SetClientSite(client_site);
299 if (FAILED(hr) || !client_site) {
300 EventHandlers* handlers[] = {
301 &onmessage_,
302 &onloaderror_,
303 &onload_,
304 &onreadystatechanged_,
305 };
306
307 for (int i = 0; i < arraysize(handlers); ++i)
308 handlers[i]->clear();
309
310 // Drop privileged mode on uninitialization.
311 is_privileged_ = false;
312 } else {
313 ScopedComPtr<IHTMLDocument2> document;
314 GetContainingDocument(document.Receive());
315 if (document) {
316 ScopedBstr url;
317 if (SUCCEEDED(document->get_URL(url.Receive())))
318 WideToUTF8(url, url.Length(), &document_url_);
319 }
320
321 // Probe to see whether the host implements the privileged service.
322 ScopedComPtr<IChromeFramePrivileged> service;
323 HRESULT service_hr = DoQueryService(SID_ChromeFramePrivileged, client_site,
324 service.Receive());
325 if (SUCCEEDED(service_hr) && service) {
326 // Does the host want privileged mode?
327 boolean wants_privileged = false;
328 service_hr = service->GetWantsPrivileged(&wants_privileged);
329
330 if (SUCCEEDED(service_hr) && wants_privileged)
331 is_privileged_ = true;
332 }
333
334 std::wstring chrome_extra_arguments;
335 std::wstring profile_name(GetHostProcessName(false));
336 if (is_privileged_) {
337 // Does the host want to provide extra arguments?
338 ScopedBstr extra_arguments_arg;
339 service_hr = service->GetChromeExtraArguments(
340 extra_arguments_arg.Receive());
341 if (S_OK == service_hr && extra_arguments_arg)
342 chrome_extra_arguments.assign(extra_arguments_arg,
343 extra_arguments_arg.Length());
344
345 ScopedBstr profile_name_arg;
346 service_hr = service->GetChromeProfileName(profile_name_arg.Receive());
347 if (S_OK == service_hr && profile_name_arg)
348 profile_name.assign(profile_name_arg, profile_name_arg.Length());
349 }
350
351 if (!InitializeAutomation(profile_name, chrome_extra_arguments,
352 IsIEInPrivate())) {
353 return E_FAIL;
354 }
355 }
356
357 return hr;
358 }
359
360 HRESULT ChromeFrameActivex::GetObjectScriptId(IHTMLObjectElement* object_elem,
361 BSTR* id) {
362 DCHECK(object_elem != NULL);
363 DCHECK(id != NULL);
364
365 HRESULT hr = E_FAIL;
366 if (object_elem) {
367 ScopedComPtr<IHTMLElement> elem;
368 hr = elem.QueryFrom(object_elem);
369 if (elem) {
370 hr = elem->get_id(id);
371 }
372 }
373
374 return hr;
375 }
376
377 HRESULT ChromeFrameActivex::GetObjectElement(IHTMLObjectElement** element) {
378 DCHECK(m_spClientSite);
379 if (!m_spClientSite)
380 return E_UNEXPECTED;
381
382 ScopedComPtr<IOleControlSite> site;
383 HRESULT hr = site.QueryFrom(m_spClientSite);
384 if (site) {
385 ScopedComPtr<IDispatch> disp;
386 hr = site->GetExtendedControl(disp.Receive());
387 if (disp) {
388 hr = disp.QueryInterface(element);
389 } else {
390 DCHECK(FAILED(hr));
391 }
392 }
393
394 return hr;
395 }
396
397 HRESULT ChromeFrameActivex::CreateScriptBlockForEvent(
398 IHTMLElement2* insert_after, BSTR instance_id, BSTR script,
399 BSTR event_name) {
400 DCHECK(insert_after);
401 DCHECK(::SysStringLen(event_name) > 0); // should always have this
402
403 // This might be 0 if not specified in the HTML document.
404 if (!::SysStringLen(instance_id)) {
405 // TODO(tommi): Should we give ourselves an ID if this happens?
406 NOTREACHED() << "Need to handle this";
407 return E_INVALIDARG;
408 }
409
410 ScopedComPtr<IHTMLDocument2> document;
411 HRESULT hr = GetContainingDocument(document.Receive());
412 if (SUCCEEDED(hr)) {
413 ScopedComPtr<IHTMLElement> element, new_element;
414 document->createElement(StackBstr(L"script"), element.Receive());
415 if (element) {
416 ScopedComPtr<IHTMLScriptElement> script_element;
417 if (SUCCEEDED(hr = script_element.QueryFrom(element))) {
418 script_element->put_htmlFor(instance_id);
419 script_element->put_event(event_name);
420 script_element->put_text(script);
421
422 hr = insert_after->insertAdjacentElement(StackBstr(L"afterEnd"),
423 element,
424 new_element.Receive());
425 }
426 }
427 }
428
429 return hr;
430 }
431
432 HRESULT ChromeFrameActivex::CreateDomEvent(const std::string& event_type,
433 const std::string& data,
434 const std::string& origin,
435 IDispatch** event) {
436 DCHECK(event_type.length() > 0);
437 DCHECK(event != NULL);
438
439 CComObject<ComMessageEvent>* ev = NULL;
440 HRESULT hr = CComObject<ComMessageEvent>::CreateInstance(&ev);
441 if (SUCCEEDED(hr)) {
442 ev->AddRef();
443
444 ScopedComPtr<IOleContainer> container;
445 m_spClientSite->GetContainer(container.Receive());
446 if (ev->Initialize(container, data, origin, event_type)) {
447 *event = ev;
448 } else {
449 NOTREACHED() << "event->Initialize";
450 ev->Release();
451 hr = E_UNEXPECTED;
452 }
453 }
454
455 return hr;
456 }
457
458 void ChromeFrameActivex::FireEvent(const EventHandlers& handlers,
459 const std::string& arg) {
460 if (handlers.size()) {
461 ScopedComPtr<IDispatch> event;
462 if (SUCCEEDED(CreateDomEvent("event", arg, "", event.Receive()))) {
463 FireEvent(handlers, event);
464 }
465 }
466 }
467
468 void ChromeFrameActivex::FireEvent(const EventHandlers& handlers,
469 IDispatch* event) {
470 DCHECK(event != NULL);
471 VARIANT arg = { VT_DISPATCH };
472 arg.pdispVal = event;
473 DISPPARAMS params = { &arg, NULL, 1, 0 };
474 for (EventHandlers::const_iterator it = handlers.begin();
475 it != handlers.end();
476 ++it) {
477 HRESULT hr = (*it)->Invoke(DISPID_VALUE, IID_NULL, LOCALE_USER_DEFAULT,
478 DISPATCH_METHOD, &params, NULL, NULL, NULL);
479 // 0x80020101 == SCRIPT_E_REPORTED.
480 // When the script we're invoking has an error, we get this error back.
481 DLOG_IF(ERROR, FAILED(hr) && hr != 0x80020101)
482 << StringPrintf(L"Failed to invoke script: 0x%08X", hr);
483 }
484 }
485
486 void ChromeFrameActivex::FireEvent(const EventHandlers& handlers,
487 IDispatch* event, BSTR target) {
488 DCHECK(event != NULL);
489 // Arguments in reverse order to event handler function declaration,
490 // because that's what DISPPARAMS requires.
491 VARIANT args[2] = { { VT_BSTR }, { VT_DISPATCH }, };
492 args[0].bstrVal = target;
493 args[1].pdispVal = event;
494 DISPPARAMS params = { args, NULL, arraysize(args), 0 };
495 for (EventHandlers::const_iterator it = handlers.begin();
496 it != handlers.end();
497 ++it) {
498 HRESULT hr = (*it)->Invoke(DISPID_VALUE, IID_NULL, LOCALE_USER_DEFAULT,
499 DISPATCH_METHOD, &params, NULL, NULL, NULL);
500 // 0x80020101 == SCRIPT_E_REPORTED.
501 // When the script we're invoking has an error, we get this error back.
502 DLOG_IF(ERROR, FAILED(hr) && hr != 0x80020101)
503 << StringPrintf(L"Failed to invoke script: 0x%08X", hr);
504 }
505 }
OLDNEW
« no previous file with comments | « chrome_frame/chrome_frame_activex.h ('k') | chrome_frame/chrome_frame_activex.rgs » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698