Index: src/plugin/AdblockPlusDomTraverser.cpp
===================================================================
--- a/src/plugin/AdblockPlusDomTraverser.cpp
+++ b/src/plugin/AdblockPlusDomTraverser.cpp
@@ -108,9 +108,8 @@
 
 
 bool CPluginDomTraverser::IsEnabled()
-{ 
+{
   CPluginClient* client = CPluginClient::GetInstance();
-
   return client && CPluginSettings::GetInstance()->IsPluginEnabled() && !client->IsWhitelistedUrl(m_domain);
 }
 
Index: src/plugin/PluginFilter.cpp
===================================================================
--- a/src/plugin/PluginFilter.cpp
+++ b/src/plugin/PluginFilter.cpp
@@ -420,6 +420,7 @@
 {
   m_contentMapText[CFilter::contentTypeDocument] = "DOCUMENT";
   m_contentMapText[CFilter::contentTypeObject] = "OBJECT";
+  m_contentMapText[CFilter::contentTypeObjectSubrequest] = "OBJECT-SUBREQUEST";
   m_contentMapText[CFilter::contentTypeImage] = "IMAGE";
   m_contentMapText[CFilter::contentTypeScript] = "SCRIPT";
   m_contentMapText[CFilter::contentTypeOther] = "OTHER";
@@ -707,5 +708,8 @@
     }
     return true;
   }
+#ifdef ENABLE_DEBUG_RESULT
+  CPluginDebug::DebugResultIgnoring(type, src, domain);
+#endif
   return false;
 }
Index: src/plugin/PluginTabBase.cpp
===================================================================
--- a/src/plugin/PluginTabBase.cpp
+++ b/src/plugin/PluginTabBase.cpp
@@ -208,9 +208,6 @@
         docHostUIHandler->UpdateUI();
       }
     }
-
-    pDoc.Release();
-    pDocDispatch.Release();
   }
 }
 
Index: src/plugin/PluginWbPassThrough.cpp
===================================================================
--- a/src/plugin/PluginWbPassThrough.cpp
+++ b/src/plugin/PluginWbPassThrough.cpp
@@ -7,14 +7,27 @@
 #include "PluginSettings.h"
 #include "PluginClass.h"
 #include "PluginSystem.h"
-
+#include <WinInet.h>
 #include "wtypes.h"
 
-EXTERN_C IMAGE_DOS_HEADER __ImageBase;
+namespace
+{
+  std::string g_blockedByABPPage = "<!DOCTYPE html>"
+    "<html>"
+        "<body>"
+          "<!-- blocked by AdblockPlus -->"
+        "</body>"
+    "</html>";
+}
 
+WBPassthruSink::WBPassthruSink()
+  : m_currentPositionOfSentPage(0)
+  , m_contentType(CFilter::EContentType::contentTypeAny)
+  , m_blockedInTransaction(false)
+{
+}
 
