| LEFT | RIGHT | 
|    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 #include "../shared/Utils.h" | 
|   13 EXTERN_C IMAGE_DOS_HEADER __ImageBase; |   13  | 
|   14  |   14 namespace | 
|   15  |   15 { | 
|   16  |   16   const std::string g_blockedByABPPage = "<!DOCTYPE html>" | 
|   17 int WBPassthruSink::GetContentTypeFromMimeType(CString mimeType) |   17     "<html>" | 
 |   18         "<body>" | 
 |   19           "<!-- blocked by AdblockPlus -->" | 
 |   20         "</body>" | 
 |   21     "</html>"; | 
 |   22  | 
 |   23   template <class T> | 
 |   24   T ExtractHttpHeader(const T& allHeaders, const T& targetHeaderNameWithColon, c
     onst T& delimiter) | 
 |   25   { | 
 |   26     auto targetHeaderBeginsAt = allHeaders.find(targetHeaderNameWithColon); | 
 |   27     if (targetHeaderBeginsAt == T::npos) | 
 |   28     { | 
 |   29       return T(); | 
 |   30     } | 
 |   31     targetHeaderBeginsAt += targetHeaderNameWithColon.length(); | 
 |   32     auto targetHeaderEndsAt = allHeaders.find(delimiter, targetHeaderBeginsAt); | 
 |   33     if (targetHeaderEndsAt == T::npos) | 
 |   34     { | 
 |   35       return T(); | 
 |   36     } | 
 |   37     return allHeaders.substr(targetHeaderBeginsAt, targetHeaderEndsAt - targetHe
     aderBeginsAt); | 
 |   38   } | 
 |   39  | 
 |   40   std::string ExtractHttpAcceptHeader(IInternetProtocol* internetProtocol) | 
 |   41   { | 
 |   42     // Despite there being HTTP_QUERY_ACCEPT and other query info flags, they do
     n't work here, | 
 |   43     // only HTTP_QUERY_RAW_HEADERS_CRLF | HTTP_QUERY_FLAG_REQUEST_HEADERS does w
     ork. | 
 |   44     ATL::CComPtr<IWinInetHttpInfo> winInetHttpInfo; | 
 |   45     HRESULT hr = internetProtocol->QueryInterface(&winInetHttpInfo); | 
 |   46     if (FAILED(hr) || !winInetHttpInfo) | 
 |   47     { | 
 |   48       return ""; | 
 |   49     } | 
 |   50     DWORD size = 0; | 
 |   51     DWORD flags = 0; | 
 |   52     DWORD queryOption = HTTP_QUERY_RAW_HEADERS_CRLF | HTTP_QUERY_FLAG_REQUEST_HE
     ADERS; | 
 |   53     hr = winInetHttpInfo->QueryInfo(queryOption, /*buffer*/ nullptr, /*get size*
     / &size, &flags, /*reserved*/ 0); | 
 |   54     if (FAILED(hr)) | 
 |   55     { | 
 |   56       return ""; | 
 |   57     } | 
 |   58     std::string buf(size, '\0'); | 
 |   59     hr = winInetHttpInfo->QueryInfo(queryOption, &buf[0], &size, &flags, 0); | 
 |   60     if (FAILED(hr)) | 
 |   61     { | 
 |   62       return ""; | 
 |   63     } | 
 |   64     return ExtractHttpHeader<std::string>(buf, "Accept:", "\r\n"); | 
 |   65   } | 
 |   66  | 
 |   67   bool IsXmlHttpRequest(const std::wstring& additionalHeaders) | 
 |   68   { | 
 |   69     auto requestedWithHeader = ExtractHttpHeader<std::wstring>(additionalHeaders
     , L"X-Requested-With:", L"\n"); | 
 |   70     return TrimString(requestedWithHeader) == L"XMLHttpRequest"; | 
 |   71   } | 
 |   72 } | 
 |   73  | 
 |   74 WBPassthruSink::WBPassthruSink() | 
 |   75   : m_currentPositionOfSentPage(0) | 
 |   76   , m_contentType(CFilter::EContentType::contentTypeAny) | 
 |   77   , m_isCustomResponse(false) | 
 |   78 { | 
 |   79 } | 
 |   80  | 
 |   81 int WBPassthruSink::GetContentTypeFromMimeType(const CString& mimeType) | 
