| Index: chrome/browser/errorpage_browsertest.cc
|
| diff --git a/chrome/browser/errorpage_browsertest.cc b/chrome/browser/errorpage_browsertest.cc
|
| index e2afcbf59b7c601ef1b81187426d68a6d2e86b55..7a7b66748ec9edf29a9965c148be8accb81a7b15 100644
|
| --- a/chrome/browser/errorpage_browsertest.cc
|
| +++ b/chrome/browser/errorpage_browsertest.cc
|
| @@ -6,6 +6,8 @@
|
| #include "base/prefs/pref_service.h"
|
| #include "base/strings/stringprintf.h"
|
| #include "base/strings/utf_string_conversions.h"
|
| +#include "chrome/browser/browsing_data/browsing_data_helper.h"
|
| +#include "chrome/browser/browsing_data/browsing_data_remover.h"
|
| #include "chrome/browser/google/google_util.h"
|
| #include "chrome/browser/net/url_request_mock_util.h"
|
| #include "chrome/browser/profiles/profile.h"
|
| @@ -25,6 +27,12 @@
|
| #include "content/test/net/url_request_mock_http_job.h"
|
| #include "net/base/net_errors.h"
|
| #include "net/base/net_util.h"
|
| +#include "net/http/http_cache.h"
|
| +#include "net/http/http_transaction.h"
|
| +#include "net/http/http_transaction_factory.h"
|
| +#include "net/test/spawned_test_server/spawned_test_server.h"
|
| +#include "net/url_request/url_request_context.h"
|
| +#include "net/url_request/url_request_context_getter.h"
|
| #include "net/url_request/url_request_filter.h"
|
| #include "net/url_request/url_request_job_factory.h"
|
|
|
| @@ -121,7 +129,6 @@ class ErrorPageTest : public InProcessBrowserTest {
|
| }
|
| };
|
|
|
| -
|
| class TestFailProvisionalLoadObserver : public content::WebContentsObserver {
|
| public:
|
| explicit TestFailProvisionalLoadObserver(content::WebContents* contents)
|
| @@ -148,6 +155,143 @@ class TestFailProvisionalLoadObserver : public content::WebContentsObserver {
|
| DISALLOW_COPY_AND_ASSIGN(TestFailProvisionalLoadObserver);
|
| };
|
|
|
| +class TestNetworkTransaction : public net::HttpTransaction {
|
| + public:
|
| + explicit TestNetworkTransaction(enum net::Error err): err_(err) {
|
| + DCHECK_NE(net::OK, err);
|
| + }
|
| + virtual ~TestNetworkTransaction() {}
|
| +
|
| + // net::HttpTransaction
|
| + virtual int Start(const net::HttpRequestInfo* request_info,
|
| + const net::CompletionCallback& callback,
|
| + const net::BoundNetLog& net_log) OVERRIDE {
|
| + base::MessageLoop::current()->PostTask(
|
| + FROM_HERE, base::Bind(callback, err_));
|
| + return net::ERR_IO_PENDING;
|
| + }
|
| + virtual int RestartIgnoringLastError(
|
| + const net::CompletionCallback& callback) OVERRIDE {
|
| + return net::ERR_FAILED;
|
| + }
|
| + virtual int RestartWithCertificate(
|
| + net::X509Certificate* client_cert,
|
| + const net::CompletionCallback& callback) OVERRIDE {
|
| + return net::ERR_FAILED;
|
| + }
|
| + virtual int RestartWithAuth(
|
| + const net::AuthCredentials& credentials,
|
| + const net::CompletionCallback& callback) OVERRIDE {
|
| + return net::ERR_FAILED;
|
| + }
|
| + virtual bool IsReadyToRestartForAuth() OVERRIDE {
|
| + return false;
|
| + }
|
| + virtual int Read(net::IOBuffer* buf, int buf_len,
|
| + const net::CompletionCallback& callback) OVERRIDE {
|
| + NOTREACHED();
|
| + return net::ERR_FAILED;
|
| + }
|
| + virtual void StopCaching() OVERRIDE {}
|
| + virtual bool GetFullRequestHeaders(
|
| + net::HttpRequestHeaders* headers) const OVERRIDE {
|
| + return false;
|
| + }
|
| + virtual int64 GetTotalReceivedBytes() const OVERRIDE {
|
| + return 0;
|
| + }
|
| + virtual void DoneReading() OVERRIDE {
|
| + NOTREACHED();
|
| + }
|
| + virtual const net::HttpResponseInfo* GetResponseInfo() const OVERRIDE {
|
| + return NULL;
|
| + }
|
| + virtual net::LoadState GetLoadState() const OVERRIDE {
|
| + return net::LOAD_STATE_IDLE;
|
| + }
|
| + virtual net::UploadProgress GetUploadProgress() const OVERRIDE {
|
| + return net::UploadProgress();
|
| + }
|
| + virtual bool GetLoadTimingInfo(
|
| + net::LoadTimingInfo* load_timing_info) const OVERRIDE {
|
| + // Shouldn't be relevant; using the minimal set from
|
| + // http_transaction_unittest.cc MockNetworkTransaction::GetLoadTimingInfo().
|
| + load_timing_info->socket_reused = true;
|
| + load_timing_info->send_start = base::TimeTicks::Now();
|
| + load_timing_info->send_end = base::TimeTicks::Now();
|
| + return true;
|
| + }
|
| + virtual void SetPriority(net::RequestPriority priority) OVERRIDE {}
|
| + virtual void SetWebSocketHandshakeStreamCreateHelper(
|
| + net::WebSocketHandshakeStreamBase::CreateHelper* create_helper) OVERRIDE {
|
| + NOTREACHED();
|
| + }
|
| + virtual void SetBeforeNetworkStartCallback(
|
| + const BeforeNetworkStartCallback& callback) OVERRIDE {
|
| + }
|
| + virtual int ResumeNetworkStart() OVERRIDE {
|
| + NOTREACHED();
|
| + return net::ERR_FAILED;
|
| + }
|
| +
|
| + private:
|
| + enum net::Error err_;
|
| +};
|
| +
|
| +// Creates transactions that always (asynchronously) return |err|.
|
| +// |err| must not be net::OK.
|
| +class TestNetworkTransactionFactory : public net::HttpTransactionFactory {
|
| + public:
|
| + explicit TestNetworkTransactionFactory(enum net::Error err) : err_(err) {}
|
| + virtual ~TestNetworkTransactionFactory() {}
|
| +
|
| + // net::HttpTransactionFactory:
|
| + virtual int CreateTransaction(
|
| + net::RequestPriority priority,
|
| + scoped_ptr<net::HttpTransaction>* trans) OVERRIDE {
|
| + trans->reset(new TestNetworkTransaction(err_));
|
| + return net::OK;
|
| + }
|
| + virtual net::HttpCache* GetCache() OVERRIDE {
|
| + return NULL;
|
| + }
|
| + virtual net::HttpNetworkSession* GetSession() OVERRIDE {
|
| + return NULL; // TODO(rdsmith): Is this really safe?
|
| + }
|
| +
|
| + static void SetupInstance(net::URLRequestContextGetter* getter,
|
| + enum net::Error err) {
|
| + DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| + net::HttpCache* cache(
|
| + getter->GetURLRequestContext()->http_transaction_factory()->GetCache());
|
| + DCHECK(cache);
|
| + DCHECK(!old_network_layer_.get());
|
| + scoped_ptr<TestNetworkTransactionFactory> factory(
|
| + new TestNetworkTransactionFactory(err));
|
| + old_network_layer_ = cache->SetNetworkLayerForTesting(
|
| + factory.PassAs<net::HttpTransactionFactory>());
|
| + }
|
| +
|
| + static void TearDownInstance(net::URLRequestContextGetter* getter) {
|
| + DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| + net::HttpCache* cache(
|
| + getter->GetURLRequestContext()->http_transaction_factory()->GetCache());
|
| + DCHECK(cache);
|
| + DCHECK(old_network_layer_.get());
|
| + cache->SetNetworkLayerForTesting(old_network_layer_.Pass());
|
| + }
|
| +
|
| + private:
|
| + enum net::Error err_;
|
| +
|
| + // It is the caller's responsibility to make sure that TearDownInstance()
|
| + // is called so that this does not leak.
|
| + static scoped_ptr<net::HttpTransactionFactory> old_network_layer_;
|
| +};
|
| +
|
| +scoped_ptr<net::HttpTransactionFactory>
|
| +TestNetworkTransactionFactory::old_network_layer_;
|
| +
|
| // See crbug.com/109669
|
| #if defined(USE_AURA) || defined(OS_WIN)
|
| #define MAYBE_DNSError_Basic DISABLED_DNSError_Basic
|
| @@ -356,6 +500,76 @@ IN_PROC_BROWSER_TEST_F(ErrorPageTest, Page404) {
|
| 1);
|
| }
|
|
|
| +// Checks that when an error occurs, the stale cache status of the page
|
| +// is correctly transferred.
|
| +IN_PROC_BROWSER_TEST_F(ErrorPageTest, StaleCacheStatus) {
|
| + ASSERT_TRUE(test_server()->Start());
|
| + // Load cache with entry with "nocache" set, to create stale
|
| + // cache.
|
| + GURL test_url(test_server()->GetURL("files/nocache.html"));
|
| + NavigateToURLAndWaitForTitle(test_url, "Nocache Test Page", 1);
|
| +
|
| + // Reload same URL after forcing an error from the the network layer;
|
| + // confirm that the error page is told the cached copy exists.
|
| + scoped_refptr<net::URLRequestContextGetter> url_request_context_getter =
|
| + browser()->profile()->GetRequestContext();
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO, FROM_HERE,
|
| + base::Bind(&TestNetworkTransactionFactory::SetupInstance,
|
| + url_request_context_getter,
|
| + // Note that we can't use an error that'll invoke the link
|
| + // doctor. In normal network error conditions that would
|
| + // work (because the link doctor fetch would also fail,
|
| + // putting us back in the main offline path), but
|
| + // SetUrlRequestMocksEnabled() has also specfied a link
|
| + // doctor mock, which will be accessible because it
|
| + // won't go through the network cache.
|
| + net::ERR_FAILED));
|
| +
|
| + ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
|
| + // First fails, second to error page.
|
| + // TODO(rdsmith): The above is wrong; why?
|
| + browser(), test_url, 1 /* 2 */);
|
| +
|
| + content::WebContents* wc =
|
| + browser()->tab_strip_model()->GetActiveWebContents();
|
| + const char* js_cache_probe =
|
| + "(function () {\n"
|
| + "if ('staleCopyInCache' in templateData) {\n"
|
| + "return templateData.staleCopyInCache;\n"
|
| + "} else {\n"
|
| + "return 'Undefined';\n"
|
| + "}\n"
|
| + "})();";
|
| +
|
| + scoped_ptr<base::Value> value =
|
| + content::ExecuteScriptAndGetValue(
|
| + wc->GetRenderViewHost(), js_cache_probe);
|
| + ASSERT_TRUE(value->IsType(base::Value::TYPE_BOOLEAN)) << "Type is "
|
| + << value->GetType();
|
| + bool result = false;
|
| + EXPECT_TRUE(value->GetAsBoolean(&result));
|
| + EXPECT_TRUE(result);
|
| +
|
| + // Clear the cache and reload the same URL; confirm the error page is told
|
| + // that there is no cached copy.
|
| + BrowsingDataRemover* remover =
|
| + BrowsingDataRemover::CreateForUnboundedRange(browser()->profile());
|
| + remover->Remove(BrowsingDataRemover::REMOVE_CACHE,
|
| + BrowsingDataHelper::UNPROTECTED_WEB);
|
| + ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
|
| + browser(), test_url, 1); // First fails, second to error page.
|
| + value = content::ExecuteScriptAndGetValue(
|
| + wc->GetRenderViewHost(), js_cache_probe);
|
| + ASSERT_TRUE(value->IsType(base::Value::TYPE_BOOLEAN));
|
| + EXPECT_TRUE(value->GetAsBoolean(&result));
|
| + EXPECT_FALSE(result);
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO, FROM_HERE,
|
| + base::Bind(&TestNetworkTransactionFactory::TearDownInstance,
|
| + url_request_context_getter));
|
| +}
|
| +
|
| // Returns Javascript code that executes plain text search for the page.
|
| // Pass into content::ExecuteScriptAndExtractBool as |script| parameter.
|
| std::string GetTextContentContainsStringScript(
|
|
|