-
-int WBPassthruSink::GetContentTypeFromMimeType(CString mimeType)
+int WBPassthruSink::GetContentTypeFromMimeType(const CString& mimeType)
 {
   if (mimeType.Find(L"image/") >= 0)
   {
@@ -45,7 +58,7 @@
   return CFilter::contentTypeAny;
 }
 
-int WBPassthruSink::GetContentTypeFromURL(CString src)
+int WBPassthruSink::GetContentTypeFromURL(const CString& src)
 {
   CString srcExt = src;
 
@@ -83,14 +96,10 @@
   {
     return CFilter::contentTypeSubdocument;
   }
-  else
-  {
-    return CFilter::contentTypeAny & ~CFilter::contentTypeSubdocument;
-  }
-
+  return CFilter::contentTypeAny;
 }
 
-int WBPassthruSink::GetContentType(CString mimeType, std::wstring domain, CString src)
+int WBPassthruSink::GetContentType(const CString& mimeType, const std::wstring& domain, const CString& src)
 {
   // No referer or mime type
   // BINDSTRING_XDR_ORIGIN works only for IE v8+
@@ -113,56 +122,57 @@
 ////////////////////////////////////////////////////////////////////////////////////////
 HRESULT WBPassthruSink::OnStart(LPCWSTR szUrl, IInternetProtocolSink *pOIProtSink,
                                 IInternetBindInfo *pOIBindInfo, DWORD grfPI, HANDLE_PTR dwReserved,
-                                IInternetProtocol* pTargetProtocol)
+                                IInternetProtocol* pTargetProtocol, bool& handled)
 {
-
   m_pTargetProtocol = pTargetProtocol;
   bool isBlocked = false;
-  m_shouldBlock = false;
-  m_lastDataReported = false;
-  CString src;
-  src.Append(szUrl);
+  CString src = szUrl;
   DEBUG_GENERAL(src);
   CPluginClient::UnescapeUrl(src);
 
-  std::wstring boundDomain;
+  // call the impl of the base class as soon as possible because it initializes the base class
+  // members, used by this method. It queries for the required interfaces.
+  HRESULT hr = BaseClass::OnStart(szUrl, pOIProtSink, pOIBindInfo, grfPI, dwReserved, pTargetProtocol);
+  if (FAILED(hr))
+  {
+    return hr;
+  }
+
   CString mimeType;
-  LPOLESTR mime[10];
   if (pOIBindInfo)
   {
     ULONG resLen = 0;
 
     // Apparently IE will report random mime type if there's more then 1 in the list.
     // So we get the whole list and just use the first one (top priority one)
+    LPOLESTR mime[10];
     pOIBindInfo->GetBindString(BINDSTRING_ACCEPT_MIMES, mime, 10, &resLen);
     if (mime && resLen > 0)
     {
       mimeType.SetString(mime[0]);
     }
-    LPOLESTR bindToObject = 0;
-    pOIBindInfo->GetBindString(BINDSTRING_FLAG_BIND_TO_OBJECT, &bindToObject, 1, &resLen);
-    wchar_t* domainRetrieved = 0;
-    if (resLen == 0 || wcscmp(bindToObject, L"FALSE") == 0)
+    LPOLESTR bindString = nullptr;
+    pOIBindInfo->GetBindString(BINDSTRING_FLAG_BIND_TO_OBJECT, &bindString, 1, &resLen);
+    LPOLESTR domainRetrieved = nullptr;
+    if (resLen == 0 || wcscmp(bindString, L"FALSE") == 0)
     {
       HRESULT hr = pOIBindInfo->GetBindString(BINDSTRING_XDR_ORIGIN, &domainRetrieved, 1, &resLen);
-      
       if ((hr == S_OK) && domainRetrieved && (resLen > 0))
       {
-        boundDomain = std::wstring(domainRetrieved);
+        m_boundDomain = domainRetrieved;
       }
     }
+    // We can obtain IBindCtx* here, but IEnumString obtained via IBindCtx::EnumObjectParam
+    // does not return any parameter, so it's useless.
   }
 
   CString cookie;
   ULONG len1 = 2048;
   ULONG len2 = 2048;
 
-  int contentType = CFilter::contentTypeAny;
-
   CPluginTab* tab = CPluginClass::GetTab(::GetCurrentThreadId());
   CPluginClient* client = CPluginClient::GetInstance();
 
-
   if (tab && client)
   {
     CString documentUrl = tab->GetDocumentUrl();
@@ -171,150 +181,133 @@
     {
       // fall through
     }
-    else if (CPluginSettings::GetInstance()->IsPluginEnabled() && !client->IsWhitelistedUrl(to_wstring(documentUrl)))
+    else if (CPluginSettings::GetInstance()->IsPluginEnabled() && !client->IsWhitelistedUrl(std::wstring(documentUrl)))
     {
-      boundDomain = to_wstring(tab->GetDocumentUrl());
-      contentType = CFilter::contentTypeAny;
-      if ((tab != 0) && (tab->IsFrameCached(src)))
+      m_boundDomain = tab->GetDocumentUrl();
+      m_contentType = CFilter::contentTypeAny;
+      if (tab != nullptr && tab->IsFrameCached(src))
       {
-        contentType = CFilter::contentTypeSubdocument;
+        m_contentType = CFilter::contentTypeSubdocument;
       }
       else
       {
-        contentType = GetContentType(mimeType, boundDomain, src);
+        m_contentType = GetContentType(mimeType, m_boundDomain, src);
       }
-      if (client->ShouldBlock(to_wstring(src), contentType, boundDomain, true))
-      {
-        isBlocked = true;
-        DEBUG_BLOCKER("Blocker::Blocking Http-request:" + src);
-      }
-    }
-    if (!isBlocked)
-    {
-      DEBUG_BLOCKER("Blocker::Ignoring Http-request:" + src)
     }
   }
 
+  if (tab == nullptr)
+  {
+    m_contentType = GetContentType(mimeType, m_boundDomain, src);
+  }
 
-  if (tab == NULL)
   {
-    contentType = GetContentType(mimeType, boundDomain, src);
-    if (client->ShouldBlock(to_wstring(src), contentType, boundDomain, true))
+    // Here is the heuristic which detects the requests issued by Flash.ocx.
+    // It turned out that the implementation from ''Flash.ocx'' (tested version is 15.0.0.152)
+    // returns quite minimal configuration in comparison with the implementation from Microsofts'
+    // libraries (see grfBINDF and bindInfo.dwOptions). The impl from MS often includes something
+    // else.
+    ATL::CComPtr<IBindStatusCallback> bscb;
+    if (SUCCEEDED(QueryServiceFromClient(&bscb)) && !!bscb)
     {
-      isBlocked = true;
+      DWORD grfBINDF = 0;
+      BINDINFO bindInfo = {};
+      bindInfo.cbSize = sizeof(bindInfo);
+      if (SUCCEEDED(bscb->GetBindInfo(&grfBINDF, &bindInfo))
+        && (BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE| BINDF_PULLDATA) == grfBINDF
+        && (BINDINFO_OPTIONS_ENABLE_UTF8 | BINDINFO_OPTIONS_USE_IE_ENCODING) == bindInfo.dwOptions
+        )
+      {
+        m_contentType = CFilter::EContentType::contentTypeObjectSubrequest;
+      }
     }
   }
 
-#ifdef _DEBUG
-  CString type;
+  // The descision about EContentType::contentTypeAny is made later in
+  // WBPassthruSink::BeginningTransaction. Sometimes here we cannot detect the request type, but
+  // in WBPassthruSink::BeginningTransaction the header Accept is available which allows to
+  // obtain the "request type" in our terminology.
+  if (nullptr != client
+    && CFilter::EContentType::contentTypeAny != m_contentType
+    && client->ShouldBlock(static_cast<const wchar_t*>(src), m_contentType, m_boundDomain, true))
+  {
+    isBlocked = true;
+  }
 
-  if (contentType == CFilter::contentTypeDocument) type = "DOCUMENT";
-  else if (contentType == CFilter::contentTypeObject) type = "OBJECT";
-  else if (contentType == CFilter::contentTypeImage) type = "IMAGE";
-  else if (contentType == CFilter::contentTypeScript) type = "SCRIPT";
-  else if (contentType == CFilter::contentTypeOther) type = "OTHER";
-  else if (contentType == CFilter::contentTypeUnknown) type = "OTHER";
-  else if (contentType == CFilter::contentTypeSubdocument) type = "SUBDOCUMENT";
-  else if (contentType == CFilter::contentTypeStyleSheet) type = "STYLESHEET";
-  else type = "OTHER";
-
-  if (isBlocked)
+  // For IE6 and earlier there is iframe back button issue, so avoid it.
+  if (isBlocked && client->GetIEVersion() > 6)
   {
-    CPluginDebug::DebugResultBlocking(type, src, boundDomain);
-  }
-  else
-  {
-    CPluginDebug::DebugResultIgnoring(type, src, boundDomain);
-  }
-#endif
-
-  //Fixes the iframe back button issue
-  if (client->GetIEVersion() > 6)
-  {
-    if ((contentType == CFilter::contentTypeImage) && (isBlocked))
+    handled = true;
+    if (CFilter::EContentType::contentTypeImage == m_contentType)
     {
-      m_shouldBlock = true;
-      BaseClass::OnStart(szUrl, pOIProtSink, pOIBindInfo, grfPI, dwReserved, pTargetProtocol);
-
+      // IE shows a cross that img is not loaded
       return INET_E_REDIRECT_FAILED;
-
     }
-    if (((contentType == CFilter::contentTypeSubdocument))&& (isBlocked)) 
+    if (CFilter::EContentType::contentTypeSubdocument == m_contentType)
     {
-      m_shouldBlock = true;
-      BaseClass::OnStart(szUrl, pOIProtSink, pOIBindInfo, grfPI, dwReserved, pTargetProtocol);
-
+      PassthroughAPP::CustomSinkStartPolicy<WBPassthru, WBPassthruSink>::GetProtocol(this)->m_shouldSupplyCustomContent = true;
       m_spInternetProtocolSink->ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE, L"text/html");
-
-      //Here we check if we are running on Windows 8 Consumer Preview. 
-      //For some reason on that environment the next line causes IE to crash
-      if (CPluginSettings::GetInstance()->GetWindowsBuildNumber() != 8250)
-      {
-        m_spInternetProtocolSink->ReportResult(INET_E_REDIRECT_FAILED, 0, szUrl);
-      }
-
-      return INET_E_REDIRECT_FAILED;
+      m_spInternetProtocolSink->ReportData(BSCF_FIRSTDATANOTIFICATION, 0, static_cast<ULONG>(g_blockedByABPPage.size()));
+      return S_OK;
     } 
-    if (((contentType == CFilter::contentTypeScript)) && (isBlocked)) 
+    if (CFilter::EContentType::contentTypeScript == m_contentType)
     {
-      m_shouldBlock = true;
-      BaseClass::OnStart(szUrl, pOIProtSink, pOIBindInfo, grfPI, dwReserved, pTargetProtocol);
       m_spInternetProtocolSink->ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE, L"text/javascript");
       m_spInternetProtocolSink->ReportResult(INET_E_REDIRECTING, 301, L"data:");
       return INET_E_REDIRECT_FAILED;
     }
-    if ((contentType == CFilter::contentTypeXmlHttpRequest) && (isBlocked)) 
+    if (CFilter::EContentType::contentTypeXmlHttpRequest == m_contentType)
     {
-      m_shouldBlock = true;
-      BaseClass::OnStart(szUrl, pOIProtSink, pOIBindInfo, grfPI, dwReserved, pTargetProtocol);
       m_spInternetProtocolSink->ReportResult(INET_E_REDIRECTING, 301, L"data:");
       return INET_E_REDIRECT_FAILED;
     }
-    if ((isBlocked)) 
+    if (CFilter::EContentType::contentTypeAny != m_contentType)
     {
-      m_shouldBlock = true;
-      BaseClass::OnStart(szUrl, pOIProtSink, pOIBindInfo, grfPI, dwReserved, pTargetProtocol);
-      m_spInternetProtocolSink->ReportResult(S_FALSE, 0, L"");
-
+      m_spInternetProtocolSink->ReportResult(INET_E_REDIRECTING, 301, L"data:");
       return INET_E_REDIRECT_FAILED;
     }
   }