|   18 { |   82 { | 
|   19   if (mimeType.Find(L"image/") >= 0) |   83   if (mimeType.Find(L"image/") >= 0) | 
|   20   { |   84   { | 
|   21     return CFilter::contentTypeImage; |   85     return CFilter::contentTypeImage; | 
|   22   } |   86   } | 
|   23   if (mimeType.Find(L"text/css") >= 0) |   87   if (mimeType.Find(L"text/css") >= 0) | 
|   24   { |   88   { | 
|   25     return CFilter::contentTypeStyleSheet; |   89     return CFilter::contentTypeStyleSheet; | 
|   26   } |   90   } | 
|   27   if ((mimeType.Find(L"application/javascript") >= 0) || (mimeType.Find(L"applic
     ation/json") >= 0)) |   91   if ((mimeType.Find(L"application/javascript") >= 0) || (mimeType.Find(L"applic
     ation/json") >= 0)) | 
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   77     return CFilter::contentTypeXmlHttpRequest; |  141     return CFilter::contentTypeXmlHttpRequest; | 
|   78   } |  142   } | 
|   79   else if (ext == L".swf") |  143   else if (ext == L".swf") | 
|   80   { |  144   { | 
|   81     return CFilter::contentTypeObject; |  145     return CFilter::contentTypeObject; | 
|   82   } |  146   } | 
|   83   else if (ext == L".jsp" || ext == L".php" || ext == L".html") |  147   else if (ext == L".jsp" || ext == L".php" || ext == L".html") | 
|   84   { |  148   { | 
|   85     return CFilter::contentTypeSubdocument; |  149     return CFilter::contentTypeSubdocument; | 
|   86   } |  150   } | 
|   87   else |  151   return CFilter::contentTypeAny; | 
|   88   { |  152 } | 
|   89     return CFilter::contentTypeAny & ~CFilter::contentTypeSubdocument; |  153  | 
|   90   } |  154 int WBPassthruSink::GetContentType(const CString& mimeType, const std::wstring& 
     domain, const std::wstring& src) | 
|   91  |  | 
|   92 } |  | 
|   93  |  | 
|   94 int WBPassthruSink::GetContentType(CString mimeType, const std::wstring& domain,
      const std::wstring& src) |  | 
|   95 { |  155 { | 
|   96   // No referer or mime type |  156   // No referer or mime type | 
|   97   // BINDSTRING_XDR_ORIGIN works only for IE v8+ |  157   // BINDSTRING_XDR_ORIGIN works only for IE v8+ | 
|   98   if (mimeType.IsEmpty() && domain.empty() && CPluginClient::GetInstance()->GetI
     EVersion() >= 8) |  158   if (mimeType.IsEmpty() && domain.empty() && CPluginClient::GetInstance()->GetI
     EVersion() >= 8) | 
|   99   { |  159   { | 
|  100     return CFilter::contentTypeXmlHttpRequest; |  160     return CFilter::contentTypeXmlHttpRequest; | 
|  101   } |  161   } | 
|  102   int contentType = GetContentTypeFromMimeType(mimeType); |  162   int contentType = GetContentTypeFromMimeType(mimeType); | 
|  103   if (contentType == CFilter::contentTypeAny) |  163   if (contentType == CFilter::contentTypeAny) | 
|  104   { |  164   { | 
|  105     contentType = GetContentTypeFromURL(src); |  165     contentType = GetContentTypeFromURL(src); | 
|  106   } |  166   } | 
|  107   return contentType; |  167   return contentType; | 
|  108 } |  168 } | 
|  109  |  169  | 
|  110 ////////////////////////////////////////////////////////////////////////////////
     //////// |  170 ////////////////////////////////////////////////////////////////////////////////
     //////// | 
|  111 //WBPassthruSink |  171 //WBPassthruSink | 
|  112 //Monitor and/or cancel every request and responde |  172 //Monitor and/or cancel every request and responde | 
|  113 //WB makes, including images, sounds, scripts, etc |  173 //WB makes, including images, sounds, scripts, etc | 
|  114 ////////////////////////////////////////////////////////////////////////////////
     //////// |  174 ////////////////////////////////////////////////////////////////////////////////
     //////// | 
|  115 HRESULT WBPassthruSink::OnStart(LPCWSTR szUrl, IInternetProtocolSink *pOIProtSin
     k, |  175 HRESULT WBPassthruSink::OnStart(LPCWSTR szUrl, IInternetProtocolSink *pOIProtSin
     k, | 
|  116                                 IInternetBindInfo *pOIBindInfo, DWORD grfPI, HAN
     DLE_PTR dwReserved, |  176                                 IInternetBindInfo *pOIBindInfo, DWORD grfPI, HAN
     DLE_PTR dwReserved, | 
|  117                                 IInternetProtocol* pTargetProtocol) |  177                                 IInternetProtocol* pTargetProtocol, bool& handle
     d) | 
|  118 { |  178 { | 
|  119  |  | 
|  120   m_pTargetProtocol = pTargetProtocol; |  179   m_pTargetProtocol = pTargetProtocol; | 
|  121   bool isBlocked = false; |  180   return BaseClass::OnStart(szUrl, pOIProtSink, pOIBindInfo, grfPI, dwReserved, 
     pTargetProtocol); | 
|  122   m_shouldBlock = false; |  181 } | 
|  123   m_lastDataReported = false; |  182  | 
|  124   std::wstring src(szUrl); |  183 HRESULT WBPassthruSink::OnRead(void* pv, ULONG cb, ULONG* pcbRead) | 
|  125   DEBUG_GENERAL(ToCString(src)); |  184 { | 
|  126   UnescapeUrl(src); |  185   if (!pv || !pcbRead) | 
|  127  |  186   { | 
|  128   std::wstring boundDomain; |  187     return E_POINTER; | 
|  129   CString mimeType; |  188   } | 
|  130   LPOLESTR mime[10]; |  189   *pcbRead = 0; | 
|  131   if (pOIBindInfo) |  190  | 
|  132   { |  191   if (PassthroughAPP::CustomSinkStartPolicy<WBPassthru, WBPassthruSink>::GetProt
     ocol(this)->m_shouldSupplyCustomContent) | 
|  133     ULONG resLen = 0; |  192   { | 
|  134  |  193     ULONG blockedByABPPageSize = static_cast<ULONG>(g_blockedByABPPage.size()); | 
|  135     // Apparently IE will report random mime type if there's more then 1 in the 
     list. |  194     auto positionGrow = std::min<ULONG>(cb, static_cast<ULONG>(blockedByABPPageS
     ize - m_currentPositionOfSentPage)); | 
|  136     // So we get the whole list and just use the first one (top priority one) |  195     if (positionGrow == 0) { | 
|  137     pOIBindInfo->GetBindString(BINDSTRING_ACCEPT_MIMES, mime, 10, &resLen); |  196       return S_FALSE; | 
|  138     if (mime && resLen > 0) |  197     } | 
|  139     { |  198     std::copy(g_blockedByABPPage.begin(), g_blockedByABPPage.begin() + positionG
     row, | 
|  140       mimeType.SetString(mime[0]); |  199       stdext::make_checked_array_iterator(static_cast<char*>(pv), cb)); | 
|  141     } |  200     *pcbRead = positionGrow; | 
|  142     LPOLESTR bindToObject = 0; |  201     m_currentPositionOfSentPage += positionGrow; | 
|  143     pOIBindInfo->GetBindString(BINDSTRING_FLAG_BIND_TO_OBJECT, &bindToObject, 1,
      &resLen); |  202  | 
|  144     wchar_t* domainRetrieved = 0; |  203     if (m_spInternetProtocolSink) | 
|  145     if (resLen == 0 || wcscmp(bindToObject, L"FALSE") == 0) |  204     { | 
|  146     { |  205       m_spInternetProtocolSink->ReportData(BSCF_INTERMEDIATEDATANOTIFICATION, | 
|  147       HRESULT hr = pOIBindInfo->GetBindString(BINDSTRING_XDR_ORIGIN, &domainRetr
     ieved, 1, &resLen); |  206         static_cast<ULONG>(m_currentPositionOfSentPage), blockedByABPPageSize); | 
|  148        |  207     } | 
|  149       if ((hr == S_OK) && domainRetrieved && (resLen > 0)) |  208     if (blockedByABPPageSize == m_currentPositionOfSentPage && m_spInternetProto
     colSink) | 
|  150       { |  209     { | 
|  151         boundDomain = std::wstring(domainRetrieved); |  210       m_spInternetProtocolSink->ReportData(BSCF_DATAFULLYAVAILABLE, blockedByABP
     PageSize, blockedByABPPageSize); | 
|  152       } |  211       m_spInternetProtocolSink->ReportResult(S_OK, 0, nullptr); | 
|  153     } |  | 
|  154   } |  | 
|  155  |  | 
|  156   CString cookie; |  | 
|  157   ULONG len1 = 2048; |  | 
|  158   ULONG len2 = 2048; |  | 
|  159  |  | 
|  160   int contentType = CFilter::contentTypeAny; |  | 
|  161  |  | 
|  162   CPluginTab* tab = CPluginClass::GetTab(::GetCurrentThreadId()); |  | 
|  163   CPluginClient* client = CPluginClient::GetInstance(); |  | 
|  164  |  | 
|  165  |  | 
|  166   if (tab && client) |  | 
|  167   { |  | 
|  168     std::wstring documentUrl = tab->GetDocumentUrl(); |  | 
|  169     // Page is identical to document => don't block |  | 
|  170     if (documentUrl == src) |  | 
|  171     { |  | 
|  172       // fall through |  | 
|  173     } |  | 
|  174     else if (CPluginSettings::GetInstance()->IsPluginEnabled() && !client->IsWhi
     telistedUrl(documentUrl)) |  | 
|  175     { |  | 
|  176       boundDomain = tab->GetDocumentUrl(); |  | 
|  177       contentType = CFilter::contentTypeAny; |  | 
|  178       if ((tab != 0) && (tab->IsFrameCached(src))) |  | 
|  179       { |  | 
|  180         contentType = CFilter::contentTypeSubdocument; |  | 
|  181       } |  | 
|  182       else |  | 
|  183       { |  | 
|  184         contentType = GetContentType(mimeType, boundDomain, src); |  | 
|  185       } |  | 
|  186       if (client->ShouldBlock(src, contentType, boundDomain, true)) |  | 
|  187       { |  | 
|  188         isBlocked = true; |  | 
|  189         DEBUG_BLOCKER("Blocker::Blocking Http-request:" + ToCString(src)); |  | 
|  190       } |  | 
|  191     } |  | 
|  192     if (!isBlocked) |  | 
|  193     { |  | 
|  194       DEBUG_BLOCKER("Blocker::Ignoring Http-request:" + ToCString(src)) |  | 
|  195     } |  | 
|  196   } |  | 
|  197  |  | 
|  198  |  | 
|  199   if (tab == NULL) |  | 
|  200   { |  | 
|  201     contentType = GetContentType(mimeType, boundDomain, src); |  | 
|  202     if (client->ShouldBlock(src, contentType, boundDomain, true)) |  | 
|  203     { |  | 
|  204       isBlocked = true; |  | 
|  205     } |  | 
|  206   } |  | 
|  207  |  | 
|  208 #ifdef _DEBUG |  | 
|  209   CString type; |  | 
|  210  |  | 
|  211   if (contentType == CFilter::contentTypeDocument) type = "DOCUMENT"; |  | 
|  212   else if (contentType == CFilter::contentTypeObject) type = "OBJECT"; |  | 
|  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   { |  | 
|  223     CPluginDebug::DebugResultBlocking(type, src, boundDomain); |  | 
|  224   } |  | 
|  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     { |  | 
|  236       m_shouldBlock = true; |  | 
|  237       BaseClass::OnStart(szUrl, pOIProtSink, pOIBindInfo, grfPI, dwReserved, pTa
     rgetProtocol); |  | 
|  238  |  | 
|  239       return INET_E_REDIRECT_FAILED; |  | 
|  240  |  | 
|  241     } |  | 
|  242     if (((contentType == CFilter::contentTypeSubdocument))&& (isBlocked))  |  | 
|  243     { |  | 
|  244       m_shouldBlock = true; |  | 
|  245       BaseClass::OnStart(szUrl, pOIProtSink, pOIBindInfo, grfPI, dwReserved, pTa
     rgetProtocol); |  | 
|  246  |  | 
|  247       m_spInternetProtocolSink->ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE, L"t
     ext/html"); |  | 
|  248  |  | 
|  249       //Here we check if we are running on Windows 8 Consumer Preview.  |  | 
|  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     }  |  | 
|  258     if (((contentType == CFilter::contentTypeScript)) && (isBlocked))  |  | 
|  259     { |  | 
|  260       m_shouldBlock = true; |  | 
|  261       BaseClass::OnStart(szUrl, pOIProtSink, pOIBindInfo, grfPI, dwReserved, pTa
     rgetProtocol); |  | 
|  262       m_spInternetProtocolSink->ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE, L"t
     ext/javascript"); |  | 
|  263       m_spInternetProtocolSink->ReportResult(INET_E_REDIRECTING, 301, L"data:"); |  | 
|  264       return INET_E_REDIRECT_FAILED; |  | 
|  265     } |  | 
|  266     if ((contentType == CFilter::contentTypeXmlHttpRequest) && (isBlocked))  |  | 
|  267     { |  | 
|  268       m_shouldBlock = true; |  | 
|  269       BaseClass::OnStart(szUrl, pOIProtSink, pOIBindInfo, grfPI, dwReserved, pTa
     rgetProtocol); |  | 
|  270       m_spInternetProtocolSink->ReportResult(INET_E_REDIRECTING, 301, L"data:"); |  | 
|  271       return INET_E_REDIRECT_FAILED; |  | 
|  272     } |  | 
|  273     if ((isBlocked))  |  | 
|  274     { |  | 
|  275       m_shouldBlock = true; |  | 
|  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; |  | 
|  280     } |  | 
|  281   } |  | 
|  282   return isBlocked ? S_FALSE : BaseClass::OnStart(szUrl, pOIProtSink, pOIBindInf
     o, grfPI, dwReserved, pTargetProtocol); |  | 
|  283 } |  | 
|  284  |  | 
|  285  |  | 
|  286 HRESULT WBPassthruSink::Read(void *pv, ULONG cb, ULONG* pcbRead) |  | 
|  287 { |  | 
|  288   if (m_shouldBlock) |  | 
|  289   { |  | 
|  290     *pcbRead = 0; |  | 
|  291     if (!m_lastDataReported) |  | 
|  292     { |  | 
|  293       if (cb <= 1) |  | 
|  294       { |  | 
|  295         //IE must've gone nuts if this happened, but let's be cool about it and 
     report we have no more data |  | 
|  296         m_spInternetProtocolSink->ReportResult(S_FALSE, 0, NULL); |  | 
|  297         return S_FALSE; |  | 
|  298       } |  | 
|  299       *pcbRead = 1; |  | 
|  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     } |  212     } | 
|  310     return S_OK; |  213     return S_OK; | 
|  311   } |  214   } | 
|  312   else  |  215   return m_pTargetProtocol->Read(pv, cb, pcbRead); | 
|  313   { |  | 
|  314  |  | 
|  315     return m_pTargetProtocol->Read(pv, cb, pcbRead); |  | 
|  316   } |  | 
|  317   return S_OK; |  | 
|  318 } |  216 } | 
|  319 STDMETHODIMP WBPassthruSink::Switch( |  217 STDMETHODIMP WBPassthruSink::Switch( | 
|  320   /* [in] */ PROTOCOLDATA *pProtocolData) |  218   /* [in] */ PROTOCOLDATA *pProtocolData) | 
|  321 { |  219 { | 
|  322   ATLASSERT(m_spInternetProtocolSink != 0); |  220   ATLASSERT(m_spInternetProtocolSink != 0); | 
|  323  |  221  | 
|  324   /* |  222   /* | 
|  325   From Igor Tandetnik "itandetnik@mvps.org" |  223   From Igor Tandetnik "itandetnik@mvps.org" | 
|  326   " |  224   " | 
|  327   Beware multithreading. URLMon has this nasty habit of spinning worker  |  225   Beware multithreading. URLMon has this nasty habit of spinning worker  | 
|  328   threads, not even bothering to initialize COM on them, and calling APP  |  226   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  |  227   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).  |  228   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.  |  229   You are only guaranteed to be on the main STA thread in two cases.  | 
|  332   First, in methods of interfaces that were obtained with  |  230   First, in methods of interfaces that were obtained with  | 
|  333   IServiceProvider, such as IHttpNegotiage::BeginningTransaction or  |  231   IServiceProvider, such as IHttpNegotiage::BeginningTransaction or  | 
|  334   IAuthenticate::Authenticate. Second, you can call  |  232   IAuthenticate::Authenticate. Second, you can call  | 
|  335   IInternetProtocolSink::Switch with PD_FORCE_SWITCH flag in  |  233   IInternetProtocolSink::Switch with PD_FORCE_SWITCH flag in  | 
|  336   PROTOCOLDATA::grfFlags, eventually URLMon will turn around and call  |  234   PROTOCOLDATA::grfFlags, eventually URLMon will turn around and call  | 
|  337   IInternetProtocol::Continue on the main thread.  |  235   IInternetProtocol::Continue on the main thread.  | 
|  338  |  236  | 
|  339   Or, if you happen to have a window handy that was created on the main  |  237   Or, if you happen to have a window handy that was created on the main  | 
|  340   thread, you can post yourself a message. |  238   thread, you can post yourself a message. | 
|  341   " |  239   " | 
|  342   */ |  240   */ | 
|  343   return m_spInternetProtocolSink ? m_spInternetProtocolSink->Switch(pProtocolDa
     ta) : E_UNEXPECTED; |  241   return m_spInternetProtocolSink ? m_spInternetProtocolSink->Switch(pProtocolDa
     ta) : E_UNEXPECTED; | 
|  344 } |  242 } | 
|  345  |  243  | 
|  346  |  244 // This is the heuristic which detects the requests issued by Flash.ocx. | 
|  347 STDMETHODIMP WBPassthruSink::BeginningTransaction(LPCWSTR szURL, LPCWSTR szHeade
     rs, DWORD dwReserved, LPWSTR *pszAdditionalHeaders) |  245 // It turned out that the implementation from ''Flash.ocx'' (tested version is 1
     5.0.0.152) | 
