| 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 |