OLD | NEW |
(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 <htiframe.h> |
| 6 |
| 7 #include "chrome_frame/protocol_sink_wrap.h" |
| 8 |
| 9 #include "base/scoped_bstr_win.h" |
| 10 #include "base/logging.h" |
| 11 #include "base/registry.h" |
| 12 #include "base/scoped_bstr_win.h" |
| 13 #include "base/singleton.h" |
| 14 #include "base/string_util.h" |
| 15 |
| 16 #include "chrome_frame/utils.h" |
| 17 #include "chrome_frame/vtable_patch_manager.h" |
| 18 |
| 19 // BINDSTATUS_SERVER_MIMETYPEAVAILABLE == 54. Introduced in IE 8, so |
| 20 // not in everyone's headers yet. See: |
| 21 // http://msdn.microsoft.com/en-us/library/ms775133(VS.85,loband).aspx |
| 22 #ifndef BINDSTATUS_SERVER_MIMETYPEAVAILABLE |
| 23 #define BINDSTATUS_SERVER_MIMETYPEAVAILABLE 54 |
| 24 #endif |
| 25 |
| 26 static const wchar_t* kChromeMimeType = L"application/chromepage"; |
| 27 static const char kTextHtmlMimeType[] = "text/html"; |
| 28 |
| 29 static const int kInternetProtocolStartIndex = 3; |
| 30 static const int kInternetProtocolReadIndex = 9; |
| 31 static const int kInternetProtocolStartExIndex = 13; |
| 32 |
| 33 BEGIN_VTABLE_PATCHES(IInternetProtocol) |
| 34 VTABLE_PATCH_ENTRY(kInternetProtocolStartIndex, ProtocolSinkWrap::OnStart) |
| 35 VTABLE_PATCH_ENTRY(kInternetProtocolReadIndex, ProtocolSinkWrap::OnRead) |
| 36 END_VTABLE_PATCHES() |
| 37 |
| 38 BEGIN_VTABLE_PATCHES(IInternetProtocolEx) |
| 39 VTABLE_PATCH_ENTRY(kInternetProtocolStartIndex, ProtocolSinkWrap::OnStart) |
| 40 VTABLE_PATCH_ENTRY(kInternetProtocolReadIndex, ProtocolSinkWrap::OnRead) |
| 41 VTABLE_PATCH_ENTRY(kInternetProtocolStartExIndex, ProtocolSinkWrap::OnStartEx) |
| 42 END_VTABLE_PATCHES() |
| 43 |
| 44 // |
| 45 // ProtocolSinkWrap implementation |
| 46 // |
| 47 |
| 48 // Static map initialization |
| 49 ProtocolSinkWrap::ProtocolSinkMap ProtocolSinkWrap::sink_map_; |
| 50 CComAutoCriticalSection ProtocolSinkWrap::sink_map_lock_; |
| 51 |
| 52 ProtocolSinkWrap::ProtocolSinkWrap() |
| 53 : protocol_(NULL), renderer_type_(UNDETERMINED), |
| 54 buffer_size_(0), buffer_pos_(0), is_saved_result_(false), |
| 55 result_code_(0), result_error_(0), report_data_recursiveness_(0) { |
| 56 memset(buffer_, 0, arraysize(buffer_)); |
| 57 } |
| 58 |
| 59 ProtocolSinkWrap::~ProtocolSinkWrap() { |
| 60 CComCritSecLock<CComAutoCriticalSection> lock(sink_map_lock_); |
| 61 DCHECK(sink_map_.end() != sink_map_.find(protocol_)); |
| 62 sink_map_.erase(protocol_); |
| 63 protocol_ = NULL; |
| 64 DLOG(INFO) << "ProtocolSinkWrap: active sinks: " << sink_map_.size(); |
| 65 } |
| 66 |
| 67 bool ProtocolSinkWrap::PatchProtocolHandler(const wchar_t* dll, |
| 68 const CLSID& handler_clsid) { |
| 69 HMODULE module = ::GetModuleHandle(dll); |
| 70 if (!module) { |
| 71 NOTREACHED() << "urlmon is not yet loaded. Error: " << GetLastError(); |
| 72 return false; |
| 73 } |
| 74 |
| 75 typedef HRESULT (WINAPI* DllGetClassObject_Fn)(REFCLSID, REFIID, LPVOID*); |
| 76 DllGetClassObject_Fn fn = reinterpret_cast<DllGetClassObject_Fn>( |
| 77 ::GetProcAddress(module, "DllGetClassObject")); |
| 78 if (!fn) { |
| 79 NOTREACHED() << "DllGetClassObject not found in urlmon.dll"; |
| 80 return false; |
| 81 } |
| 82 |
| 83 ScopedComPtr<IClassFactory> protocol_class_factory; |
| 84 HRESULT hr = fn(handler_clsid, IID_IClassFactory, |
| 85 reinterpret_cast<LPVOID*>(protocol_class_factory.Receive())); |
| 86 if (FAILED(hr)) { |
| 87 NOTREACHED() << "DllGetclassObject failed. Error: " << hr; |
| 88 return false; |
| 89 } |
| 90 |
| 91 ScopedComPtr<IInternetProtocol> handler_instance; |
| 92 hr = protocol_class_factory->CreateInstance(NULL, IID_IInternetProtocol, |
| 93 reinterpret_cast<void**>(handler_instance.Receive())); |
| 94 if (FAILED(hr)) { |
| 95 NOTREACHED() << "ClassFactory::CreateInstance failed for InternetProtocol." |
| 96 << " Error: " << hr; |
| 97 return false; |
| 98 } |
| 99 |
| 100 ScopedComPtr<IInternetProtocolEx> ipex; |
| 101 ipex.QueryFrom(handler_instance); |
| 102 if (ipex) { |
| 103 vtable_patch::PatchInterfaceMethods(ipex, IInternetProtocolEx_PatchInfo); |
| 104 } else { |
| 105 vtable_patch::PatchInterfaceMethods(handler_instance, |
| 106 IInternetProtocol_PatchInfo); |
| 107 } |
| 108 |
| 109 return true; |
| 110 } |
| 111 |
| 112 // IInternetProtocol/Ex method implementation. |
| 113 HRESULT ProtocolSinkWrap::OnStart(InternetProtocol_Start_Fn orig_start, |
| 114 IInternetProtocol* protocol, LPCWSTR url, IInternetProtocolSink* prot_sink, |
| 115 IInternetBindInfo* bind_info, DWORD flags, HANDLE_PTR reserved) { |
| 116 DCHECK(orig_start); |
| 117 DLOG_IF(INFO, url != NULL) << "OnStart: " << url; |
| 118 |
| 119 ScopedComPtr<IInternetProtocolSink> sink_to_use(MaybeWrapSink(protocol, |
| 120 prot_sink, url)); |
| 121 return orig_start(protocol, url, sink_to_use, bind_info, flags, reserved); |
| 122 } |
| 123 |
| 124 HRESULT ProtocolSinkWrap::OnStartEx(InternetProtocol_StartEx_Fn orig_start_ex, |
| 125 IInternetProtocolEx* protocol, IUri* uri, IInternetProtocolSink* prot_sink, |
| 126 IInternetBindInfo* bind_info, DWORD flags, HANDLE_PTR reserved) { |
| 127 DCHECK(orig_start_ex); |
| 128 |
| 129 ScopedBstr url; |
| 130 uri->GetPropertyBSTR(Uri_PROPERTY_ABSOLUTE_URI, url.Receive(), 0); |
| 131 DLOG_IF(INFO, url != NULL) << "OnStartEx: " << url; |
| 132 |
| 133 ScopedComPtr<IInternetProtocolSink> sink_to_use(MaybeWrapSink(protocol, |
| 134 prot_sink, url)); |
| 135 return orig_start_ex(protocol, uri, sink_to_use, bind_info, flags, reserved); |
| 136 } |
| 137 |
| 138 HRESULT ProtocolSinkWrap::OnRead(InternetProtocol_Read_Fn orig_read, |
| 139 IInternetProtocol* protocol, void* buffer, ULONG size, ULONG* size_read) { |
| 140 DCHECK(orig_read); |
| 141 |
| 142 scoped_refptr<ProtocolSinkWrap> instance = |
| 143 ProtocolSinkWrap::InstanceFromProtocol(protocol); |
| 144 HRESULT hr; |
| 145 if (instance) { |
| 146 DCHECK(instance->protocol_ == protocol); |
| 147 hr = instance->OnReadImpl(buffer, size, size_read, orig_read); |
| 148 } else { |
| 149 hr = orig_read(protocol, buffer, size, size_read); |
| 150 } |
| 151 |
| 152 return hr; |
| 153 } |
| 154 |
| 155 bool ProtocolSinkWrap::Initialize(IInternetProtocol* protocol, |
| 156 IInternetProtocolSink* original_sink, const wchar_t* url) { |
| 157 DCHECK(original_sink); |
| 158 delegate_ = original_sink; |
| 159 protocol_ = protocol; |
| 160 if (url) |
| 161 url_ = url; |
| 162 |
| 163 CComCritSecLock<CComAutoCriticalSection> lock(sink_map_lock_); |
| 164 DCHECK(sink_map_.end() == sink_map_.find(protocol)); |
| 165 sink_map_[protocol] = this; |
| 166 DLOG(INFO) << "ProtocolSinkWrap: active sinks: " << sink_map_.size(); |
| 167 return true; |
| 168 } |
| 169 |
| 170 HRESULT WINAPI ProtocolSinkWrap::CheckOutgoingInterface(void* obj, |
| 171 REFIID iid, LPVOID* ret, DWORD cookie) { |
| 172 ProtocolSinkWrap* instance = reinterpret_cast<ProtocolSinkWrap*>(obj); |
| 173 HRESULT hr = E_NOINTERFACE; |
| 174 if (instance && instance->delegate_) |
| 175 hr = instance->delegate_->QueryInterface(iid, ret); |
| 176 |
| 177 #ifndef NDEBUG |
| 178 if (SUCCEEDED(hr)) { |
| 179 wchar_t iid_string[64] = {0}; |
| 180 StringFromGUID2(iid, iid_string, arraysize(iid_string)); |
| 181 DLOG(INFO) << "Giving out wrapped interface: " << iid_string; |
| 182 } |
| 183 #endif |
| 184 |
| 185 return hr; |
| 186 } |
| 187 |
| 188 HRESULT WINAPI ProtocolSinkWrap::IfDelegateSupports(void* obj, |
| 189 REFIID iid, LPVOID* ret, DWORD cookie) { |
| 190 HRESULT hr = E_NOINTERFACE; |
| 191 ProtocolSinkWrap* instance = reinterpret_cast<ProtocolSinkWrap*>(obj); |
| 192 if (instance && instance->delegate_) { |
| 193 ScopedComPtr<IUnknown> original; |
| 194 hr = instance->delegate_->QueryInterface(iid, |
| 195 reinterpret_cast<void**>(original.Receive())); |
| 196 if (original) { |
| 197 IUnknown* supported_interface = reinterpret_cast<IUnknown*>( |
| 198 reinterpret_cast<DWORD_PTR>(obj) + cookie); |
| 199 supported_interface->AddRef(); |
| 200 *ret = supported_interface; |
| 201 hr = S_OK; |
| 202 } |
| 203 } |
| 204 |
| 205 return hr; |
| 206 } |
| 207 |
| 208 // IInternetProtocolSink methods |
| 209 STDMETHODIMP ProtocolSinkWrap::Switch(PROTOCOLDATA* protocol_data) { |
| 210 HRESULT hr = E_FAIL; |
| 211 if (delegate_) |
| 212 hr = delegate_->Switch(protocol_data); |
| 213 return hr; |
| 214 } |
| 215 |
| 216 STDMETHODIMP ProtocolSinkWrap::ReportProgress(ULONG status_code, |
| 217 LPCWSTR status_text) { |
| 218 DLOG(INFO) << "ProtocolSinkWrap::ReportProgress: Code:" << status_code << |
| 219 " Text: " << (status_text ? status_text : L""); |
| 220 if ((BINDSTATUS_MIMETYPEAVAILABLE == status_code) || |
| 221 (BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE == status_code)) { |
| 222 // If we have a MIMETYPE and that MIMETYPE is not "text/html". we don't |
| 223 // want to do anything with this. |
| 224 if (status_text) { |
| 225 size_t status_text_length = lstrlenW(status_text); |
| 226 const wchar_t* status_text_end = status_text + std::min( |
| 227 status_text_length, arraysize(kTextHtmlMimeType) - 1); |
| 228 if (!LowerCaseEqualsASCII(status_text, status_text_end, |
| 229 kTextHtmlMimeType)) { |
| 230 renderer_type_ = OTHER; |
| 231 } |
| 232 } |
| 233 } |
| 234 |
| 235 HRESULT hr = E_FAIL; |
| 236 if (delegate_) |
| 237 hr = delegate_->ReportProgress(status_code, status_text); |
| 238 return hr; |
| 239 } |
| 240 |
| 241 STDMETHODIMP ProtocolSinkWrap::ReportData(DWORD flags, ULONG progress, |
| 242 ULONG max_progress) { |
| 243 DCHECK(protocol_); |
| 244 DCHECK(delegate_); |
| 245 DLOG(INFO) << "ProtocolSinkWrap::ReportData: flags: " << flags << |
| 246 " progress: " << progress << " progress_max: " << max_progress; |
| 247 |
| 248 scoped_refptr<ProtocolSinkWrap> self_ref(this); |
| 249 |
| 250 // Maintain a stack depth to make a determination. ReportData is called |
| 251 // recursively in IE8. If the request can be served in a single Read, the |
| 252 // situation ends up like this: |
| 253 // orig_prot |
| 254 // |--> ProtocolSinkWrap::ReportData (BSCF_FIRSTDATANOTIFICATION) |
| 255 // |--> orig_prot->Read(...) - 1st read - S_OK and data |
| 256 // |--> ProtocolSinkWrap::ReportData (BSCF_LASTDATANOTIFICATION) |
| 257 // |--> orig_prot->Read(...) - 2nd read S_FALSE, 0 bytes |
| 258 // |
| 259 // Inner call returns S_FALSE and no data. We try to make a determination |
| 260 // of render type then and incorrectly set it to 'OTHER' as we don't have |
| 261 // any data yet. However, we can make a determination in the context of |
| 262 // outer ReportData since the first read will return S_OK with data. Then |
| 263 // the next Read in the loop will return S_FALSE and we will enter the |
| 264 // determination logic. |
| 265 |
| 266 // NOTE: We use the report_data_recursiveness_ variable to detect situations |
| 267 // in which calls to ReportData are re-entrant (such as when the entire |
| 268 // contents of a page fit inside a single packet). In these cases, we |
| 269 // don't care about re-entrant calls beyond the second, and so we compare |
| 270 // report_data_recursiveness_ inside the while loop, making sure we skip |
| 271 // what would otherwise be spurious calls to ReportProgress(). |
| 272 report_data_recursiveness_++; |
| 273 |
| 274 HRESULT hr = S_OK; |
| 275 if (is_undetermined()) { |
| 276 HRESULT hr_read = S_OK; |
| 277 while (hr_read == S_OK) { |
| 278 ULONG size_read = 0; |
| 279 hr_read = protocol_->Read(buffer_ + buffer_size_, |
| 280 kMaxContentSniffLength - buffer_size_, &size_read); |
| 281 buffer_size_ += size_read; |
| 282 |
| 283 // Attempt to determine the renderer type if we have received |
| 284 // sufficient data. Do not attempt this when we are called recursively. |
| 285 if (report_data_recursiveness_ < 2 && (S_FALSE == hr_read) || |
| 286 (buffer_size_ >= kMaxContentSniffLength)) { |
| 287 DetermineRendererType(); |
| 288 if (renderer_type() == CHROME) { |
| 289 // Workaround for IE 8 and "nosniff". See: |
| 290 // http://blogs.msdn.com/ie/archive/2008/09/02/ie8-security-part-vi-be
ta-2-update.aspx |
| 291 delegate_->ReportProgress( |
| 292 BINDSTATUS_SERVER_MIMETYPEAVAILABLE, kChromeMimeType); |
| 293 // For IE < 8. |
| 294 delegate_->ReportProgress( |
| 295 BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE, kChromeMimeType); |
| 296 |
| 297 delegate_->ReportData( |
| 298 BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE, 0, 0); |
| 299 } |
| 300 break; |
| 301 } |
| 302 } |
| 303 } |
| 304 |
| 305 // we call original only if the renderer type is other |
| 306 if (renderer_type() == OTHER) { |
| 307 hr = delegate_->ReportData(flags, progress, max_progress); |
| 308 |
| 309 if (is_saved_result_) { |
| 310 is_saved_result_ = false; |
| 311 delegate_->ReportResult(result_code_, result_error_, |
| 312 result_text_.c_str()); |
| 313 } |
| 314 } |
| 315 |
| 316 report_data_recursiveness_--; |
| 317 return hr; |
| 318 } |
| 319 |
| 320 STDMETHODIMP ProtocolSinkWrap::ReportResult(HRESULT result, DWORD error, |
| 321 LPCWSTR result_text) { |
| 322 DLOG(INFO) << "ProtocolSinkWrap::ReportResult: result: " << result << |
| 323 " error: " << error << " Text: " << (result_text ? result_text : L""); |
| 324 |
| 325 // If this request failed, we don't want to have anything to do with this. |
| 326 if (FAILED(result)) |
| 327 renderer_type_ = OTHER; |
| 328 |
| 329 // if we are still not sure about the renderer type, cache the result, |
| 330 // othewise urlmon will get confused about getting reported about a |
| 331 // success result for which it never received any data. |
| 332 if (is_undetermined()) { |
| 333 is_saved_result_ = true; |
| 334 result_code_ = result; |
| 335 result_error_ = error; |
| 336 if (result_text) |
| 337 result_text_ = result_text; |
| 338 return S_OK; |
| 339 } |
| 340 |
| 341 HRESULT hr = E_FAIL; |
| 342 if (delegate_) |
| 343 hr = delegate_->ReportResult(result, error, result_text); |
| 344 |
| 345 return hr; |
| 346 } |
| 347 |
| 348 // IInternetBindInfoEx |
| 349 STDMETHODIMP ProtocolSinkWrap::GetBindInfo( |
| 350 DWORD* flags, BINDINFO* bind_info_ret) { |
| 351 ScopedComPtr<IInternetBindInfo> bind_info; |
| 352 HRESULT hr = bind_info.QueryFrom(delegate_); |
| 353 if (bind_info) |
| 354 hr = bind_info->GetBindInfo(flags, bind_info_ret); |
| 355 return hr; |
| 356 } |
| 357 |
| 358 STDMETHODIMP ProtocolSinkWrap::GetBindString(ULONG string_type, |
| 359 LPOLESTR* string_array, ULONG array_size, ULONG* size_returned) { |
| 360 ScopedComPtr<IInternetBindInfo> bind_info; |
| 361 HRESULT hr = bind_info.QueryFrom(delegate_); |
| 362 if (bind_info) |
| 363 hr = bind_info->GetBindString(string_type, string_array, |
| 364 array_size, size_returned); |
| 365 return hr; |
| 366 } |
| 367 |
| 368 STDMETHODIMP ProtocolSinkWrap::GetBindInfoEx(DWORD *flags, BINDINFO* bind_info, |
| 369 DWORD* bindf2, DWORD *reserved) { |
| 370 ScopedComPtr<IInternetBindInfoEx> bind_info_ex; |
| 371 HRESULT hr = bind_info_ex.QueryFrom(delegate_); |
| 372 if (bind_info_ex) |
| 373 hr = bind_info_ex->GetBindInfoEx(flags, bind_info, bindf2, reserved); |
| 374 return hr; |
| 375 } |
| 376 |
| 377 // IServiceProvider |
| 378 STDMETHODIMP ProtocolSinkWrap::QueryService(REFGUID service_guid, |
| 379 REFIID riid, void** service) { |
| 380 ScopedComPtr<IServiceProvider> service_provider; |
| 381 HRESULT hr = service_provider.QueryFrom(delegate_); |
| 382 if (service_provider) |
| 383 hr = service_provider->QueryService(service_guid, riid, service); |
| 384 return hr; |
| 385 } |
| 386 |
| 387 // IAuthenticate |
| 388 STDMETHODIMP ProtocolSinkWrap::Authenticate(HWND* window, |
| 389 LPWSTR* user_name, LPWSTR* password) { |
| 390 ScopedComPtr<IAuthenticate> authenticate; |
| 391 HRESULT hr = authenticate.QueryFrom(delegate_); |
| 392 if (authenticate) |
| 393 hr = authenticate->Authenticate(window, user_name, password); |
| 394 return hr; |
| 395 } |
| 396 |
| 397 // IInternetProtocolEx |
| 398 STDMETHODIMP ProtocolSinkWrap::Start(LPCWSTR url, |
| 399 IInternetProtocolSink *protocol_sink, IInternetBindInfo* bind_info, |
| 400 DWORD flags, HANDLE_PTR reserved) { |
| 401 ScopedComPtr<IInternetProtocolRoot> protocol; |
| 402 HRESULT hr = protocol.QueryFrom(delegate_); |
| 403 if (protocol) |
| 404 hr = protocol->Start(url, protocol_sink, bind_info, flags, reserved); |
| 405 return hr; |
| 406 } |
| 407 |
| 408 STDMETHODIMP ProtocolSinkWrap::Continue(PROTOCOLDATA* protocol_data) { |
| 409 ScopedComPtr<IInternetProtocolRoot> protocol; |
| 410 HRESULT hr = protocol.QueryFrom(delegate_); |
| 411 if (protocol) |
| 412 hr = protocol->Continue(protocol_data); |
| 413 return hr; |
| 414 } |
| 415 |
| 416 STDMETHODIMP ProtocolSinkWrap::Abort(HRESULT reason, DWORD options) { |
| 417 ScopedComPtr<IInternetProtocolRoot> protocol; |
| 418 HRESULT hr = protocol.QueryFrom(delegate_); |
| 419 if (protocol) |
| 420 hr = protocol->Abort(reason, options); |
| 421 return hr; |
| 422 } |
| 423 |
| 424 STDMETHODIMP ProtocolSinkWrap::Terminate(DWORD options) { |
| 425 ScopedComPtr<IInternetProtocolRoot> protocol; |
| 426 HRESULT hr = protocol.QueryFrom(delegate_); |
| 427 if (protocol) |
| 428 hr = protocol->Terminate(options); |
| 429 return hr; |
| 430 } |
| 431 |
| 432 STDMETHODIMP ProtocolSinkWrap::Suspend() { |
| 433 ScopedComPtr<IInternetProtocolRoot> protocol; |
| 434 HRESULT hr = protocol.QueryFrom(delegate_); |
| 435 if (protocol) |
| 436 hr = protocol->Suspend(); |
| 437 return hr; |
| 438 } |
| 439 |
| 440 STDMETHODIMP ProtocolSinkWrap::Resume() { |
| 441 ScopedComPtr<IInternetProtocolRoot> protocol; |
| 442 HRESULT hr = protocol.QueryFrom(delegate_); |
| 443 if (protocol) |
| 444 hr = protocol->Resume(); |
| 445 return hr; |
| 446 } |
| 447 |
| 448 STDMETHODIMP ProtocolSinkWrap::Read(void *buffer, ULONG size, |
| 449 ULONG* size_read) { |
| 450 ScopedComPtr<IInternetProtocol> protocol; |
| 451 HRESULT hr = protocol.QueryFrom(delegate_); |
| 452 if (protocol) |
| 453 hr = protocol->Read(buffer, size, size_read); |
| 454 return hr; |
| 455 } |
| 456 |
| 457 STDMETHODIMP ProtocolSinkWrap::Seek(LARGE_INTEGER move, DWORD origin, |
| 458 ULARGE_INTEGER* new_pos) { |
| 459 ScopedComPtr<IInternetProtocol> protocol; |
| 460 HRESULT hr = protocol.QueryFrom(delegate_); |
| 461 if (protocol) |
| 462 hr = protocol->Seek(move, origin, new_pos); |
| 463 return hr; |
| 464 } |
| 465 |
| 466 STDMETHODIMP ProtocolSinkWrap::LockRequest(DWORD options) { |
| 467 ScopedComPtr<IInternetProtocol> protocol; |
| 468 HRESULT hr = protocol.QueryFrom(delegate_); |
| 469 if (protocol) |
| 470 hr = protocol->LockRequest(options); |
| 471 return hr; |
| 472 } |
| 473 |
| 474 STDMETHODIMP ProtocolSinkWrap::UnlockRequest() { |
| 475 ScopedComPtr<IInternetProtocol> protocol; |
| 476 HRESULT hr = protocol.QueryFrom(delegate_); |
| 477 if (protocol) |
| 478 hr = protocol->UnlockRequest(); |
| 479 return hr; |
| 480 } |
| 481 |
| 482 STDMETHODIMP ProtocolSinkWrap::StartEx(IUri* uri, |
| 483 IInternetProtocolSink* protocol_sink, IInternetBindInfo* bind_info, |
| 484 DWORD flags, HANDLE_PTR reserved) { |
| 485 ScopedComPtr<IInternetProtocolEx> protocol; |
| 486 HRESULT hr = protocol.QueryFrom(delegate_); |
| 487 if (protocol) |
| 488 hr = protocol->StartEx(uri, protocol_sink, bind_info, flags, reserved); |
| 489 return hr; |
| 490 } |
| 491 |
| 492 // IInternetPriority |
| 493 STDMETHODIMP ProtocolSinkWrap::SetPriority(LONG priority) { |
| 494 ScopedComPtr<IInternetPriority> internet_priority; |
| 495 HRESULT hr = internet_priority.QueryFrom(delegate_); |
| 496 if (internet_priority) |
| 497 hr = internet_priority->SetPriority(priority); |
| 498 return hr; |
| 499 } |
| 500 |
| 501 STDMETHODIMP ProtocolSinkWrap::GetPriority(LONG* priority) { |
| 502 ScopedComPtr<IInternetPriority> internet_priority; |
| 503 HRESULT hr = internet_priority.QueryFrom(delegate_); |
| 504 if (internet_priority) |
| 505 hr = internet_priority->GetPriority(priority); |
| 506 return hr; |
| 507 } |
| 508 |
| 509 // IWrappedProtocol |
| 510 STDMETHODIMP ProtocolSinkWrap::GetWrapperCode(LONG *code, DWORD_PTR reserved) { |
| 511 ScopedComPtr<IWrappedProtocol> wrapped_protocol; |
| 512 HRESULT hr = wrapped_protocol.QueryFrom(delegate_); |
| 513 if (wrapped_protocol) |
| 514 hr = wrapped_protocol->GetWrapperCode(code, reserved); |
| 515 return hr; |
| 516 } |
| 517 |
| 518 |
| 519 // public IUriContainer |
| 520 STDMETHODIMP ProtocolSinkWrap::GetIUri(IUri** uri) { |
| 521 ScopedComPtr<IUriContainer> uri_container; |
| 522 HRESULT hr = uri_container.QueryFrom(delegate_); |
| 523 if (uri_container) |
| 524 hr = uri_container->GetIUri(uri); |
| 525 return hr; |
| 526 } |
| 527 |
| 528 // Protected helpers |
| 529 |
| 530 void ProtocolSinkWrap::DetermineRendererType() { |
| 531 if (is_undetermined()) { |
| 532 if (IsOptInUrl(url_.c_str())) { |
| 533 renderer_type_ = CHROME; |
| 534 } else { |
| 535 std::wstring xua_compat_content; |
| 536 // Note that document_contents_ may have NULL characters in it. While |
| 537 // browsers may handle this properly, we don't and will stop scanning for |
| 538 // the XUACompat content value if we encounter one. |
| 539 DCHECK(buffer_size_ < arraysize(buffer_)); |
| 540 buffer_[buffer_size_] = 0; |
| 541 std::wstring html_contents; |
| 542 // TODO(joshia): detect and handle different content encodings |
| 543 UTF8ToWide(buffer_, buffer_size_, &html_contents); |
| 544 UtilGetXUACompatContentValue(html_contents, &xua_compat_content); |
| 545 if (StrStrI(xua_compat_content.c_str(), kChromeContentPrefix)) { |
| 546 renderer_type_ = CHROME; |
| 547 } else { |
| 548 renderer_type_ = OTHER; |
| 549 } |
| 550 } |
| 551 } |
| 552 } |
| 553 |
| 554 HRESULT ProtocolSinkWrap::OnReadImpl(void* buffer, ULONG size, ULONG* size_read, |
| 555 InternetProtocol_Read_Fn orig_read) { |
| 556 // We want to switch the renderer to chrome, we cannot return any |
| 557 // data now. |
| 558 if (CHROME == renderer_type()) |
| 559 return S_FALSE; |
| 560 |
| 561 // Serve data from our buffer first. |
| 562 if (OTHER == renderer_type()) { |
| 563 const ULONG bytes_to_copy = std::min(buffer_size_ - buffer_pos_, size); |
| 564 if (bytes_to_copy) { |
| 565 memcpy(buffer, buffer_ + buffer_pos_, bytes_to_copy); |
| 566 *size_read = bytes_to_copy; |
| 567 buffer_pos_ += bytes_to_copy; |
| 568 return S_OK; |
| 569 } |
| 570 } |
| 571 |
| 572 return orig_read(protocol_, buffer, size, size_read); |
| 573 } |
| 574 |
| 575 scoped_refptr<ProtocolSinkWrap> ProtocolSinkWrap::InstanceFromProtocol( |
| 576 IInternetProtocol* protocol) { |
| 577 CComCritSecLock<CComAutoCriticalSection> lock(sink_map_lock_); |
| 578 scoped_refptr<ProtocolSinkWrap> instance; |
| 579 ProtocolSinkMap::iterator it = sink_map_.find(protocol); |
| 580 if (sink_map_.end() != it) |
| 581 instance = it->second; |
| 582 return instance; |
| 583 } |
| 584 |
| 585 HRESULT ProtocolSinkWrap::WebBrowserFromProtocolSink( |
| 586 IInternetProtocolSink* sink, IWebBrowser2** web_browser) { |
| 587 // TODO(tommi): GUID_NULL doesn't work when loading from history. |
| 588 // asking for IID_IHttpNegotiate as the service id works, but |
| 589 // getting the IWebBrowser2 interface still doesn't work. |
| 590 ScopedComPtr<IHttpNegotiate> http_negotiate; |
| 591 HRESULT hr = DoQueryService(GUID_NULL, sink, http_negotiate.Receive()); |
| 592 if (http_negotiate) |
| 593 hr = DoQueryService(IID_ITargetFrame2, http_negotiate, web_browser); |
| 594 |
| 595 return hr; |
| 596 } |
| 597 |
| 598 ScopedComPtr<IInternetProtocolSink> ProtocolSinkWrap::MaybeWrapSink( |
| 599 IInternetProtocol* protocol, IInternetProtocolSink* prot_sink, |
| 600 const wchar_t* url) { |
| 601 ScopedComPtr<IInternetProtocolSink> sink_to_use; |
| 602 sink_to_use.QueryFrom(prot_sink); |
| 603 ScopedComPtr<IWebBrowser2> web_browser; |
| 604 WebBrowserFromProtocolSink(prot_sink, web_browser.Receive()); |
| 605 if (web_browser) { |
| 606 CComObject<ProtocolSinkWrap>* wrap = NULL; |
| 607 CComObject<ProtocolSinkWrap>::CreateInstance(&wrap); |
| 608 DCHECK(wrap); |
| 609 if (wrap->Initialize(protocol, prot_sink, url)) { |
| 610 sink_to_use = wrap; |
| 611 } |
| 612 } |
| 613 |
| 614 return sink_to_use; |
| 615 } |
OLD | NEW |