TEST(RawResourceTest, RevalidationSucceededForResourceWithoutBody)
{
    Resource* resource = RawResource::create(ResourceRequest("data:text/html,"), Resource::Raw);
    ResourceResponse response;
    response.setHTTPStatusCode(200);
    resource->responseReceived(response, nullptr);
    resource->finish();
    memoryCache()->add(resource);

    // Simulate a successful revalidation.
    resource->setRevalidatingRequest(ResourceRequest("data:text/html,"));

    Persistent<DummyClient> client = new DummyClient;
    resource->addClient(client);

    ResourceResponse revalidatingResponse;
    revalidatingResponse.setHTTPStatusCode(304);
    resource->responseReceived(revalidatingResponse, nullptr);
    EXPECT_FALSE(resource->isCacheValidator());
    EXPECT_EQ(200, resource->response().httpStatusCode());
    EXPECT_EQ(nullptr, resource->resourceBuffer());
    EXPECT_EQ(memoryCache()->resourceForURL(KURL(ParsedURLString, "data:text/html,")), resource);
    memoryCache()->remove(resource);

    resource->removeClient(client);
    EXPECT_FALSE(resource->hasClientsOrObservers());
    EXPECT_FALSE(client->called());
    EXPECT_EQ(0u, client->data().size());
}
TEST(RawResourceTest, RemoveClientDuringCallback)
{
    Resource* raw = RawResource::create(ResourceRequest("data:text/html,"), Resource::Raw);

    // Create a non-null response.
    ResourceResponse response = raw->response();
    response.setURL(KURL(ParsedURLString, "http://600.613/"));
    raw->setResponse(response);
    raw->finish();
    EXPECT_FALSE(raw->response().isNull());

    Persistent<DummyClient> dummyClient = new DummyClient();
    Persistent<RemovingClient> removingClient = new RemovingClient(dummyClient.get());
    raw->addClient(dummyClient);
    raw->addClient(removingClient);
    testing::runPendingTasks();
    EXPECT_FALSE(raw->hasClientsOrObservers());
}
// Regression test for http://crbug.com/594072.
// This emulates a modal dialog triggering a nested run loop inside
// ResourceLoader::cancel(). If the ResourceLoader doesn't promptly cancel its
// WebURLLoader before notifying its clients, a nested run loop  may send a
// network response, leading to an invalid state transition in ResourceLoader.
TEST_F(ResourceFetcherTest, ResponseOnCancel) {
    KURL url(ParsedURLString, "http://127.0.0.1:8000/foo.png");
    URLTestHelpers::registerMockedURLLoad(url, testImageFilename, "image/png");

    ResourceFetcher* fetcher =
        ResourceFetcher::create(ResourceFetcherTestMockFetchContext::create());
    ResourceRequest resourceRequest(url);
    resourceRequest.setRequestContext(WebURLRequest::RequestContextInternal);
    FetchRequest fetchRequest =
        FetchRequest(resourceRequest, FetchInitiatorInfo());
    Resource* resource = RawResource::fetch(fetchRequest, fetcher);
    Persistent<ServeRequestsOnCompleteClient> client =
        new ServeRequestsOnCompleteClient();
    resource->addClient(client);
    resource->loader()->cancel();
    resource->removeClient(client);
    Platform::current()->getURLLoaderMockFactory()->unregisterURL(url);
}
TEST(RawResourceTest, RedirectDuringRevalidation)
{
    Resource* resource = RawResource::create(ResourceRequest("https://example.com/1"), Resource::Raw);
    ResourceResponse response;
    response.setURL(KURL(ParsedURLString, "https://example.com/1"));
    response.setHTTPStatusCode(200);
    resource->responseReceived(response, nullptr);
    const char data[5] = "abcd";
    resource->appendData(data, 4);
    resource->finish();
    memoryCache()->add(resource);

    EXPECT_FALSE(resource->isCacheValidator());
    EXPECT_EQ("https://example.com/1", resource->resourceRequest().url().getString());
    EXPECT_EQ("https://example.com/1", resource->lastResourceRequest().url().getString());

    // Simulate a revalidation.
    resource->setRevalidatingRequest(ResourceRequest("https://example.com/1"));
    EXPECT_TRUE(resource->isCacheValidator());
    EXPECT_EQ("https://example.com/1", resource->resourceRequest().url().getString());
    EXPECT_EQ("https://example.com/1", resource->lastResourceRequest().url().getString());

    Persistent<DummyClient> client = new DummyClient;
    resource->addClient(client);

    // The revalidating request is redirected.
    ResourceResponse redirectResponse;
    redirectResponse.setURL(KURL(ParsedURLString, "https://example.com/1"));
    redirectResponse.setHTTPHeaderField("location", "https://example.com/2");
    redirectResponse.setHTTPStatusCode(308);
    ResourceRequest redirectedRevalidatingRequest("https://example.com/2");
    resource->willFollowRedirect(redirectedRevalidatingRequest, redirectResponse);
    EXPECT_FALSE(resource->isCacheValidator());
    EXPECT_EQ("https://example.com/1", resource->resourceRequest().url().getString());
    EXPECT_EQ("https://example.com/2", resource->lastResourceRequest().url().getString());

    // The final response is received.
    ResourceResponse revalidatingResponse;
    revalidatingResponse.setURL(KURL(ParsedURLString, "https://example.com/2"));
    revalidatingResponse.setHTTPStatusCode(200);
    resource->responseReceived(revalidatingResponse, nullptr);
    const char data2[4] = "xyz";
    resource->appendData(data2, 3);
    resource->finish();
    EXPECT_FALSE(resource->isCacheValidator());
    EXPECT_EQ("https://example.com/1", resource->resourceRequest().url().getString());
    EXPECT_EQ("https://example.com/2", resource->lastResourceRequest().url().getString());
    EXPECT_FALSE(resource->isCacheValidator());
    EXPECT_EQ(200, resource->response().httpStatusCode());
    EXPECT_EQ(3u, resource->resourceBuffer()->size());
    EXPECT_EQ(memoryCache()->resourceForURL(KURL(ParsedURLString, "https://example.com/1")), resource);

    EXPECT_TRUE(client->called());
    EXPECT_EQ(1, client->numberOfRedirectsReceived());
    EXPECT_EQ("xyz", String(client->data().data(), client->data().size()));

    // Test the case where a client is added after revalidation is completed.
    Persistent<DummyClient> client2 = new DummyClient;
    resource->addClient(client2);

    // Because RawResourceClient is added asynchronously,
    // |runPendingTasks()| is called to make |client2| to be notified.
    testing::runPendingTasks();

    EXPECT_TRUE(client2->called());
    EXPECT_EQ(1, client2->numberOfRedirectsReceived());
    EXPECT_EQ("xyz", String(client2->data().data(), client2->data().size()));

    memoryCache()->remove(resource);

    resource->removeClient(client);
    resource->removeClient(client2);
    EXPECT_FALSE(resource->hasClientsOrObservers());
}
TEST(RawResourceTest, RevalidationSucceededUpdateHeaders)
{
    Resource* resource = RawResource::create(ResourceRequest("data:text/html,"), Resource::Raw);
    ResourceResponse response;
    response.setHTTPStatusCode(200);
    response.addHTTPHeaderField("keep-alive", "keep-alive value");
    response.addHTTPHeaderField("expires", "expires value");
    response.addHTTPHeaderField("last-modified", "last-modified value");
    response.addHTTPHeaderField("proxy-authenticate", "proxy-authenticate value");
    response.addHTTPHeaderField("proxy-connection", "proxy-connection value");
    response.addHTTPHeaderField("x-custom", "custom value");
    resource->responseReceived(response, nullptr);
    resource->finish();
    memoryCache()->add(resource);

    // Simulate a successful revalidation.
    resource->setRevalidatingRequest(ResourceRequest("data:text/html,"));

    // Validate that these headers pre-update.
    EXPECT_EQ("keep-alive value", resource->response().httpHeaderField("keep-alive"));
    EXPECT_EQ("expires value", resource->response().httpHeaderField("expires"));
    EXPECT_EQ("last-modified value", resource->response().httpHeaderField("last-modified"));
    EXPECT_EQ("proxy-authenticate value", resource->response().httpHeaderField("proxy-authenticate"));
    EXPECT_EQ("proxy-authenticate value", resource->response().httpHeaderField("proxy-authenticate"));
    EXPECT_EQ("proxy-connection value", resource->response().httpHeaderField("proxy-connection"));
    EXPECT_EQ("custom value", resource->response().httpHeaderField("x-custom"));

    Persistent<DummyClient> client = new DummyClient;
    resource->addClient(client.get());

    // Perform a revalidation step.
    ResourceResponse revalidatingResponse;
    revalidatingResponse.setHTTPStatusCode(304);
    // Headers that aren't copied with an 304 code.
    revalidatingResponse.addHTTPHeaderField("keep-alive", "garbage");
    revalidatingResponse.addHTTPHeaderField("expires", "garbage");
    revalidatingResponse.addHTTPHeaderField("last-modified", "garbage");
    revalidatingResponse.addHTTPHeaderField("proxy-authenticate", "garbage");
    revalidatingResponse.addHTTPHeaderField("proxy-connection", "garbage");
    // Header that is updated with 304 code.
    revalidatingResponse.addHTTPHeaderField("x-custom", "updated");
    resource->responseReceived(revalidatingResponse, nullptr);

    // Validate the original response.
    EXPECT_EQ(200, resource->response().httpStatusCode());

    // Validate that these headers are not updated.
    EXPECT_EQ("keep-alive value", resource->response().httpHeaderField("keep-alive"));
    EXPECT_EQ("expires value", resource->response().httpHeaderField("expires"));
    EXPECT_EQ("last-modified value", resource->response().httpHeaderField("last-modified"));
    EXPECT_EQ("proxy-authenticate value", resource->response().httpHeaderField("proxy-authenticate"));
    EXPECT_EQ("proxy-authenticate value", resource->response().httpHeaderField("proxy-authenticate"));
    EXPECT_EQ("proxy-connection value", resource->response().httpHeaderField("proxy-connection"));
    EXPECT_EQ("updated", resource->response().httpHeaderField("x-custom"));

    memoryCache()->remove(resource);

    resource->removeClient(client);
    EXPECT_FALSE(resource->hasClientsOrObservers());
    EXPECT_FALSE(client->called());
    EXPECT_EQ(0u, client->data().size());
}