-  return isBlocked ? S_FALSE : BaseClass::OnStart(szUrl, pOIProtSink, pOIBindInfo, grfPI, dwReserved, pTargetProtocol);
+
+  return isBlocked ? S_FALSE : hr;
 }
 
+HRESULT WBPassthruSink::OnRead(void* pv, ULONG cb, ULONG* pcbRead)
+{
+  if (pv == nullptr)
+  {
+    return E_POINTER;
+  }
+  if (pcbRead == nullptr)
+  {
+    return E_POINTER;
+  }
+  *pcbRead = 0;
 
-HRESULT WBPassthruSink::Read(void *pv, ULONG cb, ULONG* pcbRead)
-{
-  if (m_shouldBlock)
+  if (PassthroughAPP::CustomSinkStartPolicy<WBPassthru, WBPassthruSink>::GetProtocol(this)->m_shouldSupplyCustomContent)
   {
-    *pcbRead = 0;
-    if (!m_lastDataReported)
+    ULONG blockedByABPPageSize = static_cast<ULONG>(g_blockedByABPPage.size());
+    auto positionGrow = std::min<ULONG>(cb, static_cast<ULONG>(blockedByABPPageSize - m_currentPositionOfSentPage));
+    if (positionGrow == 0) {
+      return S_FALSE;
+    }
+    std::copy(g_blockedByABPPage.begin(), g_blockedByABPPage.begin() + positionGrow,
+      stdext::make_checked_array_iterator(static_cast<char*>(pv), cb));
+    *pcbRead = positionGrow;
+    m_currentPositionOfSentPage += positionGrow;
+
+    if (m_spInternetProtocolSink)
     {
-      if (cb <= 1)
-      {
-        //IE must've gone nuts if this happened, but let's be cool about it and report we have no more data
-        m_spInternetProtocolSink->ReportResult(S_FALSE, 0, NULL);
-        return S_FALSE;
-      }
-      *pcbRead = 1;
-      memcpy(pv, " ", 1);
-
-      if (m_spInternetProtocolSink != NULL)
-      {
-        m_spInternetProtocolSink->ReportResult(S_OK, 0, NULL);
-      }
-      m_lastDataReported = true;
-      m_shouldBlock = false;
-      return S_OK;
+      m_spInternetProtocolSink->ReportData(BSCF_INTERMEDIATEDATANOTIFICATION,
+        static_cast<ULONG>(m_currentPositionOfSentPage), blockedByABPPageSize);
+    }
+    if (blockedByABPPageSize == m_currentPositionOfSentPage && m_spInternetProtocolSink)
+    {
+      m_spInternetProtocolSink->ReportData(BSCF_DATAFULLYAVAILABLE, blockedByABPPageSize, blockedByABPPageSize);
+      m_spInternetProtocolSink->ReportResult(S_OK, 0, nullptr);
     }
     return S_OK;
   }
-  else 
-  {
-
-    return m_pTargetProtocol->Read(pv, cb, pcbRead);
-  }
-  return S_OK;
+  return m_pTargetProtocol->Read(pv, cb, pcbRead);
 }
 STDMETHODIMP WBPassthruSink::Switch(
   /* [in] */ PROTOCOLDATA *pProtocolData)
@@ -343,14 +336,63 @@
   return m_spInternetProtocolSink ? m_spInternetProtocolSink->Switch(pProtocolData) : E_UNEXPECTED;
 }
 
