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

Side by Side Diff: chrome_frame/urlmon_bind_status_callback.cc

Issue 1589013: Switch renderer in Moniker patch... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 10 years, 8 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
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 "chrome_frame/urlmon_bind_status_callback.h" 5 #include "chrome_frame/urlmon_bind_status_callback.h"
6 6
7 #include <mshtml.h>
7 #include <shlguid.h> 8 #include <shlguid.h>
8 9
9 #include "base/logging.h" 10 #include "base/logging.h"
10 #include "base/string_util.h" 11 #include "base/string_util.h"
11 12 #include "base/utf_string_conversions.h"
12 CFUrlmonBindStatusCallback::CFUrlmonBindStatusCallback() 13
13 : only_buffer_(false), data_(new RequestData()) { 14 #include "chrome_frame/urlmon_moniker.h"
14 DLOG(INFO) << __FUNCTION__ << me(); 15 #include "chrome_tab.h" // NOLINT
15 } 16
16 17
17 CFUrlmonBindStatusCallback::~CFUrlmonBindStatusCallback() { 18 // A helper to given feed data to the specified |bscb| using
18 DLOG(INFO) << __FUNCTION__ << me(); 19 // CacheStream instance.
19 } 20 HRESULT CacheStream::BSCBFeedData(IBindStatusCallback* bscb, const char* data,
20 21 size_t size, CLIPFORMAT clip_format,
21 std::string CFUrlmonBindStatusCallback::me() { 22 size_t flags) {
22 return StringPrintf(" obj=0x%08X", 23 if (!bscb) {
23 static_cast<CFUrlmonBindStatusCallback*>(this)); 24 NOTREACHED() << "invalid IBindStatusCallback";
24 } 25 return E_INVALIDARG;
25 26 }
26 HRESULT CFUrlmonBindStatusCallback::DelegateQI(void* obj, REFIID iid, 27
27 void** ret, DWORD cookie) { 28 // We can't use a CComObjectStackEx here since mshtml will hold
28 CFUrlmonBindStatusCallback* me = 29 // onto the stream pointer.
29 reinterpret_cast<CFUrlmonBindStatusCallback*>(obj); 30 CComObject<CacheStream>* cache_stream = NULL;
30 HRESULT hr = me->delegate_.QueryInterface(iid, ret); 31 HRESULT hr = CComObject<CacheStream>::CreateInstance(&cache_stream);
31 return hr;
32 }
33
34 HRESULT CFUrlmonBindStatusCallback::Initialize(IBindCtx* bind_ctx,
35 RequestHeaders* headers) {
36 DLOG(INFO) << __FUNCTION__ << me();
37 DCHECK(bind_ctx);
38 DCHECK(!binding_delegate_.get());
39 // headers may be NULL.
40
41 data_->Initialize(headers);
42
43 bind_ctx_ = bind_ctx;
44
45 // Replace the bind context callback with ours.
46 HRESULT hr = ::RegisterBindStatusCallback(bind_ctx, this,
47 delegate_.Receive(), 0);
48 if (!delegate_) {
49 NOTREACHED() << "Failed to find registered bind status callback";
50 ::RevokeBindStatusCallback(bind_ctx_, this);
51 bind_ctx_.Release();
52 hr = E_UNEXPECTED;
53 }
54
55 return hr;
56 }
57
58 HRESULT CFUrlmonBindStatusCallback::QueryService(REFGUID service, REFIID iid,
59 void** object) {
60 HRESULT hr = E_NOINTERFACE;
61 if (delegate_) {
62 ScopedComPtr<IServiceProvider> svc;
63 svc.QueryFrom(delegate_);
64 if (svc) {
65 hr = svc->QueryService(service, iid, object);
66 }
67 }
68 return hr;
69 }
70
71 // IBindStatusCallback
72 HRESULT CFUrlmonBindStatusCallback::OnStartBinding(DWORD reserved,
73 IBinding* binding) {
74 DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" tid=%i",
75 PlatformThread::CurrentId());
76 DCHECK(!binding_delegate_.get());
77
78 CComObject<SimpleBindingImpl>* binding_delegate;
79 HRESULT hr = CComObject<SimpleBindingImpl>::CreateInstance(&binding_delegate);
80 if (FAILED(hr)) { 32 if (FAILED(hr)) {
81 NOTREACHED(); 33 NOTREACHED();
82 return hr; 34 return hr;
83 } 35 }
84 36
85 binding_delegate_ = binding_delegate; 37 cache_stream->AddRef();
86 DCHECK_EQ(binding_delegate->m_dwRef, 1); 38 cache_stream->Initialize(data, size);
87 binding_delegate_->SetDelegate(binding); 39
88 40 FORMATETC format_etc = { clip_format, NULL, DVASPECT_CONTENT, -1,
89 return delegate_->OnStartBinding(reserved, binding_delegate_); 41 TYMED_ISTREAM };
90 } 42 STGMEDIUM medium = {0};
91 43 medium.tymed = TYMED_ISTREAM;
92 HRESULT CFUrlmonBindStatusCallback::GetPriority(LONG* priority) { 44 medium.pstm = cache_stream;
45
46 hr = bscb->OnDataAvailable(flags, size, &format_etc, &medium);
47
48 cache_stream->Release();
49 return hr;
50 }
51
52 void CacheStream::Initialize(const char* cache, size_t size) {
53 cache_ = cache;
54 size_ = size;
55 position_ = 0;
56 }
57
58 // Read is the only call that we expect. Return E_PENDING if there
59 // is no more data to serve. Otherwise this will result in a
60 // read with 0 bytes indicating that no more data is available.
61 STDMETHODIMP CacheStream::Read(void* pv, ULONG cb, ULONG* read) {
62 if (!pv || !read)
63 return E_INVALIDARG;
64
65 // Default to E_PENDING to signal that this is a partial data.
66 HRESULT hr = E_PENDING;
67 if (position_ < size_) {
68 *read = std::min(size_ - position_, size_t(cb));
69 memcpy(pv, cache_ + position_, *read);
70 position_ += *read;
71 hr = S_OK;
72 }
73
74 return hr;
75 }
76
77
78 /////////////////////////////////////////////////////////////////////
79
80 bool SniffData::InitializeCache(const std::wstring& url) {
81 url_ = url;
82 renderer_type_ = UNDETERMINED;
83
84 const int kAllocationSize = 32 * 1024;
85 HGLOBAL memory = GlobalAlloc(0, kAllocationSize);
86 HRESULT hr = CreateStreamOnHGlobal(memory, TRUE, cache_.Receive());
87 if (FAILED(hr)) {
88 GlobalFree(memory);
89 NOTREACHED();
90 return false;
91 }
92
93 return true;
94 }
95
96 HRESULT SniffData::ReadIntoCache(IStream* stream, bool force_determination) {
97 if (!stream) {
98 NOTREACHED();
99 return E_INVALIDARG;
100 }
101
102 HRESULT hr = S_OK;
103 while (SUCCEEDED(hr)) {
104 const size_t kChunkSize = 4 * 1024;
105 char buffer[kChunkSize];
106 DWORD read = 0;
107 hr = stream->Read(buffer, sizeof(buffer), &read);
108 if (read) {
109 DWORD written = 0;
110 cache_->Write(buffer, read, &written);
111 size_ += written;
112 }
113
114 if ((S_FALSE == hr) || !read)
115 break;
116 }
117
118 if (force_determination || (size() >= kMaxSniffSize)) {
119 DetermineRendererType();
120 }
121
122 return hr;
123 }
124
125 HRESULT SniffData::DrainCache(IBindStatusCallback* bscb, DWORD bscf,
126 CLIPFORMAT clip_format) {
127 if (!is_cache_valid()) {
128 return S_OK;
129 }
130
131 // Ideally we could just use the cache_ IStream implementation but
132 // can't use it here since we have to return E_PENDING for the
133 // last call
134 HGLOBAL memory = NULL;
135 HRESULT hr = GetHGlobalFromStream(cache_, &memory);
136 if (SUCCEEDED(hr) && memory) {
137 char* buffer = reinterpret_cast<char*>(GlobalLock(memory));
138 hr = CacheStream::BSCBFeedData(bscb, buffer, size_, clip_format, bscf);
139 GlobalUnlock(memory);
140 }
141
142 size_ = 0;
143 cache_.Release();
144 return hr;
145 }
146
147 // Scan the buffer or OptIn URL list and decide if the renderer is
148 // to be switched
149 void SniffData::DetermineRendererType() {
150 if (is_undetermined()) {
151 if (IsOptInUrl(url_.c_str())) {
152 renderer_type_ = CHROME;
153 } else {
154 renderer_type_ = OTHER;
155 if (is_cache_valid() && cache_) {
156 HGLOBAL memory = NULL;
157 GetHGlobalFromStream(cache_, &memory);
158 char* buffer = reinterpret_cast<char*>(GlobalLock(memory));
159
160 std::wstring html_contents;
161 // TODO(joshia): detect and handle different content encodings
162 if (buffer && size_) {
163 UTF8ToWide(buffer, size_, &html_contents);
164 GlobalUnlock(memory);
165 }
166
167 // Note that document_contents_ may have NULL characters in it. While
168 // browsers may handle this properly, we don't and will stop scanning
169 // for the XUACompat content value if we encounter one.
170 std::wstring xua_compat_content;
171 UtilGetXUACompatContentValue(html_contents, &xua_compat_content);
172 if (StrStrI(xua_compat_content.c_str(), kChromeContentPrefix)) {
173 renderer_type_ = CHROME;
174 }
175 }
176 }
177 }
178 }
179
180 /////////////////////////////////////////////////////////////////////
181
182 HRESULT BSCBStorageBind::Initialize(IMoniker* moniker, IBindCtx* bind_ctx) {
183 DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" tid=%i",
184 PlatformThread::CurrentId());
185
186 HRESULT hr = AttachToBind(bind_ctx);
187 if (FAILED(hr)) {
188 NOTREACHED() << __FUNCTION__ << me() << "AttachToBind error: " << hr;
189 return hr;
190 }
191
192 if (!delegate()) {
193 NOTREACHED() << __FUNCTION__ << me() << "No existing callback: " << hr;
194 return E_FAIL;
195 }
196
197 std::wstring url = GetActualUrlFromMoniker(moniker, bind_ctx,
198 std::wstring());
199 data_sniffer_.InitializeCache(url);
200 return hr;
201 }
202
203 STDMETHODIMP BSCBStorageBind::OnProgress(ULONG progress, ULONG progress_max,
204 ULONG status_code, LPCWSTR status_text) {
205 DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" status=%i tid=%i %ls",
206 status_code, PlatformThread::CurrentId(), status_text);
207
208 HRESULT hr = S_OK;
209 if (data_sniffer_.is_undetermined()) {
210 Progress new_progress = { progress, progress_max, status_code,
211 status_text ? status_text : std::wstring() };
212 saved_progress_.push_back(new_progress);
213 } else {
214 hr = CallbackImpl::OnProgress(progress, progress_max, status_code,
215 status_text);
216 }
217
218 return hr;
219 }
220
221 // Refer to urlmon_moniker.h for explanation of how things work.
222 STDMETHODIMP BSCBStorageBind::OnDataAvailable(DWORD flags, DWORD size,
223 FORMATETC* format_etc,
224 STGMEDIUM* stgmed) {
93 DLOG(INFO) << __FUNCTION__ << StringPrintf(" tid=%i", 225 DLOG(INFO) << __FUNCTION__ << StringPrintf(" tid=%i",
94 PlatformThread::CurrentId()); 226 PlatformThread::CurrentId());
95 return delegate_->GetPriority(priority); 227 if (!stgmed || !format_etc) {
96 } 228 DLOG(INFO) << __FUNCTION__ << me() << "Invalid stgmed or format_etc";
97 229 return CallbackImpl::OnDataAvailable(flags, size, format_etc, stgmed);
98 HRESULT CFUrlmonBindStatusCallback::OnLowResource(DWORD reserved) { 230 }
231
232 if ((stgmed->tymed != TYMED_ISTREAM) || !stgmed->pstm) {
233 DLOG(INFO) << __FUNCTION__ << me() << "stgmedium is not a valid stream";
234 return CallbackImpl::OnDataAvailable(flags, size, format_etc, stgmed);
235 }
236
237 HRESULT hr = S_OK;
238 if (!clip_format_)
239 clip_format_ = format_etc->cfFormat;
240
241 if (data_sniffer_.is_undetermined()) {
242 bool force_determination = !!(flags &
243 (BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE));
244 hr = data_sniffer_.ReadIntoCache(stgmed->pstm, force_determination);
245 // If we don't have sufficient data to determine renderer type
246 // wait for the next data notification.
247 if (data_sniffer_.is_undetermined())
248 return S_OK;
249 }
250
251 DCHECK(!data_sniffer_.is_undetermined());
252
253 if (data_sniffer_.is_cache_valid()) {
254 hr = MayPlayBack(flags);
255 DCHECK(!data_sniffer_.is_cache_valid());
256 } else {
257 hr = CallbackImpl::OnDataAvailable(flags, size, format_etc, stgmed);
258 }
259
260 return hr;
261 }
262
263 STDMETHODIMP BSCBStorageBind::OnStopBinding(HRESULT hresult, LPCWSTR error) {
99 DLOG(INFO) << __FUNCTION__ << StringPrintf(" tid=%i", 264 DLOG(INFO) << __FUNCTION__ << StringPrintf(" tid=%i",
100 PlatformThread::CurrentId()); 265 PlatformThread::CurrentId());
101 return delegate_->OnLowResource(reserved); 266 HRESULT hr = MayPlayBack(BSCF_LASTDATANOTIFICATION);
102 } 267 return CallbackImpl::OnStopBinding(hresult, error);
103 268 }
104 HRESULT CFUrlmonBindStatusCallback::OnProgress(ULONG progress, 269
105 ULONG progress_max, 270 // Play back the cached data to the delegate. Normally this would happen
106 ULONG status_code, 271 // when we have read enough data to determine the renderer. In this case
107 LPCWSTR status_text) { 272 // we first play back the data from the cache and then go into a 'pass
108 DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" status=%i tid=%i %ls", 273 // through' mode. In some cases we may end up getting OnStopBinding
109 status_code, PlatformThread::CurrentId(), status_text); 274 // before we get a chance to determine. Also it's possible that the
110 if (status_code == BINDSTATUS_REDIRECTING && status_text) { 275 // BindToStorage call will return before OnStopBinding is sent. Hence
111 redirected_url_ = status_text; 276 // This is called from 3 places and it's important to maintain the
112 } 277 // exact sequence of calls.
113 return delegate_->OnProgress(progress, progress_max, status_code, 278 // Once the data is played back, calling this again is a no op.
114 status_text); 279 HRESULT BSCBStorageBind::MayPlayBack(DWORD flags) {
115 } 280 // Force renderer type determination if not already done since
116 281 // we want to play back data now.
117 HRESULT CFUrlmonBindStatusCallback::OnStopBinding(HRESULT hresult, 282 data_sniffer_.DetermineRendererType();
118 LPCWSTR error) { 283 DCHECK(!data_sniffer_.is_undetermined());
119 DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" hr=0x%08X '%ls' tid=%i", 284
120 hresult, error, PlatformThread::CurrentId()); 285 HRESULT hr = S_OK;
121 if (SUCCEEDED(hresult)) { 286 if (data_sniffer_.is_chrome()) {
122 // Notify the BHO that this is the one and only RequestData object. 287 // Remember clip format. If we are switching to chrome, then in order
123 NavigationManager* mgr = NavigationManager::GetThreadInstance(); 288 // to make mshtml return INET_E_TERMINATED_BIND and reissue navigation
124 DCHECK(mgr); 289 // with the same bind context, we have to return a mime type that is
125 if (mgr && data_->GetCachedContentSize()) { 290 // special cased by mshtml.
126 mgr->SetActiveRequestData(data_); 291 static const CLIPFORMAT kMagicClipFormat =
127 if (!redirected_url_.empty()) { 292 RegisterClipboardFormat(CFSTR_MIME_MPEG);
128 mgr->set_url(redirected_url_.c_str()); 293 clip_format_ = kMagicClipFormat;
294 } else {
295 if (!saved_progress_.empty()) {
296 for (std::vector<Progress>::iterator i = saved_progress_.begin();
297 i != saved_progress_.end(); i++) {
298 const wchar_t* status_text = i->status_text_.empty() ?
299 NULL : i->status_text_.c_str();
300 CallbackImpl::OnProgress(i->progress_, i->progress_max_,
301 i->status_code_, status_text);
129 } 302 }
303 saved_progress_.clear();
130 } 304 }
131 305 }
132 if (only_buffer_) { 306
133 hresult = INET_E_TERMINATED_BIND; 307 if (data_sniffer_.is_cache_valid()) {
134 DLOG(INFO) << " - changed to INET_E_TERMINATED_BIND"; 308 hr = data_sniffer_.DrainCache(delegate(),
135 } 309 flags | BSCF_FIRSTDATANOTIFICATION, clip_format_);
136 } 310 if (data_sniffer_.is_chrome())
137 311 NavigationManager::AttachCFObject(bind_ctx_);
138 // Hold a reference to ourselves while we release the bind context 312 }
139 // and disconnect the callback. 313
140 AddRef(); 314 return hr;
141 315 }
142 HRESULT hr = delegate_->OnStopBinding(hresult, error);
143
144 if (bind_ctx_) {
145 ::RevokeBindStatusCallback(bind_ctx_, this);
146 bind_ctx_.Release();
147 }
148
149 binding_delegate_.Release();
150
151 // After this call, this object might be gone.
152 Release();
153
154 return hr;
155 }
156
157 HRESULT CFUrlmonBindStatusCallback::GetBindInfo(DWORD* bindf,
158 BINDINFO* bind_info) {
159 DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" tid=%i",
160 PlatformThread::CurrentId());
161 return delegate_->GetBindInfo(bindf, bind_info);
162 }
163
164 HRESULT CFUrlmonBindStatusCallback::OnDataAvailable(DWORD bscf, DWORD size,
165 FORMATETC* format_etc,
166 STGMEDIUM* stgmed) {
167 DCHECK(format_etc);
168 #ifndef NDEBUG
169 wchar_t clip_fmt_name[MAX_PATH] = {0};
170 if (format_etc) {
171 ::GetClipboardFormatNameW(format_etc->cfFormat, clip_fmt_name,
172 arraysize(clip_fmt_name));
173 }
174 DLOG(INFO) << __FUNCTION__ << me()
175 << StringPrintf(" tid=%i original fmt=%ls",
176 PlatformThread::CurrentId(), clip_fmt_name);
177
178 if (!stgmed) {
179 NOTREACHED() << "Invalid STGMEDIUM received";
180 return delegate_->OnDataAvailable(bscf, size, format_etc, stgmed);
181 }
182
183 if (stgmed->tymed != TYMED_ISTREAM) {
184 DLOG(INFO) << "Not handling medium:" << stgmed->tymed;
185 return delegate_->OnDataAvailable(bscf, size, format_etc, stgmed);
186 }
187
188 if (bscf & BSCF_FIRSTDATANOTIFICATION) {
189 DLOG(INFO) << "first data notification";
190 }
191 #endif
192
193 HRESULT hr = S_OK;
194 size_t bytes_read = 0;
195 if (!only_buffer_) {
196 hr = data_->DelegateDataRead(delegate_, bscf, size, format_etc, stgmed,
197 &bytes_read);
198 }
199
200 DLOG(INFO) << __FUNCTION__ << StringPrintf(" - 0x%08x", hr);
201 if (hr == INET_E_TERMINATED_BIND) {
202 // Check if the content type is CF's mime type.
203 UINT cf_format = ::RegisterClipboardFormatW(kChromeMimeType);
204 bool override_bind_results = (format_etc->cfFormat == cf_format);
205 if (!override_bind_results) {
206 ScopedComPtr<IBrowserService> browser_service;
207 DoQueryService(SID_SShellBrowser, delegate_, browser_service.Receive());
208 override_bind_results = (browser_service != NULL) &&
209 CheckForCFNavigation(browser_service, false);
210 }
211
212 if (override_bind_results) {
213 // We want to complete fetching the entire document even though the
214 // delegate isn't interested in continuing.
215 // This happens when we switch from mshtml to CF.
216 // We take over and buffer the document and once we're done, we report
217 // INET_E_TERMINATED to mshtml so that it will continue as usual.
218 hr = S_OK;
219 only_buffer_ = true;
220 binding_delegate_->OverrideBindResults(INET_E_TERMINATED_BIND);
221 }
222 }
223
224 if (only_buffer_) {
225 data_->CacheAll(stgmed->pstm);
226 DCHECK(hr == S_OK);
227 }
228
229 return hr;
230 }
231
232 HRESULT CFUrlmonBindStatusCallback::OnObjectAvailable(REFIID iid,
233 IUnknown* unk) {
234 DLOG(INFO) << __FUNCTION__ << StringPrintf(" tid=%i",
235 PlatformThread::CurrentId());
236 return delegate_->OnObjectAvailable(iid, unk);
237 }
238
239 // IBindStatusCallbackEx
240 HRESULT CFUrlmonBindStatusCallback::GetBindInfoEx(DWORD* bindf,
241 BINDINFO* bind_info,
242 DWORD* bindf2,
243 DWORD* reserved) {
244 DLOG(INFO) << __FUNCTION__ << StringPrintf(" tid=%i",
245 PlatformThread::CurrentId());
246 ScopedComPtr<IBindStatusCallbackEx> bscbex;
247 bscbex.QueryFrom(delegate_);
248 return bscbex->GetBindInfoEx(bindf, bind_info, bindf2, reserved);
249 }
250
251 HRESULT CFUrlmonBindStatusCallback::BeginningTransaction(LPCWSTR url,
252 LPCWSTR headers,
253 DWORD reserved,
254 LPWSTR* additional_headers) {
255 DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" tid=%i",
256 PlatformThread::CurrentId());
257
258 ScopedComPtr<IHttpNegotiate> http_negotiate;
259 HRESULT hr = http_negotiate.QueryFrom(delegate_);
260 if (SUCCEEDED(hr)) {
261 hr = http_negotiate->BeginningTransaction(url, headers, reserved,
262 additional_headers);
263 } else {
264 hr = S_OK;
265 }
266
267 data_->headers()->OnBeginningTransaction(url, headers,
268 additional_headers && *additional_headers ? *additional_headers : NULL);
269
270 DLOG_IF(ERROR, FAILED(hr)) << __FUNCTION__;
271 return hr;
272 }
273
274 HRESULT CFUrlmonBindStatusCallback::OnResponse(DWORD response_code,
275 LPCWSTR response_headers,
276 LPCWSTR request_headers,
277 LPWSTR* additional_headers) {
278 DLOG(INFO) << __FUNCTION__ << me() << StringPrintf(" tid=%i",
279 PlatformThread::CurrentId());
280
281 data_->headers()->OnResponse(response_code, response_headers,
282 request_headers);
283
284 ScopedComPtr<IHttpNegotiate> http_negotiate;
285 HRESULT hr = http_negotiate.QueryFrom(delegate_);
286 if (SUCCEEDED(hr)) {
287 hr = http_negotiate->OnResponse(response_code, response_headers,
288 request_headers, additional_headers);
289 } else {
290 hr = S_OK;
291 }
292 return hr;
293 }
294
295 HRESULT CFUrlmonBindStatusCallback::GetRootSecurityId(BYTE* security_id,
296 DWORD* security_id_size,
297 DWORD_PTR reserved) {
298 ScopedComPtr<IHttpNegotiate2> http_negotiate;
299 http_negotiate.QueryFrom(delegate_);
300 return http_negotiate->GetRootSecurityId(security_id, security_id_size,
301 reserved);
302 }
303
304 HRESULT CFUrlmonBindStatusCallback::GetSerializedClientCertContext(
305 BYTE** cert,
306 DWORD* cert_size) {
307 ScopedComPtr<IHttpNegotiate3> http_negotiate;
308 http_negotiate.QueryFrom(delegate_);
309 return http_negotiate->GetSerializedClientCertContext(cert, cert_size);
310 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698