|  348 { |  246 // returns quite minimal configuration in comparison with the implementation fro
     m Microsofts' | 
 |  247 // libraries (see grfBINDF and bindInfo.dwOptions). The impl from MS often inclu
     des something | 
 |  248 // else. | 
 |  249 bool WBPassthruSink::IsFlashRequest(const wchar_t* const* additionalHeaders) | 
 |  250 { | 
 |  251   if (additionalHeaders && *additionalHeaders) | 
 |  252   { | 
 |  253     auto flashVersionHeader = ExtractHttpHeader<std::wstring>(*additionalHeaders
     , L"x-flash-version:", L"\n"); | 
 |  254     if (!TrimString(flashVersionHeader).empty()) | 
 |  255     { | 
 |  256       return true; | 
 |  257     } | 
 |  258   } | 
 |  259   ATL::CComPtr<IBindStatusCallback> bscb; | 
 |  260   if (SUCCEEDED(QueryServiceFromClient(&bscb)) && !!bscb) | 
 |  261   { | 
 |  262     DWORD grfBINDF = 0; | 
 |  263     BINDINFO bindInfo = {}; | 
 |  264     bindInfo.cbSize = sizeof(bindInfo); | 
 |  265     if (SUCCEEDED(bscb->GetBindInfo(&grfBINDF, &bindInfo)) && | 
 |  266       (BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE| BINDF_PULLDATA) == grfBINDF && | 
 |  267       (BINDINFO_OPTIONS_ENABLE_UTF8 | BINDINFO_OPTIONS_USE_IE_ENCODING) == bindI
     nfo.dwOptions | 
 |  268       ) | 
 |  269     { | 
 |  270       return true; | 
 |  271     } | 
 |  272   } | 
 |  273   return false; | 
 |  274 } | 
 |  275  | 
 |  276 STDMETHODIMP WBPassthruSink::BeginningTransaction(LPCWSTR szURL, LPCWSTR szHeade
     rs, DWORD dwReserved, LPWSTR* pszAdditionalHeaders) | 
 |  277 { | 
 |  278   if (!szURL) | 
 |  279   { | 
 |  280     return E_POINTER; | 
 |  281   } | 
 |  282   std::wstring src = szURL; | 
 |  283   DEBUG_GENERAL(ToCString(src)); | 
 |  284  | 
 |  285   std::string acceptHeader = ExtractHttpAcceptHeader(m_spTargetProtocol); | 
 |  286   m_contentType = GetContentTypeFromMimeType(ATL::CString(acceptHeader.c_str()))
     ; | 
 |  287  | 
|  349   if (pszAdditionalHeaders) |  288   if (pszAdditionalHeaders) | 
|  350   { |  289   { | 
|  351     *pszAdditionalHeaders = 0; |  290     *pszAdditionalHeaders = nullptr; | 
 |  291   } | 
 |  292  | 
 |  293   CComPtr<IHttpNegotiate> httpNegotiate; | 
 |  294   QueryServiceFromClient(&httpNegotiate); | 
 |  295   // This fills the pszAdditionalHeaders with more headers. One of which is the 
     Referer header, which we need. | 
 |  296   // There doesn't seem to be any other way to get this header before the reques
     t has been made. | 
 |  297   HRESULT nativeHr = httpNegotiate ? httpNegotiate->BeginningTransaction(szURL, 
     szHeaders, dwReserved, pszAdditionalHeaders) : S_OK; | 
 |  298  | 
 |  299   if (pszAdditionalHeaders && *pszAdditionalHeaders) | 
 |  300   { | 
 |  301     m_boundDomain = ExtractHttpHeader<std::wstring>(*pszAdditionalHeaders, L"Ref
     erer:", L"\n"); | 
 |  302   } | 
 |  303   m_boundDomain = TrimString(m_boundDomain); | 
 |  304   CPluginTab* tab = CPluginClass::GetTab(::GetCurrentThreadId()); | 
 |  305   CPluginClient* client = CPluginClient::GetInstance(); | 
 |  306  | 
 |  307   if (tab && client) | 
 |  308   { | 
 |  309     std::wstring documentUrl = tab->GetDocumentUrl(); | 
 |  310     // Page is identical to document => don't block | 
 |  311     if (documentUrl == src) | 
 |  312     { | 
 |  313       return nativeHr; | 
 |  314     } | 
 |  315     else if (CPluginSettings::GetInstance()->IsPluginEnabled() && !client->IsWhi
     telistedUrl(documentUrl)) | 
 |  316     { | 
 |  317       if (tab->IsFrameCached(src)) | 
 |  318       { | 
 |  319         m_contentType = CFilter::contentTypeSubdocument; | 
 |  320       } | 
 |  321     } | 
 |  322   } | 
 |  323  | 
 |  324   if (IsFlashRequest(pszAdditionalHeaders)) | 
 |  325   { | 
 |  326     m_contentType = CFilter::EContentType::contentTypeObjectSubrequest; | 
 |  327   } | 
 |  328  | 
 |  329   if (pszAdditionalHeaders && *pszAdditionalHeaders && IsXmlHttpRequest(*pszAddi
     tionalHeaders)) | 
 |  330   { | 
 |  331     m_contentType = CFilter::EContentType::contentTypeXmlHttpRequest; | 
 |  332   } | 
 |  333  | 
 |  334   if (client->ShouldBlock(szURL, m_contentType, m_boundDomain, /*debug flag but 
     must be set*/true)) | 
 |  335   { | 
 |  336     // NOTE: Feeding custom HTML to Flash, instead of original object subrequest | 
 |  337     // doesn't have much sense. It also can manifest in unwanted result» | 
 |  338     // like video being blocked (See https://issues.adblockplus.org/ticket/1669)
     »        | 
 |  339     // So we report blocked object subrequests as failed, not just empty HTML. | 
 |  340     m_isCustomResponse = m_contentType != CFilter::contentTypeObjectSubrequest;  | 
 |  341     return E_ABORT; | 
 |  342   } | 
 |  343   return nativeHr; | 
 |  344 } | 
 |  345  | 
 |  346 STDMETHODIMP WBPassthruSink::OnResponse(DWORD dwResponseCode, LPCWSTR szResponse
     Headers, LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders) | 
 |  347 { | 
 |  348   if (pszAdditionalRequestHeaders) | 
 |  349   { | 
 |  350     *pszAdditionalRequestHeaders = 0; | 
|  352   } |  351   } | 
|  353  |  352  | 
|  354   CComPtr<IHttpNegotiate> spHttpNegotiate; |  353   CComPtr<IHttpNegotiate> spHttpNegotiate; | 
|  355   QueryServiceFromClient(&spHttpNegotiate); |  354   QueryServiceFromClient(&spHttpNegotiate); | 
|  356   return spHttpNegotiate ? spHttpNegotiate->BeginningTransaction(szURL, szHeader
     s,dwReserved, pszAdditionalHeaders) : S_OK; |  | 
|  357 } |  | 
|  358  |  | 
|  359 STDMETHODIMP WBPassthruSink::OnResponse(DWORD dwResponseCode, LPCWSTR szResponse
     Headers, LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders) |  | 
|  360 { |  | 
|  361   if (pszAdditionalRequestHeaders) |  | 
|  362   { |  | 
|  363     *pszAdditionalRequestHeaders = 0; |  | 
|  364   } |  | 
|  365  |  | 
|  366   CComPtr<IHttpNegotiate> spHttpNegotiate; |  | 
|  367   QueryServiceFromClient(&spHttpNegotiate); |  | 
|  368  |  355  | 
|  369   return spHttpNegotiate ? spHttpNegotiate->OnResponse(dwResponseCode, szRespons
     eHeaders, szRequestHeaders, pszAdditionalRequestHeaders) : S_OK; |  356   return spHttpNegotiate ? spHttpNegotiate->OnResponse(dwResponseCode, szRespons
     eHeaders, szRequestHeaders, pszAdditionalRequestHeaders) : S_OK; | 
|  370 } |  357 } | 
|  371  |  358  | 
|  372 STDMETHODIMP WBPassthruSink::ReportProgress(ULONG ulStatusCode, LPCWSTR szStatus
     Text) |  359 STDMETHODIMP WBPassthruSink::ReportProgress(ULONG ulStatusCode, LPCWSTR szStatus
     Text) | 
|  373 { |  360 { | 
|  374   return m_spInternetProtocolSink ? m_spInternetProtocolSink->ReportProgress(ulS
     tatusCode, szStatusText) : S_OK; |  361   return m_spInternetProtocolSink ? m_spInternetProtocolSink->ReportProgress(ulS
     tatusCode, szStatusText) : S_OK; | 
|  375 } |  362 } | 
|  376  |  363  | 
 |  364 STDMETHODIMP WBPassthruSink::ReportResult(/* [in] */ HRESULT hrResult, /* [in] *
     / DWORD dwError, /* [in] */ LPCWSTR szResult) | 
 |  365 { | 
 |  366   if (m_isCustomResponse) | 
 |  367   { | 
 |  368     // Don't notify the client about aborting of the operation, thus don't call 
     BaseClass::ReportResult. | 
 |  369     // Current method is called by the original protocol implementation and we a
     re intercepting the | 
 |  370     // call here and eating it, we will call the proper ReportResult later by ou
     rself. | 
 |  371     return S_OK; | 
 |  372   } | 
 |  373   return BaseClass::ReportResult(hrResult, dwError, szResult); | 
 |  374 } | 
 |  375  | 
 |  376  | 
 |  377 WBPassthru::WBPassthru() | 
 |  378   : m_shouldSupplyCustomContent(false) | 
 |  379 { | 
 |  380 } | 
|  377  |  381  | 
|  378 STDMETHODIMP WBPassthru::Start(LPCWSTR szUrl, IInternetProtocolSink *pOIProtSink
     , |  382 STDMETHODIMP WBPassthru::Start(LPCWSTR szUrl, IInternetProtocolSink *pOIProtSink
     , | 
|  379     IInternetBindInfo *pOIBindInfo, DWORD grfPI, HANDLE_PTR dwReserved) |  383     IInternetBindInfo *pOIBindInfo, DWORD grfPI, HANDLE_PTR dwReserved) | 
|  380 { |  384 { | 
|  381   ATLASSERT(m_spInternetProtocol != 0); |  385   ATLASSERT(m_spInternetProtocol != 0); | 
|  382   if (!m_spInternetProtocol) |  386   if (!m_spInternetProtocol) | 
|  383   { |  387   { | 
|  384     return E_UNEXPECTED; |  388     return E_UNEXPECTED; | 
|  385   } |  389   } | 
|  386  |  390  | 
|  387   return OnStart(szUrl, pOIProtSink, pOIBindInfo, grfPI, |  391   return OnStart(szUrl, pOIProtSink, pOIBindInfo, grfPI, dwReserved, m_spInterne
     tProtocol); | 
|  388     dwReserved, m_spInternetProtocol); |  392 } | 
|  389 } |  393  | 
|  390  |  394 STDMETHODIMP WBPassthru::Read(/* [in, out] */ void *pv,/* [in] */ ULONG cb,/* [o
     ut] */ ULONG *pcbRead) | 
|  391  STDMETHODIMP WBPassthru::Read(»/* [in, out] */ void *pv,/* [in] */ ULONG cb,/* 
     [out] */ ULONG *pcbRead) |  395 { | 
|  392  { |  396   WBPassthruSink* pSink = GetSink(); | 
|  393     |  397   return pSink->OnRead(pv, cb, pcbRead); | 
|  394    WBPassthruSink* pSink = GetSink(); |  398 } | 
|  395    return pSink->Read(pv, cb, pcbRead); |  | 
|  396  } |  | 
| LEFT | RIGHT |