-
-STDMETHODIMP WBPassthruSink::BeginningTransaction(LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
+STDMETHODIMP WBPassthruSink::BeginningTransaction(LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR* pszAdditionalHeaders)
 {
   if (pszAdditionalHeaders)
   {
-    *pszAdditionalHeaders = 0;
+    *pszAdditionalHeaders = nullptr;
   }
 
+  CPluginClient* client = nullptr;
+  if (CFilter::EContentType::contentTypeAny == m_contentType && (client = CPluginClient::GetInstance()))
+  {
+    auto acceptHeader = [&]() -> std::string
+    {
+      // Despite there is HTTP_QUERY_ACCEPT and other query info flags, they don't work here,
+      // only HTTP_QUERY_RAW_HEADERS_CRLF | HTTP_QUERY_FLAG_REQUEST_HEADERS does dork.
+      ATL::CComPtr<IWinInetHttpInfo> winInetHttpInfo;
+      HRESULT hr = m_spTargetProtocol->QueryInterface(&winInetHttpInfo);
+      if(FAILED(hr))
+      {
+        return "";
+      }
+      DWORD size = 0;
+      DWORD flags = 0;
+      hr = winInetHttpInfo->QueryInfo(HTTP_QUERY_RAW_HEADERS_CRLF | HTTP_QUERY_FLAG_REQUEST_HEADERS,
+          /*buffer*/nullptr, /* get size */&size, &flags, /*reserved*/ 0);
+      if(FAILED(hr))
+      {
+        return "";
+      }
+      std::string buf(size, '\0');
+      hr = winInetHttpInfo->QueryInfo(HTTP_QUERY_RAW_HEADERS_CRLF | HTTP_QUERY_FLAG_REQUEST_HEADERS,
+        &buf[0], &size, &flags, 0);
+      if(FAILED(hr))
+      {
+        return "";
+      }
+      char acceptHeader[] = "Accept:";
+      auto acceptHeaderBeginsAt = buf.find(acceptHeader);
+      if (std::string::npos == acceptHeaderBeginsAt)
+      {
+        return "";
+      }
+      acceptHeaderBeginsAt += sizeof(acceptHeader);
+      auto acceptHeaderEndsAt = buf.find("\n", acceptHeaderBeginsAt);
+      if (std::string::npos == acceptHeaderEndsAt)
+      {
+        return "";
+      }
+      return buf.substr(acceptHeaderBeginsAt, acceptHeaderEndsAt - acceptHeaderBeginsAt);
+    }();
+    m_contentType = GetContentTypeFromMimeType(ATL::CString(acceptHeader.c_str()));
+    bool isBlocked = client->ShouldBlock(szURL, m_contentType, m_boundDomain, /*debug flag but must be set*/true);
+    if (isBlocked)
+    {
+      m_blockedInTransaction = true;
+      return E_ABORT;
+    }
+  }
   CComPtr<IHttpNegotiate> spHttpNegotiate;
   QueryServiceFromClient(&spHttpNegotiate);
   return spHttpNegotiate ? spHttpNegotiate->BeginningTransaction(szURL, szHeaders,dwReserved, pszAdditionalHeaders) : S_OK;
@@ -374,6 +416,24 @@
   return m_spInternetProtocolSink ? m_spInternetProtocolSink->ReportProgress(ulStatusCode, szStatusText) : S_OK;
 }
 
+STDMETHODIMP WBPassthruSink::ReportResult(/* [in] */ HRESULT hrResult, /* [in] */ DWORD dwError, /* [in] */ LPCWSTR szResult)
+{
+  if (m_blockedInTransaction)
+  {
+    // Don't notify the client about aborting of the operation, thus don't call BaseClass::ReportResult.
+    // Current method is called by the original protocol implementation and we are intercepting the
+    // call here and eating it, we will call the proper ReportResult later by ourself.
+    return S_OK;
+  }
+  return BaseClass::ReportResult(hrResult, dwError, szResult);
+}
+
+
+WBPassthru::WBPassthru()
+  : m_shouldSupplyCustomContent(false)
+  , m_hasOriginalStartCalled(false)
+{
+}
 
 STDMETHODIMP WBPassthru::Start(LPCWSTR szUrl, IInternetProtocolSink *pOIProtSink,
     IInternetBindInfo *pOIBindInfo, DWORD grfPI, HANDLE_PTR dwReserved)
@@ -384,13 +444,29 @@
     return E_UNEXPECTED;
   }
 
