15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome_frame/urlmon_bind_status_callback.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <mshtml.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <shlguid.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/platform_thread.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome_frame/bind_context_info.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome_frame/chrome_tab.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome_frame/exception_barrier.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome_frame/urlmon_moniker.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A helper to given feed data to the specified |bscb| using
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CacheStream instance.
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT CacheStream::BSCBFeedData(IBindStatusCallback* bscb, const char* data,
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  size_t size, CLIPFORMAT clip_format,
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  size_t flags, bool eof) {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!bscb) {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << "invalid IBindStatusCallback";
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return E_INVALIDARG;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We can't use a CComObjectStackEx here since mshtml will hold
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // onto the stream pointer.
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CComObject<CacheStream>* cache_stream = NULL;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = CComObject<CacheStream>::CreateInstance(&cache_stream);
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr)) {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<CacheStream> cache_ref = cache_stream;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = cache_stream->Initialize(data, size, eof);
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr))
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FORMATETC format_etc = { clip_format, NULL, DVASPECT_CONTENT, -1,
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           TYMED_ISTREAM };
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STGMEDIUM medium = {0};
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  medium.tymed = TYMED_ISTREAM;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  medium.pstm = cache_stream;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = bscb->OnDataAvailable(flags, size, &format_etc, &medium);
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return hr;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT CacheStream::Initialize(const char* cache, size_t size, bool eof) {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  position_ = 0;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  eof_ = eof;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = S_OK;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cache_.reset(new char[size]);
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (cache_.get()) {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memcpy(cache_.get(), cache, size);
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_ = size;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(ERROR) << "failed to allocate cache stream.";
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = E_OUTOFMEMORY;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return hr;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Read is the only call that we expect. Return E_PENDING if there
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is no more data to serve. Otherwise this will result in a
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// read with 0 bytes indicating that no more data is available.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)STDMETHODIMP CacheStream::Read(void* pv, ULONG cb, ULONG* read) {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!pv || !read)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return E_INVALIDARG;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!cache_.get()) {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *read = 0;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return S_FALSE;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Default to E_PENDING to signal that this is a partial data.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = eof_ ? S_FALSE : E_PENDING;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (position_ < size_) {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *read = std::min(size_ - position_, size_t(cb));
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memcpy(pv, cache_ .get() + position_, *read);
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    position_ += *read;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = S_OK;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return hr;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/////////////////////////////////////////////////////////////////////
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT SniffData::InitializeCache(const std::wstring& url) {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_ = url;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  renderer_type_ = UNDETERMINED;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int kInitialSize = 4 * 1024; // 4K
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HGLOBAL mem = GlobalAlloc(0, kInitialSize);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(mem) << "GlobalAlloc failed: " << GetLastError();
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = CreateStreamOnHGlobal(mem, TRUE, cache_.Receive());
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (SUCCEEDED(hr)) {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ULARGE_INTEGER size = {0};
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cache_->SetSize(size);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(ERROR) << "CreateStreamOnHGlobal failed: " << hr;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return hr;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT SniffData::ReadIntoCache(IStream* stream, bool force_determination) {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!stream) {
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return E_INVALIDARG;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = S_OK;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (SUCCEEDED(hr)) {
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const size_t kChunkSize = 4 * 1024;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char buffer[kChunkSize];
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DWORD read = 0;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = stream->Read(buffer, sizeof(buffer), &read);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (read) {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DWORD written = 0;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cache_->Write(buffer, read, &written);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      size_ += written;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((S_FALSE == hr) || !read)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool last_chance = force_determination || (size() >= kMaxSniffSize);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  eof_ = force_determination;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DetermineRendererType(last_chance);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return hr;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT SniffData::DrainCache(IBindStatusCallback* bscb, DWORD bscf,
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              CLIPFORMAT clip_format) {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!is_cache_valid()) {
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return S_OK;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ideally we could just use the cache_ IStream implementation but
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // can't use it here since we have to return E_PENDING for the
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // last call
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HGLOBAL memory = NULL;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = GetHGlobalFromStream(cache_, &memory);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (SUCCEEDED(hr) && memory) {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char* buffer = reinterpret_cast<char*>(GlobalLock(memory));
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = CacheStream::BSCBFeedData(bscb, buffer, size_, clip_format, bscf,
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   eof_);
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GlobalUnlock(memory);
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_ = 0;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cache_.Release();
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return hr;
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Scan the buffer or OptIn URL list and decide if the renderer is
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to be switched.  Last chance means there's no more data.
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SniffData::DetermineRendererType(bool last_chance) {
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_undetermined()) {
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (last_chance)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      renderer_type_ = OTHER;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (IsChrome(RendererTypeForUrl(url_))) {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      renderer_type_ = CHROME;
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (is_cache_valid() && cache_) {
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        HGLOBAL memory = NULL;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GetHGlobalFromStream(cache_, &memory);
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const char* buffer = reinterpret_cast<const char*>(GlobalLock(memory));
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::wstring html_contents;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // TODO(joshia): detect and handle different content encodings
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (buffer && size_) {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          UTF8ToWide(buffer, std::min(size_, kMaxSniffSize), &html_contents);
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GlobalUnlock(memory);
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Note that document_contents_ may have NULL characters in it. While
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // browsers may handle this properly, we don't and will stop scanning
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // for the XUACompat content value if we encounter one.
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::wstring xua_compat_content;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        UtilGetXUACompatContentValue(html_contents, &xua_compat_content);
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (StrStrI(xua_compat_content.c_str(), kChromeContentPrefix)) {
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          renderer_type_ = CHROME;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << __FUNCTION__ << "Url: " << url_ << base::StringPrintf(
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "Renderer type: %s", renderer_type_ == CHROME ? "CHROME" : "OTHER");
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/////////////////////////////////////////////////////////////////////
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BSCBStorageBind::BSCBStorageBind() : clip_format_(CF_NULL) {
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BSCBStorageBind::~BSCBStorageBind() {
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::for_each(saved_progress_.begin(), saved_progress_.end(),
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                utils::DeleteObject());
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT BSCBStorageBind::Initialize(IMoniker* moniker, IBindCtx* bind_ctx) {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << __FUNCTION__ << me()
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           << base::StringPrintf(" tid=%i", base::PlatformThread::CurrentId());
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::wstring url = GetActualUrlFromMoniker(moniker, bind_ctx,
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             std::wstring());
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = data_sniffer_.InitializeCache(url);
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr))
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = AttachToBind(bind_ctx);
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FAILED(hr)) {
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << __FUNCTION__ << me() << "AttachToBind error: " << hr;
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return hr;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!delegate()) {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << __FUNCTION__ << me() << "No existing callback: " << hr;
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return E_FAIL;
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return hr;
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)STDMETHODIMP BSCBStorageBind::OnProgress(ULONG progress, ULONG progress_max,
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    ULONG status_code, LPCWSTR status_text) {
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << __FUNCTION__ << me()
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           << base::StringPrintf(" status=%i tid=%i %ls", status_code,
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 base::PlatformThread::CurrentId(),
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 status_text);
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Report all crashes in the exception handler if we wrap the callback.
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that this avoids having the VEH report a crash if an SEH earlier in
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the chain handles the exception.
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExceptionBarrier barrier;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = S_OK;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(ananta)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ChromeFrame will not be informed of any redirects which occur while we
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // switch into Chrome. This will only break the moniker patch which is
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // legacy and needs to be deleted.
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ShouldCacheProgress(status_code)) {
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    saved_progress_.push_back(new Progress(progress, progress_max, status_code,
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           status_text));
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = CallbackImpl::OnProgress(progress, progress_max, status_code,
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               status_text);
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return hr;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Refer to urlmon_moniker.h for explanation of how things work.
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)STDMETHODIMP BSCBStorageBind::OnDataAvailable(DWORD flags, DWORD size,
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              FORMATETC* format_etc,
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              STGMEDIUM* stgmed) {
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << __FUNCTION__
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           << base::StringPrintf(" tid=%i", base::PlatformThread::CurrentId());
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Report all crashes in the exception handler if we wrap the callback.
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that this avoids having the VEH report a crash if an SEH earlier in
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the chain handles the exception.
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExceptionBarrier barrier;
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Do not touch anything other than text/html.
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_interesting = (format_etc && stgmed && stgmed->pstm &&
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      stgmed->tymed == TYMED_ISTREAM &&
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      IsTextHtmlClipFormat(format_etc->cfFormat));
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!is_interesting) {
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Play back report progress so far.
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MayPlayBack(flags);
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return CallbackImpl::OnDataAvailable(flags, size, format_etc, stgmed);
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = S_OK;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!clip_format_)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    clip_format_ = format_etc->cfFormat;
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (data_sniffer_.is_undetermined()) {
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool force_determination = !!(flags &
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE));
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = data_sniffer_.ReadIntoCache(stgmed->pstm, force_determination);
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we don't have sufficient data to determine renderer type
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // wait for the next data notification.
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (data_sniffer_.is_undetermined())
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return S_OK;
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!data_sniffer_.is_undetermined());
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (data_sniffer_.is_cache_valid()) {
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = MayPlayBack(flags);
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!data_sniffer_.is_cache_valid());
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = CallbackImpl::OnDataAvailable(flags, size, format_etc, stgmed);
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return hr;
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)STDMETHODIMP BSCBStorageBind::OnStopBinding(HRESULT hresult, LPCWSTR error) {
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << __FUNCTION__
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           << base::StringPrintf(" tid=%i", base::PlatformThread::CurrentId());
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Report all crashes in the exception handler if we wrap the callback.
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that this avoids having the VEH report a crash if an SEH earlier in
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the chain handles the exception.
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ExceptionBarrier barrier;
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = MayPlayBack(BSCF_LASTDATANOTIFICATION);
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hr = CallbackImpl::OnStopBinding(hresult, error);
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReleaseBind();
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return hr;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Play back the cached data to the delegate. Normally this would happen
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// when we have read enough data to determine the renderer. In this case
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// we first play back the data from the cache and then go into a 'pass
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// through' mode.  In some cases we may end up getting OnStopBinding
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// before we get a chance to determine. Also it's possible that the
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// BindToStorage call will return before OnStopBinding is sent. Hence
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is called from 3 places and it's important to maintain the
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// exact sequence of calls.
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Once the data is played back, calling this again is a no op.
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HRESULT BSCBStorageBind::MayPlayBack(DWORD flags) {
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Force renderer type determination if not already done since
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we want to play back data now.
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data_sniffer_.DetermineRendererType(true);
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!data_sniffer_.is_undetermined());
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT hr = S_OK;
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (data_sniffer_.is_chrome()) {
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Remember clip format.  If we are switching to chrome, then in order
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // to make mshtml return INET_E_TERMINATED_BIND and reissue navigation
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // with the same bind context, we have to return a mime type that is
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // special cased by mshtml.
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static const CLIPFORMAT kMagicClipFormat =
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        RegisterClipboardFormat(CFSTR_MIME_MPEG);
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    clip_format_ = kMagicClipFormat;
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!saved_progress_.empty()) {
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (ProgressVector::iterator i = saved_progress_.begin();
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           i != saved_progress_.end(); i++) {
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Progress* p = (*i);
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // We don't really expect a race condition here but just for sake
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // of completeness we check.
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (p) {
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (*i) = NULL;
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          CallbackImpl::OnProgress(p->progress(), p->progress_max(),
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   p->status_code(), p->status_text());
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          delete p;
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      saved_progress_.clear();
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (data_sniffer_.is_cache_valid()) {
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (data_sniffer_.is_chrome()) {
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::win::ScopedComPtr<BindContextInfo> info;
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BindContextInfo::FromBindContext(bind_ctx_, info.Receive());
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(info);
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (info) {
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        info->SetToSwitch(data_sniffer_.cache_);
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hr = data_sniffer_.DrainCache(delegate(),
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        flags | BSCF_FIRSTDATANOTIFICATION, clip_format_);
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG_IF(WARNING, INET_E_TERMINATED_BIND != hr) << __FUNCTION__ <<
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      " mshtml OnDataAvailable returned: " << std::hex << hr;
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return hr;
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We cache and suppress sending progress notifications till
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// we get the first OnDataAvailable. This is to prevent
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// mshtml from making up its mind about the mime type.
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// However, this is the invasive part of the patch and
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// could trip other software that's due to mistimed progress
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// notifications. It is probably not a good idea to hide redirects
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and some cookie notifications.
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We only need to suppress data notifications like
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// BINDSTATUS_MIMETYPEAVAILABLE,
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// BINDSTATUS_CACHEFILENAMEAVAILABLE etc.
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is an atempt to reduce the exposure by starting to
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// cache only when we receive one of the interesting progress
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// notification.
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BSCBStorageBind::ShouldCacheProgress(unsigned long status_code) const {
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We need to cache progress notifications only if we haven't yet figured
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // out which way the request is going.
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (data_sniffer_.is_undetermined()) {
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we are already caching then continue.
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!saved_progress_.empty())
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Start caching only if we see one of the interesting progress
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // notifications.
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (status_code) {
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case BINDSTATUS_BEGINDOWNLOADDATA:
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case BINDSTATUS_DOWNLOADINGDATA:
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case BINDSTATUS_USINGCACHEDCOPY:
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case BINDSTATUS_MIMETYPEAVAILABLE:
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case BINDSTATUS_CACHEFILENAMEAVAILABLE:
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case BINDSTATUS_SERVER_MIMETYPEAVAILABLE:
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return true;
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default:
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
428