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