-  return OnStart(szUrl, pOIProtSink, pOIBindInfo, grfPI,
-    dwReserved, m_spInternetProtocol);
+  return OnStart(szUrl, pOIProtSink, pOIBindInfo, grfPI, dwReserved, m_spInternetProtocol);
 }
 
- STDMETHODIMP WBPassthru::Read(	/* [in, out] */ void *pv,/* [in] */ ULONG cb,/* [out] */ ULONG *pcbRead)
- {
-   
-   WBPassthruSink* pSink = GetSink();
-   return pSink->Read(pv, cb, pcbRead);
- }
\ No newline at end of file
+STDMETHODIMP WBPassthru::Read(/* [in, out] */ void *pv,/* [in] */ ULONG cb,/* [out] */ ULONG *pcbRead)
+{
+  WBPassthruSink* pSink = GetSink();
+  return pSink->OnRead(pv, cb, pcbRead);
+}
+
+STDMETHODIMP WBPassthru::LockRequest(/* [in] */ DWORD options)
+{
+  if (!m_hasOriginalStartCalled)
+  {
+    return S_OK;
+  }
+  return BaseClass::LockRequest(options);
+}
+
+STDMETHODIMP WBPassthru::UnlockRequest()
+{
+  if (!m_hasOriginalStartCalled)
+  {
+    return S_OK;
+  }
+  return BaseClass::UnlockRequest();
+}
\ No newline at end of file
Index: src/plugin/PluginWbPassThrough.h
===================================================================
--- a/src/plugin/PluginWbPassThrough.h
+++ b/src/plugin/PluginWbPassThrough.h
@@ -1,5 +1,5 @@
 #pragma once
-
+#include <cstdint>
 #include "ProtocolCF.h"
 #include "ProtocolImpl.h"
 #define IE_MAX_URL_LENGTH 2048
@@ -11,14 +11,17 @@
 	typedef PassthroughAPP::CInternetProtocolSinkWithSP<WBPassthruSink, CComMultiThreadModel> BaseClass;
 
 public:
+	WBPassthruSink();
 
-	bool m_shouldBlock;
-	bool m_lastDataReported;
+	uint64_t m_currentPositionOfSentPage;
 	CComPtr<IInternetProtocol> m_pTargetProtocol;
+	int m_contentType;
+	std::wstring m_boundDomain;
+	bool m_blockedInTransaction;
 
-  int GetContentTypeFromMimeType(CString mimeType);
-  int GetContentTypeFromURL(CString src);
-  int GetContentType(CString mimeType, std::wstring domain, CString src);
+	int GetContentTypeFromMimeType(const CString& mimeType);
+	int GetContentTypeFromURL(const CString& src);
+	int GetContentType(const CString& mimeType, const std::wstring& domain, const CString& src);
 public:
 	BEGIN_COM_MAP(WBPassthruSink)
 		COM_INTERFACE_ENTRY(IHttpNegotiate)
@@ -43,13 +46,18 @@
 
 	HRESULT OnStart(LPCWSTR szUrl, IInternetProtocolSink *pOIProtSink,
 		IInternetBindInfo *pOIBindInfo, DWORD grfPI, HANDLE_PTR dwReserved,
-		IInternetProtocol* pTargetProtocol);
-	HRESULT Read(void *pv, ULONG cb, ULONG* pcbRead);
+		IInternetProtocol* pTargetProtocol, bool& handled);
+	HRESULT OnRead(void *pv, ULONG cb, ULONG* pcbRead);
 
 	STDMETHODIMP ReportProgress(
 		/* [in] */ ULONG ulStatusCode,
 		/* [in] */ LPCWSTR szStatusText);
 
+	STDMETHODIMP ReportResult(
+		/* [in] */ HRESULT hrResult,
+		/* [in] */ DWORD dwError,
+		/* [in] */ LPCWSTR szResult);
+
 	STDMETHODIMP Switch(
 		/* [in] */ PROTOCOLDATA *pProtocolData);
 };
@@ -59,11 +67,19 @@
 
 class WBPassthru : public PassthroughAPP::CInternetProtocol<WBStartPolicy>
 {
+  typedef PassthroughAPP::CInternetProtocol<WBStartPolicy> BaseClass;
 public:
+  WBPassthru();
   // IInternetProtocolRoot
   STDMETHODIMP Start(LPCWSTR szUrl, IInternetProtocolSink *pOIProtSink,
-    IInternetBindInfo *pOIBindInfo, DWORD grfPI, HANDLE_PTR dwReserved);
+    IInternetBindInfo *pOIBindInfo, DWORD grfPI, HANDLE_PTR dwReserved) override;
 
   //IInternetProtocol
-  STDMETHODIMP Read(	/* [in, out] */ void *pv,/* [in] */ ULONG cb,/* [out] */ ULONG *pcbRead);
+  STDMETHODIMP Read(/* [in, out] */ void *pv,/* [in] */ ULONG cb,/* [out] */ ULONG *pcbRead) override;
+
+  STDMETHODIMP LockRequest(/* [in] */ DWORD dwOptions) override;
+  STDMETHODIMP UnlockRequest() override;
+
+  bool m_shouldSupplyCustomContent;
+  bool m_hasOriginalStartCalled;
 };
Index: src/plugin/SinkPolicy.h
===================================================================
--- a/src/plugin/SinkPolicy.h
+++ b/src/plugin/SinkPolicy.h
@@ -155,7 +155,7 @@
 	HRESULT OnStart(LPCWSTR szUrl,
 		IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
 		DWORD grfPI, HANDLE_PTR dwReserved,
-		IInternetProtocol* pTargetProtocol) const;
+		IInternetProtocol* pTargetProtocol);
 
 
 	static Sink* GetSink(const Protocol* pProtocol);
Index: src/plugin/SinkPolicy.inl
===================================================================
--- a/src/plugin/SinkPolicy.inl
+++ b/src/plugin/SinkPolicy.inl
@@ -358,32 +358,38 @@
 inline HRESULT CustomSinkStartPolicy<Protocol, Sink>::OnStart(LPCWSTR szUrl,
 	IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
 	DWORD grfPI, HANDLE_PTR dwReserved,
-	IInternetProtocol* pTargetProtocol) const
+	IInternetProtocol* pTargetProtocol)
 {
 	ATLASSERT(pTargetProtocol != 0);
 
+	bool handled = false;
 	Sink* pSink = GetSink(static_cast<const Protocol*>(this));
 	HRESULT hr = pSink->OnStart(szUrl, pOIProtSink, pOIBindInfo, grfPI,
-		dwReserved, pTargetProtocol);
+		dwReserved, pTargetProtocol, handled);
 
 	CComPtr<IInternetProtocolSink> spSink;
 	CComPtr<IInternetBindInfo> spBindInfo;
 	if (SUCCEEDED(hr))
 	{
-		hr = pSink->QueryInterface(IID_IInternetProtocolSink,
-			reinterpret_cast<void**>(&spSink));
+		hr = pSink->QueryInterface(IID_IInternetProtocolSink, reinterpret_cast<void**>(&spSink));
 		ATLASSERT(SUCCEEDED(hr) && spSink != 0);
 	}
 	if (SUCCEEDED(hr))
 	{
-		hr = pSink->QueryInterface(IID_IInternetBindInfo,
-			reinterpret_cast<void**>(&spBindInfo));
+		hr = pSink->QueryInterface(IID_IInternetBindInfo, reinterpret_cast<void**>(&spBindInfo));
 		ATLASSERT(SUCCEEDED(hr) && spBindInfo != 0);
 	}
-	if (SUCCEEDED(hr))
+	if (SUCCEEDED(hr) && !handled)
 	{
-		hr = pTargetProtocol->Start(szUrl, spSink, spBindInfo, grfPI,
-			dwReserved);
+		hr = pTargetProtocol->Start(szUrl, spSink, spBindInfo, grfPI, dwReserved);
+		static_cast<Protocol*>(this)->m_hasOriginalStartCalled = true;
+	}
+	if (E_ABORT == hr && pSink->m_blockedInTransaction)
+	{
+		static_cast<Protocol*>(this)->m_shouldSupplyCustomContent = true;
+		pSink->m_spInternetProtocolSink->ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE, L"text/html");
+		pSink->m_spInternetProtocolSink->ReportData(BSCF_FIRSTDATANOTIFICATION, 0, static_cast<ULONG>(g_blockedByABPPage.size()));
+		return S_OK;
 	}
 	return hr;
 }
