Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: src/plugin/PluginWbPassThrough.cpp

Issue 6299667012780032: Issues #696,1231,1264,1265 - Improve handling in PassthroughApp (Closed)
Patch Set: Created Sept. 19, 2014, 2:41 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/plugin/PluginWbPassThrough.h ('k') | src/plugin/SinkPolicy.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #include "PluginStdAfx.h" 1 #include "PluginStdAfx.h"
2 2
3 #include "PluginWbPassThrough.h" 3 #include "PluginWbPassThrough.h"
4 #include "PluginClient.h" 4 #include "PluginClient.h"
5 #include "PluginClientFactory.h" 5 #include "PluginClientFactory.h"
6 #ifdef SUPPORT_FILTER 6 #ifdef SUPPORT_FILTER
7 #include "PluginFilter.h" 7 #include "PluginFilter.h"
8 #endif 8 #endif
9 #include "PluginSettings.h" 9 #include "PluginSettings.h"
10 #include "PluginClass.h" 10 #include "PluginClass.h"
11 #include "PluginSystem.h" 11 #include "PluginSystem.h"
12 12 #include <WinInet.h>
13 #include "wtypes.h" 13 #include "wtypes.h"
14 14
15 EXTERN_C IMAGE_DOS_HEADER __ImageBase; 15 namespace
16 {
17 std::string g_blockedByABPPage = "<!DOCTYPE html>"
18 "<html>"
19 "<body>"
20 "<!-- blocked by AdblockPlus -->"
21 "</body>"
22 "</html>";
23 }
16 24
25 WBPassthruSink::WBPassthruSink()
26 : m_currentPositionOfSentPage(0)
Oleksandr 2014/09/21 23:30:40 I wouldn't be entirely sure that IE does not reuse
sergei 2014/09/22 16:18:05 It does not reuse them. If it happens we will be a
Oleksandr 2014/10/03 14:36:37 Even though I can't provide an example when this m
27 , m_contentType(CFilter::EContentType::contentTypeAny)
28 , m_blockedInTransaction(false)
29 {
30 }
17 31
18 32 int WBPassthruSink::GetContentTypeFromMimeType(const CString& mimeType)
19 int WBPassthruSink::GetContentTypeFromMimeType(CString mimeType)
20 { 33 {
21 if (mimeType.Find(L"image/") >= 0) 34 if (mimeType.Find(L"image/") >= 0)
22 { 35 {
23 return CFilter::contentTypeImage; 36 return CFilter::contentTypeImage;
24 } 37 }
25 if (mimeType.Find(L"text/css") >= 0) 38 if (mimeType.Find(L"text/css") >= 0)
26 { 39 {
27 return CFilter::contentTypeStyleSheet; 40 return CFilter::contentTypeStyleSheet;
28 } 41 }
29 if ((mimeType.Find(L"application/javascript") >= 0) || (mimeType.Find(L"applic ation/json") >= 0)) 42 if ((mimeType.Find(L"application/javascript") >= 0) || (mimeType.Find(L"applic ation/json") >= 0))
(...skipping 10 matching lines...) Expand all
40 } 53 }
41 // It is important to have this check last, since it is rather generic, and mi ght overlay text/html, for example 54 // It is important to have this check last, since it is rather generic, and mi ght overlay text/html, for example
42 if (mimeType.Find(L"xml") >= 0) 55 if (mimeType.Find(L"xml") >= 0)
43 { 56 {
44 return CFilter::contentTypeXmlHttpRequest; 57 return CFilter::contentTypeXmlHttpRequest;
45 } 58 }
46 59
47 return CFilter::contentTypeAny; 60 return CFilter::contentTypeAny;
48 } 61 }
49 62
50 int WBPassthruSink::GetContentTypeFromURL(CString src) 63 int WBPassthruSink::GetContentTypeFromURL(const CString& src)
51 { 64 {
52 CString srcExt = src; 65 CString srcExt = src;
53 66
54 int pos = 0; 67 int pos = 0;
55 if ((pos = src.Find('?')) > 0) 68 if ((pos = src.Find('?')) > 0)
56 { 69 {
57 srcExt = src.Left(pos); 70 srcExt = src.Left(pos);
58 } 71 }
59 72
60 int lastDotIndex = srcExt.ReverseFind('.'); 73 int lastDotIndex = srcExt.ReverseFind('.');
(...skipping 17 matching lines...) Expand all
78 return CFilter::contentTypeXmlHttpRequest; 91 return CFilter::contentTypeXmlHttpRequest;
79 } 92 }
80 else if (ext == L".swf") 93 else if (ext == L".swf")
81 { 94 {
82 return CFilter::contentTypeObject; 95 return CFilter::contentTypeObject;
83 } 96 }
84 else if (ext == L".jsp" || ext == L".php" || ext == L".html") 97 else if (ext == L".jsp" || ext == L".php" || ext == L".html")
85 { 98 {
86 return CFilter::contentTypeSubdocument; 99 return CFilter::contentTypeSubdocument;
87 } 100 }
88 else 101 return CFilter::contentTypeAny;
89 {
90 return CFilter::contentTypeAny & ~CFilter::contentTypeSubdocument;
91 }
92
93 } 102 }
94 103
95 int WBPassthruSink::GetContentType(CString mimeType, CString domain, CString src ) 104 int WBPassthruSink::GetContentType(const CString& mimeType, const CString& domai n, const CString& src)
96 { 105 {
97 // No referer or mime type 106 // No referer or mime type
98 // BINDSTRING_XDR_ORIGIN works only for IE v8+ 107 // BINDSTRING_XDR_ORIGIN works only for IE v8+
99 if (mimeType.IsEmpty() && domain.IsEmpty() && CPluginClient::GetInstance()->Ge tIEVersion() >= 8) 108 if (mimeType.IsEmpty() && domain.IsEmpty() && CPluginClient::GetInstance()->Ge tIEVersion() >= 8)
100 { 109 {
101 return CFilter::contentTypeXmlHttpRequest; 110 return CFilter::contentTypeXmlHttpRequest;
102 } 111 }
103 int contentType = GetContentTypeFromMimeType(mimeType); 112 int contentType = GetContentTypeFromMimeType(mimeType);
104 if (contentType == CFilter::contentTypeAny) 113 if (contentType == CFilter::contentTypeAny)
105 { 114 {
106 contentType = GetContentTypeFromURL(src); 115 contentType = GetContentTypeFromURL(src);
107 } 116 }
108 return contentType; 117 return contentType;
109 } 118 }
110 119
111 //////////////////////////////////////////////////////////////////////////////// //////// 120 //////////////////////////////////////////////////////////////////////////////// ////////
112 //WBPassthruSink 121 //WBPassthruSink
113 //Monitor and/or cancel every request and responde 122 //Monitor and/or cancel every request and responde
114 //WB makes, including images, sounds, scripts, etc 123 //WB makes, including images, sounds, scripts, etc
115 //////////////////////////////////////////////////////////////////////////////// //////// 124 //////////////////////////////////////////////////////////////////////////////// ////////
116 HRESULT WBPassthruSink::OnStart(LPCWSTR szUrl, IInternetProtocolSink *pOIProtSin k, 125 HRESULT WBPassthruSink::OnStart(LPCWSTR szUrl, IInternetProtocolSink *pOIProtSin k,
117 IInternetBindInfo *pOIBindInfo, DWORD grfPI, HAN DLE_PTR dwReserved, 126 IInternetBindInfo *pOIBindInfo, DWORD grfPI, HAN DLE_PTR dwReserved,
118 IInternetProtocol* pTargetProtocol) 127 IInternetProtocol* pTargetProtocol, bool& handle d)
119 { 128 {
120
121 m_pTargetProtocol = pTargetProtocol; 129 m_pTargetProtocol = pTargetProtocol;
122 bool isBlocked = false; 130 bool isBlocked = false;
123 m_shouldBlock = false; 131 CString src = szUrl;
124 m_lastDataReported = false;
125 CString src;
126 src.Append(szUrl);
127 DEBUG_GENERAL(src); 132 DEBUG_GENERAL(src);
128 CPluginClient::UnescapeUrl(src); 133 CPluginClient::UnescapeUrl(src);
129 134
130 CString boundDomain; 135 // call the impl of the base class as soon as possible because it initializes the base class
136 // members, used by this method. It queries for the required interfaces.
137 HRESULT hr = BaseClass::OnStart(szUrl, pOIProtSink, pOIBindInfo, grfPI, dwRese rved, pTargetProtocol);
Oleksandr 2014/09/21 23:30:40 I still have my concerns if the requests are actua
sergei 2014/09/22 16:18:05 I have checked it before and now again, it works i
Oleksandr 2014/10/03 14:36:37 Not really. Just wanted to double check if you've
138 if (FAILED(hr))
139 {
140 return hr;
141 }
142
131 CString mimeType; 143 CString mimeType;
132 LPOLESTR mime[10];
133 if (pOIBindInfo) 144 if (pOIBindInfo)
134 { 145 {
135 ULONG resLen = 0; 146 ULONG resLen = 0;
136 147
137 // Apparently IE will report random mime type if there's more then 1 in the list. 148 // Apparently IE will report random mime type if there's more then 1 in the list.
138 // So we get the whole list and just use the first one (top priority one) 149 // So we get the whole list and just use the first one (top priority one)
150 LPOLESTR mime[10];
139 pOIBindInfo->GetBindString(BINDSTRING_ACCEPT_MIMES, mime, 10, &resLen); 151 pOIBindInfo->GetBindString(BINDSTRING_ACCEPT_MIMES, mime, 10, &resLen);
140 if (mime && resLen > 0) 152 if (mime && resLen > 0)
141 { 153 {
142 mimeType.SetString(mime[0]); 154 mimeType.SetString(mime[0]);
143 } 155 }
144 LPOLESTR bindToObject = 0; 156 LPOLESTR bindString = nullptr;
145 pOIBindInfo->GetBindString(BINDSTRING_FLAG_BIND_TO_OBJECT, &bindToObject, 1, &resLen); 157 pOIBindInfo->GetBindString(BINDSTRING_FLAG_BIND_TO_OBJECT, &bindString, 1, & resLen);
146 LPOLESTR domainRetrieved = 0; 158 LPOLESTR domainRetrieved = nullptr;
147 if (resLen == 0 || wcscmp(bindToObject, L"FALSE") == 0) 159 if (resLen == 0 || wcscmp(bindString, L"FALSE") == 0)
148 { 160 {
149 HRESULT hr = pOIBindInfo->GetBindString(BINDSTRING_XDR_ORIGIN, &domainRetr ieved, 1, &resLen); 161 HRESULT hr = pOIBindInfo->GetBindString(BINDSTRING_XDR_ORIGIN, &domainRetr ieved, 1, &resLen);
150
151 if ((hr == S_OK) && domainRetrieved && (resLen > 0)) 162 if ((hr == S_OK) && domainRetrieved && (resLen > 0))
152 { 163 {
153 boundDomain.SetString(domainRetrieved); 164 m_boundDomain = domainRetrieved;
154 } 165 }
155 } 166 }
167 // We can obtain IBindCtx* here, but IEnumString obtained via IBindCtx::Enum ObjectParam
168 // does not return any parameter, so it's useless.
156 } 169 }
157 170
158 CString cookie; 171 CString cookie;
159 ULONG len1 = 2048; 172 ULONG len1 = 2048;
160 ULONG len2 = 2048; 173 ULONG len2 = 2048;
161 174
162 #ifdef SUPPORT_FILTER 175 #ifdef SUPPORT_FILTER
163 int contentType = CFilter::contentTypeAny;
164
165 CPluginTab* tab = CPluginClass::GetTab(::GetCurrentThreadId()); 176 CPluginTab* tab = CPluginClass::GetTab(::GetCurrentThreadId());
166 CPluginClient* client = CPluginClient::GetInstance(); 177 CPluginClient* client = CPluginClient::GetInstance();
167 178
168
169 if (tab && client) 179 if (tab && client)
170 { 180 {
171 CString documentUrl = tab->GetDocumentUrl(); 181 CString documentUrl = tab->GetDocumentUrl();
172 // Page is identical to document => don't block 182 // Page is identical to document => don't block
173 if (documentUrl == src) 183 if (documentUrl == src)
174 { 184 {
175 // fall through 185 // fall through
176 } 186 }
177 else if (CPluginSettings::GetInstance()->IsPluginEnabled() && !client->IsWhi telistedUrl(std::wstring(documentUrl))) 187 else if (CPluginSettings::GetInstance()->IsPluginEnabled() && !client->IsWhi telistedUrl(std::wstring(documentUrl)))
178 { 188 {
179 boundDomain = tab->GetDocumentUrl(); 189 m_boundDomain = tab->GetDocumentUrl();
180 190 m_contentType = CFilter::contentTypeAny;
181 contentType = CFilter::contentTypeAny;
182
183 #ifdef SUPPORT_FRAME_CACHING 191 #ifdef SUPPORT_FRAME_CACHING
184 if ((tab != 0) && (tab->IsFrameCached(src))) 192 if (nullptr != tab && tab->IsFrameCached(src))
Oleksandr 2014/09/21 23:30:40 No yoda conditions, please if (tab != nullptr && .
185 { 193 {
186 contentType = CFilter::contentTypeSubdocument; 194 m_contentType = CFilter::contentTypeSubdocument;
187 } 195 }
188 else 196 else
189 #endif // SUPPORT_FRAME_CACHING 197 #endif // SUPPORT_FRAME_CACHING
190 contentType = GetContentType(mimeType, boundDomain, src);
191 if (client->ShouldBlock(src, contentType, boundDomain, true))
192 { 198 {
193 isBlocked = true; 199 m_contentType = GetContentType(mimeType, m_boundDomain, src);
194
195 DEBUG_BLOCKER("Blocker::Blocking Http-request:" + src);
196 } 200 }
197 } 201 }
198 if (!isBlocked)
199 {
200 DEBUG_BLOCKER("Blocker::Ignoring Http-request:" + src)
201 }
202 } 202 }
203 203
204 if (nullptr == tab)
Oleksandr 2014/09/21 23:30:40 No yoda conditions, please
205 {
206 m_contentType = GetContentType(mimeType, m_boundDomain, src);
207 }
204 208
205 if (tab == NULL)
206 { 209 {
207 contentType = GetContentType(mimeType, boundDomain, src); 210 // Here is the heuristic which detects the requests issued by Flash.ocx.
208 if (client->ShouldBlock(src, contentType, boundDomain, true)) 211 // It turned out that the implementation from ''Flash.ocx'' (tested version is 15.0.0.152)
212 // returns quite minimal configuration in comparison with the implementation from Microsofts'
213 // libraries (see grfBINDF and bindInfo.dwOptions). The impl from MS often i ncludes something
214 // else.
215 ATL::CComPtr<IBindStatusCallback> bscb;
216 if (SUCCEEDED(QueryServiceFromClient(&bscb)) && !!bscb)
209 { 217 {
210 isBlocked = true; 218 DWORD grfBINDF = 0;
219 BINDINFO bindInfo = {};
220 bindInfo.cbSize = sizeof(bindInfo);
221 if (SUCCEEDED(bscb->GetBindInfo(&grfBINDF, &bindInfo))
222 && (BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE| BINDF_PULLDATA) == grfBINDF
223 && (BINDINFO_OPTIONS_ENABLE_UTF8 | BINDINFO_OPTIONS_USE_IE_ENCODING) == bindInfo.dwOptions
224 )
Oleksandr 2014/09/21 23:30:40 This looks quite neat, however can you maybe test
sergei 2014/09/22 16:18:05 I will test it with different <IE, Flash> as far a
225 {
226 m_contentType = CFilter::EContentType::contentTypeObjectSubrequest;
227 }
211 } 228 }
212 } 229 }
213 230
214 #ifdef _DEBUG 231 // The descision about EContentType::contentTypeAny is made later in
215 CString type; 232 // WBPassthruSink::BeginningTransaction. Sometimes here we cannot detect the r equest type, but
233 // in WBPassthruSink::BeginningTransaction the header Accept is available whic h allows to
234 // obtain the "request type" in our terminology.
235 if (nullptr != client
236 && CFilter::EContentType::contentTypeAny != m_contentType
237 && client->ShouldBlock(src, m_contentType, m_boundDomain, true))
238 {
239 isBlocked = true;
240 }
216 241
217 if (contentType == CFilter::contentTypeDocument) type = "DOCUMENT"; 242 // For IE6 and earlier there is iframe back button issue, so avoid it.
218 else if (contentType == CFilter::contentTypeObject) type = "OBJECT"; 243 if (isBlocked && client->GetIEVersion() > 6)
219 else if (contentType == CFilter::contentTypeImage) type = "IMAGE";
220 else if (contentType == CFilter::contentTypeScript) type = "SCRIPT";
221 else if (contentType == CFilter::contentTypeOther) type = "OTHER";
222 else if (contentType == CFilter::contentTypeUnknown) type = "OTHER";
223 else if (contentType == CFilter::contentTypeSubdocument) type = "SUBDOCUMENT";
224 else if (contentType == CFilter::contentTypeStyleSheet) type = "STYLESHEET";
225 else type = "OTHER";
226
227 if (isBlocked)
228 { 244 {
229 CPluginDebug::DebugResultBlocking(type, src, boundDomain); 245 handled = true;
230 } 246 if (CFilter::EContentType::contentTypeImage == m_contentType)
231 else
232 {
233 CPluginDebug::DebugResultIgnoring(type, src, boundDomain);
234 }
235 #endif
236
237 //Fixes the iframe back button issue
238 if (client->GetIEVersion() > 6)
239 {
240 if ((contentType == CFilter::contentTypeImage) && (isBlocked))
241 { 247 {
242 m_shouldBlock = true; 248 // IE shows a cross that img is not loaded
Oleksandr 2014/09/21 23:30:40 Does this happen even if we "eat" the ReportResult
sergei 2014/09/22 16:18:05 Have not tested yet, also I'm afraid that sending
Oleksandr 2014/10/03 14:36:37 This can go into other review anyway. On 2014/09/2
243 BaseClass::OnStart(szUrl, pOIProtSink, pOIBindInfo, grfPI, dwReserved, pTa rgetProtocol);
244
245 return INET_E_REDIRECT_FAILED; 249 return INET_E_REDIRECT_FAILED;
246
247 } 250 }
248 if (((contentType == CFilter::contentTypeSubdocument))&& (isBlocked)) 251 if (CFilter::EContentType::contentTypeSubdocument == m_contentType)
249 { 252 {
250 m_shouldBlock = true; 253 PassthroughAPP::CustomSinkStartPolicy<WBPassthru, WBPassthruSink>::GetProt ocol(this)->m_shouldSupplyCustomContent = true;
251 BaseClass::OnStart(szUrl, pOIProtSink, pOIBindInfo, grfPI, dwReserved, pTa rgetProtocol);
252
253 m_spInternetProtocolSink->ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE, L"t ext/html"); 254 m_spInternetProtocolSink->ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE, L"t ext/html");
254 255 m_spInternetProtocolSink->ReportData(BSCF_FIRSTDATANOTIFICATION, 0, static _cast<ULONG>(g_blockedByABPPage.size()));
255 //Here we check if we are running on Windows 8 Consumer Preview. 256 return S_OK;
256 //For some reason on that environment the next line causes IE to crash
257 if (CPluginSettings::GetInstance()->GetWindowsBuildNumber() != 8250)
258 {
259 m_spInternetProtocolSink->ReportResult(INET_E_REDIRECT_FAILED, 0, szUrl) ;
260 }
261
262 return INET_E_REDIRECT_FAILED;
263 } 257 }
264 if (((contentType == CFilter::contentTypeScript)) && (isBlocked)) 258 if (CFilter::EContentType::contentTypeScript == m_contentType)
265 { 259 {
266 m_shouldBlock = true;
267 BaseClass::OnStart(szUrl, pOIProtSink, pOIBindInfo, grfPI, dwReserved, pTa rgetProtocol);
268 m_spInternetProtocolSink->ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE, L"t ext/javascript"); 260 m_spInternetProtocolSink->ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE, L"t ext/javascript");
269 m_spInternetProtocolSink->ReportResult(INET_E_REDIRECTING, 301, L"data:"); 261 m_spInternetProtocolSink->ReportResult(INET_E_REDIRECTING, 301, L"data:");
270 return INET_E_REDIRECT_FAILED; 262 return INET_E_REDIRECT_FAILED;
271 } 263 }
272 if ((contentType == CFilter::contentTypeXmlHttpRequest) && (isBlocked)) 264 if (CFilter::EContentType::contentTypeXmlHttpRequest == m_contentType)
273 { 265 {
274 m_shouldBlock = true;
275 BaseClass::OnStart(szUrl, pOIProtSink, pOIBindInfo, grfPI, dwReserved, pTa rgetProtocol);
276 m_spInternetProtocolSink->ReportResult(INET_E_REDIRECTING, 301, L"data:"); 266 m_spInternetProtocolSink->ReportResult(INET_E_REDIRECTING, 301, L"data:");
277 return INET_E_REDIRECT_FAILED; 267 return INET_E_REDIRECT_FAILED;
278 } 268 }
279 if ((isBlocked)) 269 if (CFilter::EContentType::contentTypeAny != m_contentType)
280 { 270 {
281 m_shouldBlock = true; 271 m_spInternetProtocolSink->ReportResult(INET_E_REDIRECTING, 301, L"data:");
282 BaseClass::OnStart(szUrl, pOIProtSink, pOIBindInfo, grfPI, dwReserved, pTa rgetProtocol);
283 m_spInternetProtocolSink->ReportResult(S_FALSE, 0, L"");
284
285 return INET_E_REDIRECT_FAILED; 272 return INET_E_REDIRECT_FAILED;
286 } 273 }
287 } 274 }
288 #endif // SUPPORT_FILTER 275 #endif // SUPPORT_FILTER
289 276
290 return isBlocked ? S_FALSE : BaseClass::OnStart(szUrl, pOIProtSink, pOIBindInf o, grfPI, dwReserved, pTargetProtocol); 277 return isBlocked ? S_FALSE : hr;
291 } 278 }
292 279
280 HRESULT WBPassthruSink::OnRead(void* pv, ULONG cb, ULONG* pcbRead)
281 {
282 if (nullptr == pv)
Oleksandr 2014/09/21 23:30:40 if (pv == nullptr) looks better, imho
283 {
284 return E_POINTER;
285 }
286 if (nullptr == pcbRead)
Oleksandr 2014/09/21 23:30:40 Same as above
287 {
288 return E_POINTER;
289 }
290 *pcbRead = 0;
293 291
294 HRESULT WBPassthruSink::Read(void *pv, ULONG cb, ULONG* pcbRead) 292 if (PassthroughAPP::CustomSinkStartPolicy<WBPassthru, WBPassthruSink>::GetProt ocol(this)->m_shouldSupplyCustomContent)
295 {
296 if (m_shouldBlock)
297 { 293 {
298 *pcbRead = 0; 294 ULONG myPageSize = static_cast<ULONG>(g_blockedByABPPage.size());
Oleksandr 2014/09/21 23:30:40 abpPageSize would be a better name, IMHO
sergei 2014/09/22 16:18:05 Sorry, forgot to change the name. During the playi
299 if (!m_lastDataReported) 295 auto positionGrow = std::min<ULONG>(cb, static_cast<ULONG>(g_blockedByABPPag e.size() - m_currentPositionOfSentPage));
296 if (0 == positionGrow) {
Oleksandr 2014/09/21 23:30:40 positionGrow == 0 seems more logical
297 return S_FALSE;
298 }
299 std::copy(g_blockedByABPPage.begin(), g_blockedByABPPage.begin() + positionG row,
300 stdext::make_checked_array_iterator(static_cast<char*>(pv), cb));
Oleksandr 2014/09/21 23:30:40 So this will throw a runtime error if cb < positio
sergei 2014/09/22 16:18:05 - It's not possible to compile without checked ite
Oleksandr 2014/10/03 14:36:37 I suppose you could use memcpy here instead, but I
301 *pcbRead = positionGrow;
302 m_currentPositionOfSentPage += positionGrow;
303
304 if (m_spInternetProtocolSink)
300 { 305 {
301 if (cb <= 1) 306 m_spInternetProtocolSink->ReportData(BSCF_INTERMEDIATEDATANOTIFICATION,
302 { 307 static_cast<ULONG>(m_currentPositionOfSentPage), myPageSize);
303 //IE must've gone nuts if this happened, but let's be cool about it and report we have no more data 308 }
304 m_spInternetProtocolSink->ReportResult(S_FALSE, 0, NULL); 309 if (myPageSize == m_currentPositionOfSentPage && m_spInternetProtocolSink)
305 return S_FALSE; 310 {
306 } 311 m_spInternetProtocolSink->ReportData(BSCF_DATAFULLYAVAILABLE, myPageSize, myPageSize);
307 *pcbRead = 1; 312 m_spInternetProtocolSink->ReportResult(S_OK, 0, nullptr);
308 memcpy(pv, " ", 1);
309
310 if (m_spInternetProtocolSink != NULL)
311 {
312 m_spInternetProtocolSink->ReportResult(S_OK, 0, NULL);
313 }
314 m_lastDataReported = true;
315 m_shouldBlock = false;
316 return S_OK;
317 } 313 }
318 return S_OK; 314 return S_OK;
319 } 315 }
320 else 316 return m_pTargetProtocol->Read(pv, cb, pcbRead);
321 {
322
323 return m_pTargetProtocol->Read(pv, cb, pcbRead);
324 }
325 return S_OK;
326 } 317 }
327 STDMETHODIMP WBPassthruSink::Switch( 318 STDMETHODIMP WBPassthruSink::Switch(
328 /* [in] */ PROTOCOLDATA *pProtocolData) 319 /* [in] */ PROTOCOLDATA *pProtocolData)
329 { 320 {
330 ATLASSERT(m_spInternetProtocolSink != 0); 321 ATLASSERT(m_spInternetProtocolSink != 0);
331 322
332 /* 323 /*
333 From Igor Tandetnik "itandetnik@mvps.org" 324 From Igor Tandetnik "itandetnik@mvps.org"
334 " 325 "
335 Beware multithreading. URLMon has this nasty habit of spinning worker 326 Beware multithreading. URLMon has this nasty habit of spinning worker
336 threads, not even bothering to initialize COM on them, and calling APP 327 threads, not even bothering to initialize COM on them, and calling APP
337 methods on those threads. If you try to raise COM events directly from 328 methods on those threads. If you try to raise COM events directly from
338 such a thread, bad things happen (random crashes, events being lost). 329 such a thread, bad things happen (random crashes, events being lost).
339 You are only guaranteed to be on the main STA thread in two cases. 330 You are only guaranteed to be on the main STA thread in two cases.
340 First, in methods of interfaces that were obtained with 331 First, in methods of interfaces that were obtained with
341 IServiceProvider, such as IHttpNegotiage::BeginningTransaction or 332 IServiceProvider, such as IHttpNegotiage::BeginningTransaction or
342 IAuthenticate::Authenticate. Second, you can call 333 IAuthenticate::Authenticate. Second, you can call
343 IInternetProtocolSink::Switch with PD_FORCE_SWITCH flag in 334 IInternetProtocolSink::Switch with PD_FORCE_SWITCH flag in
344 PROTOCOLDATA::grfFlags, eventually URLMon will turn around and call 335 PROTOCOLDATA::grfFlags, eventually URLMon will turn around and call
345 IInternetProtocol::Continue on the main thread. 336 IInternetProtocol::Continue on the main thread.
346 337
347 Or, if you happen to have a window handy that was created on the main 338 Or, if you happen to have a window handy that was created on the main
348 thread, you can post yourself a message. 339 thread, you can post yourself a message.
349 " 340 "
350 */ 341 */
351 return m_spInternetProtocolSink ? m_spInternetProtocolSink->Switch(pProtocolDa ta) : E_UNEXPECTED; 342 return m_spInternetProtocolSink ? m_spInternetProtocolSink->Switch(pProtocolDa ta) : E_UNEXPECTED;
352 } 343 }
353 344
354 345 STDMETHODIMP WBPassthruSink::BeginningTransaction(LPCWSTR szURL, LPCWSTR szHeade rs, DWORD dwReserved, LPWSTR* pszAdditionalHeaders)
355 STDMETHODIMP WBPassthruSink::BeginningTransaction(LPCWSTR szURL, LPCWSTR szHeade rs, DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
356 { 346 {
357 if (pszAdditionalHeaders) 347 if (pszAdditionalHeaders)
358 { 348 {
359 *pszAdditionalHeaders = 0; 349 *pszAdditionalHeaders = nullptr;
360 } 350 }
361 351
352 CPluginClient* client = nullptr;
353 if (CFilter::EContentType::contentTypeAny == m_contentType && (client = CPlugi nClient::GetInstance()))
354 {
355 auto acceptHeader = [&]() -> std::string
356 {
357 // Despite there is HTTP_QUERY_ACCEPT and other query info flags, they don 't work here,
358 // only HTTP_QUERY_RAW_HEADERS_CRLF | HTTP_QUERY_FLAG_REQUEST_HEADERS does dork.
359 ATL::CComPtr<IWinInetHttpInfo> winInetHttpInfo;
360 HRESULT hr = m_spTargetProtocol->QueryInterface(&winInetHttpInfo);
361 if(FAILED(hr))
362 {
363 return "";
364 }
365 DWORD size = 0;
366 DWORD flags = 0;
367 hr = winInetHttpInfo->QueryInfo(HTTP_QUERY_RAW_HEADERS_CRLF | HTTP_QUERY_F LAG_REQUEST_HEADERS,
368 /*buffer*/nullptr, /* get size */&size, &flags, /*reserved*/ 0);
369 if(FAILED(hr))
370 {
371 return "";
372 }
373 std::string buf(size, '\0');
374 hr = winInetHttpInfo->QueryInfo(HTTP_QUERY_RAW_HEADERS_CRLF | HTTP_QUERY_F LAG_REQUEST_HEADERS,
375 &buf[0], &size, &flags, 0);
376 if(FAILED(hr))
377 {
378 return "";
379 }
380 char acceptHeader[] = "Accept:";
381 auto acceptHeaderBeginsAt = buf.find(acceptHeader);
382 if (std::string::npos == acceptHeaderBeginsAt)
383 {
384 return "";
385 }
386 acceptHeaderBeginsAt += sizeof(acceptHeader);
387 auto acceptHeaderEndsAt = buf.find("\n", acceptHeaderBeginsAt);
388 if (std::string::npos == acceptHeaderEndsAt)
389 {
390 return "";
391 }
392 return buf.substr(acceptHeaderBeginsAt, acceptHeaderEndsAt - acceptHeaderB eginsAt);
393 }();
394 m_contentType = GetContentTypeFromMimeType(ATL::CString(acceptHeader.c_str() ));
395 bool isBlocked = client->ShouldBlock(szURL, m_contentType, m_boundDomain, /* debug flag but must be set*/true);
396 if (isBlocked)
397 {
398 m_blockedInTransaction = true;
399 return E_ABORT;
400 }
401 }
362 CComPtr<IHttpNegotiate> spHttpNegotiate; 402 CComPtr<IHttpNegotiate> spHttpNegotiate;
363 QueryServiceFromClient(&spHttpNegotiate); 403 QueryServiceFromClient(&spHttpNegotiate);
364 return spHttpNegotiate ? spHttpNegotiate->BeginningTransaction(szURL, szHeader s,dwReserved, pszAdditionalHeaders) : S_OK; 404 return spHttpNegotiate ? spHttpNegotiate->BeginningTransaction(szURL, szHeader s,dwReserved, pszAdditionalHeaders) : S_OK;
365 } 405 }
366 406
367 STDMETHODIMP WBPassthruSink::OnResponse(DWORD dwResponseCode, LPCWSTR szResponse Headers, LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders) 407 STDMETHODIMP WBPassthruSink::OnResponse(DWORD dwResponseCode, LPCWSTR szResponse Headers, LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders)
368 { 408 {
369 if (pszAdditionalRequestHeaders) 409 if (pszAdditionalRequestHeaders)
370 { 410 {
371 *pszAdditionalRequestHeaders = 0; 411 *pszAdditionalRequestHeaders = 0;
372 } 412 }
373 413
374 CComPtr<IHttpNegotiate> spHttpNegotiate; 414 CComPtr<IHttpNegotiate> spHttpNegotiate;
375 QueryServiceFromClient(&spHttpNegotiate); 415 QueryServiceFromClient(&spHttpNegotiate);
376 416
377 return spHttpNegotiate ? spHttpNegotiate->OnResponse(dwResponseCode, szRespons eHeaders, szRequestHeaders, pszAdditionalRequestHeaders) : S_OK; 417 return spHttpNegotiate ? spHttpNegotiate->OnResponse(dwResponseCode, szRespons eHeaders, szRequestHeaders, pszAdditionalRequestHeaders) : S_OK;
378 } 418 }
379 419
380 STDMETHODIMP WBPassthruSink::ReportProgress(ULONG ulStatusCode, LPCWSTR szStatus Text) 420 STDMETHODIMP WBPassthruSink::ReportProgress(ULONG ulStatusCode, LPCWSTR szStatus Text)
381 { 421 {
382 return m_spInternetProtocolSink ? m_spInternetProtocolSink->ReportProgress(ulS tatusCode, szStatusText) : S_OK; 422 return m_spInternetProtocolSink ? m_spInternetProtocolSink->ReportProgress(ulS tatusCode, szStatusText) : S_OK;
383 } 423 }
384 424
425 STDMETHODIMP WBPassthruSink::ReportResult(/* [in] */ HRESULT hrResult, /* [in] * / DWORD dwError, /* [in] */ LPCWSTR szResult)
426 {
427 if (m_blockedInTransaction)
428 {
429 // Don't notify the client about aborting of the operation, thus don't call BaseClass::ReportResult.
430 // Current method is called by the original protocol implementation and we a re intercepting the
431 // call here and eating it, we will call the proper ReportResult later by ou rself.
432 return S_OK;
433 }
434 return BaseClass::ReportResult(hrResult, dwError, szResult);
435 }
436
437
438 WBPassthru::WBPassthru()
439 : m_shouldSupplyCustomContent(false)
440 , m_hasOriginalStartCalled(false)
441 {
442 }
385 443
386 STDMETHODIMP WBPassthru::Start(LPCWSTR szUrl, IInternetProtocolSink *pOIProtSink , 444 STDMETHODIMP WBPassthru::Start(LPCWSTR szUrl, IInternetProtocolSink *pOIProtSink ,
387 IInternetBindInfo *pOIBindInfo, DWORD grfPI, HANDLE_PTR dwReserved) 445 IInternetBindInfo *pOIBindInfo, DWORD grfPI, HANDLE_PTR dwReserved)
388 { 446 {
389 ATLASSERT(m_spInternetProtocol != 0); 447 ATLASSERT(m_spInternetProtocol != 0);
390 if (!m_spInternetProtocol) 448 if (!m_spInternetProtocol)
391 { 449 {
392 return E_UNEXPECTED; 450 return E_UNEXPECTED;
393 } 451 }
394 452
395 return OnStart(szUrl, pOIProtSink, pOIBindInfo, grfPI, 453 return OnStart(szUrl, pOIProtSink, pOIBindInfo, grfPI, dwReserved, m_spInterne tProtocol);
396 dwReserved, m_spInternetProtocol);
397 } 454 }
398 455
399 STDMETHODIMP WBPassthru::Read(»/* [in, out] */ void *pv,/* [in] */ ULONG cb,/* [out] */ ULONG *pcbRead) 456 STDMETHODIMP WBPassthru::Read(/* [in, out] */ void *pv,/* [in] */ ULONG cb,/* [o ut] */ ULONG *pcbRead)
400 { 457 {
401 458 WBPassthruSink* pSink = GetSink();
402 WBPassthruSink* pSink = GetSink(); 459 return pSink->OnRead(pv, cb, pcbRead);
403 return pSink->Read(pv, cb, pcbRead); 460 }
404 } 461
462 STDMETHODIMP WBPassthru::LockRequest(/* [in] */ DWORD options)
463 {
464 if (!m_hasOriginalStartCalled)
465 {
466 return S_OK;
467 }
468 return BaseClass::LockRequest(options);
469 }
470
471 STDMETHODIMP WBPassthru::UnlockRequest()
472 {
473 if (!m_hasOriginalStartCalled)
474 {
475 return S_OK;
476 }
477 return BaseClass::UnlockRequest();
478 }
OLDNEW
« no previous file with comments | « src/plugin/PluginWbPassThrough.h ('k') | src/plugin/SinkPolicy.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld