summaryrefslogtreecommitdiffstats
path: root/content/child/web_url_loader_impl_unittest.cc
diff options
context:
space:
mode:
authormmenke@chromium.org <mmenke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-23 12:15:03 +0000
committermmenke@chromium.org <mmenke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-23 12:15:03 +0000
commita491fd9412b763f20244acb4aea17312a89f64da (patch)
tree7a49401c4f52467e8e50ff9c8770fe2a3007883e /content/child/web_url_loader_impl_unittest.cc
parentbaf267eb99e51b93b257d88d5677456c079c263d (diff)
downloadchromium_src-a491fd9412b763f20244acb4aea17312a89f64da.zip
chromium_src-a491fd9412b763f20244acb4aea17312a89f64da.tar.gz
chromium_src-a491fd9412b763f20244acb4aea17312a89f64da.tar.bz2
Fix leak WebURLLoaderImpl::Context leak on cancel.
The Context was implicitly owned by the ResourceDispatcher as well as the WebURLLoaderImpl, and was leaked on cancel because the ResourceDispatcher would never call back into the context like it expected. This CL removes that implicit ownership, and instead just keeps the Context from being deleted while it's on the stack, and still has work to do. BUG=328092 Review URL: https://codereview.chromium.org/342203002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@279091 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/child/web_url_loader_impl_unittest.cc')
-rw-r--r--content/child/web_url_loader_impl_unittest.cc643
1 files changed, 643 insertions, 0 deletions
diff --git a/content/child/web_url_loader_impl_unittest.cc b/content/child/web_url_loader_impl_unittest.cc
new file mode 100644
index 0000000..81b6779
--- /dev/null
+++ b/content/child/web_url_loader_impl_unittest.cc
@@ -0,0 +1,643 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/child/web_url_loader_impl.h"
+
+#include <string.h>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "content/child/resource_dispatcher.h"
+#include "content/public/child/request_peer.h"
+#include "content/public/common/resource_response_info.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/WebURLError.h"
+#include "third_party/WebKit/public/platform/WebURLLoaderClient.h"
+#include "third_party/WebKit/public/platform/WebURLRequest.h"
+#include "url/gurl.h"
+#include "webkit/child/resource_loader_bridge.h"
+
+namespace content {
+namespace {
+
+const char kTestURL[] = "http://foo";
+const char kTestData[] = "blah!";
+
+const char kFtpDirMimeType[] = "text/vnd.chromium.ftp-dir";
+// Simple FTP directory listing. Tests are not concerned with correct parsing,
+// but rather correct cleanup when deleted while parsing. Important details of
+// this list are that it contains more than one entry that are not "." or "..".
+const char kFtpDirListing[] =
+ "drwxr-xr-x 3 ftp ftp 4096 May 15 18:11 goat\n"
+ "drwxr-xr-x 3 ftp ftp 4096 May 15 18:11 hat";
+
+const char kMultipartResponseMimeType[] = "multipart/x-mixed-replace";
+const char kMultipartResponseHeaders[] =
+ "HTTP/1.0 200 Peachy\r\n"
+ "Content-Type: multipart/x-mixed-replace; boundary=boundary\r\n\r\n";
+// Simple multipart response. Imporant details for the tests are that it
+// contains multiple chunks, and that it doesn't end with a boundary, so will
+// send data in OnResponseComplete. Also, it will resolve to kTestData.
+const char kMultipartResponse[] =
+ "--boundary\n"
+ "Content-type: text/html\n\n"
+ "bl"
+ "--boundary\n"
+ "Content-type: text/html\n\n"
+ "ah!";
+
+class TestBridge : public webkit_glue::ResourceLoaderBridge,
+ public base::SupportsWeakPtr<TestBridge> {
+ public:
+ TestBridge() : peer_(NULL), canceled_(false) {}
+ virtual ~TestBridge() {}
+
+ // ResourceLoaderBridge implementation:
+ virtual void SetRequestBody(ResourceRequestBody* request_body) OVERRIDE {}
+
+ virtual bool Start(RequestPeer* peer) OVERRIDE {
+ EXPECT_FALSE(peer_);
+ peer_ = peer;
+ return true;
+ }
+
+ virtual void Cancel() OVERRIDE {
+ EXPECT_FALSE(canceled_);
+ canceled_ = true;
+ }
+
+ virtual void SetDefersLoading(bool value) OVERRIDE {}
+
+ virtual void DidChangePriority(net::RequestPriority new_priority,
+ int intra_priority_value) OVERRIDE {}
+
+ virtual bool AttachThreadedDataReceiver(
+ blink::WebThreadedDataReceiver* threaded_data_receiver) OVERRIDE {
+ NOTREACHED();
+ return false;
+ }
+
+ virtual void SyncLoad(SyncLoadResponse* response) OVERRIDE {}
+
+ RequestPeer* peer() { return peer_; }
+
+ bool canceled() { return canceled_; }
+
+ private:
+ RequestPeer* peer_;
+ bool canceled_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestBridge);
+};
+
+class TestResourceDispatcher : public ResourceDispatcher {
+ public:
+ TestResourceDispatcher() : ResourceDispatcher(NULL) {}
+ virtual ~TestResourceDispatcher() {}
+
+ // ResourceDispatcher implementation:
+ virtual webkit_glue::ResourceLoaderBridge* CreateBridge(
+ const RequestInfo& request_info) OVERRIDE {
+ EXPECT_FALSE(bridge_.get());
+ TestBridge* bridge = new TestBridge();
+ bridge_ = bridge->AsWeakPtr();
+ return bridge;
+ }
+
+ TestBridge* bridge() { return bridge_.get(); }
+
+ private:
+ base::WeakPtr<TestBridge> bridge_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestResourceDispatcher);
+};
+
+class TestWebURLLoaderClient : public blink::WebURLLoaderClient {
+ public:
+ TestWebURLLoaderClient(ResourceDispatcher* dispatcher)
+ : loader_(new WebURLLoaderImpl(dispatcher)),
+ expect_multipart_response_(false),
+ delete_on_receive_redirect_(false),
+ delete_on_receive_response_(false),
+ delete_on_receive_data_(false),
+ delete_on_finish_(false),
+ delete_on_fail_(false),
+ did_receive_redirect_(false),
+ did_receive_response_(false),
+ did_finish_(false) {
+ }
+
+ virtual ~TestWebURLLoaderClient() {}
+
+ // blink::WebURLLoaderClient implementation:
+ virtual void willSendRequest(
+ blink::WebURLLoader* loader,
+ blink::WebURLRequest& newRequest,
+ const blink::WebURLResponse& redirectResponse) OVERRIDE {
+ EXPECT_TRUE(loader_);
+ EXPECT_EQ(loader_.get(), loader);
+ // No test currently simulates mutiple redirects.
+ EXPECT_FALSE(did_receive_redirect_);
+ did_receive_redirect_ = true;
+
+ if (delete_on_receive_redirect_)
+ loader_.reset();
+ }
+
+ virtual void didSendData(blink::WebURLLoader* loader,
+ unsigned long long bytesSent,
+ unsigned long long totalBytesToBeSent) OVERRIDE {
+ EXPECT_TRUE(loader_);
+ EXPECT_EQ(loader_.get(), loader);
+ }
+
+ virtual void didReceiveResponse(
+ blink::WebURLLoader* loader,
+ const blink::WebURLResponse& response) OVERRIDE {
+ EXPECT_TRUE(loader_);
+ EXPECT_EQ(loader_.get(), loader);
+
+ // Only multipart requests may receive multiple response headers.
+ EXPECT_TRUE(expect_multipart_response_ || !did_receive_response_);
+
+ did_receive_response_ = true;
+ if (delete_on_receive_response_)
+ loader_.reset();
+ }
+
+ virtual void didDownloadData(blink::WebURLLoader* loader,
+ int dataLength,
+ int encodedDataLength) OVERRIDE {
+ EXPECT_TRUE(loader_);
+ EXPECT_EQ(loader_.get(), loader);
+ }
+
+ virtual void didReceiveData(blink::WebURLLoader* loader,
+ const char* data,
+ int dataLength,
+ int encodedDataLength) OVERRIDE {
+ EXPECT_TRUE(loader_);
+ EXPECT_EQ(loader_.get(), loader);
+ // The response should have started, but must not have finished, or failed.
+ EXPECT_TRUE(did_receive_response_);
+ EXPECT_FALSE(did_finish_);
+ EXPECT_EQ(net::OK, error_.reason);
+ EXPECT_EQ("", error_.domain.utf8());
+
+ received_data_.append(data, dataLength);
+
+ if (delete_on_receive_data_)
+ loader_.reset();
+ }
+
+ virtual void didReceiveCachedMetadata(blink::WebURLLoader* loader,
+ const char* data,
+ int dataLength) OVERRIDE {
+ EXPECT_EQ(loader_.get(), loader);
+ }
+
+ virtual void didFinishLoading(blink::WebURLLoader* loader,
+ double finishTime,
+ int64_t totalEncodedDataLength) OVERRIDE {
+ EXPECT_TRUE(loader_);
+ EXPECT_EQ(loader_.get(), loader);
+ EXPECT_TRUE(did_receive_response_);
+ EXPECT_FALSE(did_finish_);
+ did_finish_ = true;
+
+ if (delete_on_finish_)
+ loader_.reset();
+ }
+
+ virtual void didFail(blink::WebURLLoader* loader,
+ const blink::WebURLError& error) OVERRIDE {
+ EXPECT_TRUE(loader_);
+ EXPECT_EQ(loader_.get(), loader);
+ EXPECT_FALSE(did_finish_);
+ error_ = error;
+
+ if (delete_on_fail_)
+ loader_.reset();
+ }
+
+ WebURLLoaderImpl* loader() { return loader_.get(); }
+ void DeleteLoader() {
+ loader_.reset();
+ }
+
+ void set_expect_multipart_response() { expect_multipart_response_ = true; }
+
+ void set_delete_on_receive_redirect() { delete_on_receive_redirect_ = true; }
+ void set_delete_on_receive_response() { delete_on_receive_response_ = true; }
+ void set_delete_on_receive_data() { delete_on_receive_data_ = true; }
+ void set_delete_on_finish() { delete_on_finish_ = true; }
+ void set_delete_on_fail() { delete_on_fail_ = true; }
+
+ bool did_receive_redirect() const { return did_receive_redirect_; }
+ bool did_receive_response() const { return did_receive_response_; }
+ const std::string& received_data() const { return received_data_; }
+ bool did_finish() const { return did_finish_; }
+ const blink::WebURLError& error() const { return error_; }
+
+ private:
+ scoped_ptr<WebURLLoaderImpl> loader_;
+
+ bool expect_multipart_response_;
+
+ bool delete_on_receive_redirect_;
+ bool delete_on_receive_response_;
+ bool delete_on_receive_data_;
+ bool delete_on_finish_;
+ bool delete_on_fail_;
+
+ bool did_receive_redirect_;
+ bool did_receive_response_;
+ std::string received_data_;
+ bool did_finish_;
+ blink::WebURLError error_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestWebURLLoaderClient);
+};
+
+class WebURLLoaderImplTest : public testing::Test {
+ public:
+ explicit WebURLLoaderImplTest() : client_(&dispatcher_) {}
+ virtual ~WebURLLoaderImplTest() {}
+
+ void DoStartAsyncRequest() {
+ blink::WebURLRequest request;
+ request.initialize();
+ request.setURL(GURL(kTestURL));
+ client()->loader()->loadAsynchronously(request, client());
+ ASSERT_TRUE(bridge());
+ ASSERT_TRUE(peer());
+ }
+
+ void DoReceiveRedirect() {
+ EXPECT_FALSE(client()->did_receive_redirect());
+ peer()->OnReceivedRedirect(GURL(kTestURL), GURL(kTestURL),
+ content::ResourceResponseInfo());
+ EXPECT_TRUE(client()->did_receive_redirect());
+ }
+
+ void DoReceiveResponse() {
+ EXPECT_FALSE(client()->did_receive_response());
+ peer()->OnReceivedResponse(content::ResourceResponseInfo());
+ EXPECT_TRUE(client()->did_receive_response());
+ }
+
+ // Assumes it is called only once for a request.
+ void DoReceiveData() {
+ EXPECT_EQ("", client()->received_data());
+ peer()->OnReceivedData(kTestData, strlen(kTestData), strlen(kTestData));
+ EXPECT_EQ(kTestData, client()->received_data());
+ }
+
+ void DoCompleteRequest() {
+ EXPECT_FALSE(client()->did_finish());
+ peer()->OnCompletedRequest(net::OK, false, false, "", base::TimeTicks(),
+ strlen(kTestData));
+ EXPECT_TRUE(client()->did_finish());
+ // There should be no error.
+ EXPECT_EQ(net::OK, client()->error().reason);
+ EXPECT_EQ("", client()->error().domain.utf8());
+ }
+
+ void DoFailRequest() {
+ EXPECT_FALSE(client()->did_finish());
+ peer()->OnCompletedRequest(net::ERR_FAILED, false, false, "",
+ base::TimeTicks(), strlen(kTestData));
+ EXPECT_FALSE(client()->did_finish());
+ EXPECT_EQ(net::ERR_FAILED, client()->error().reason);
+ EXPECT_EQ(net::kErrorDomain, client()->error().domain.utf8());
+ }
+
+ void DoReceiveResponseFtp() {
+ EXPECT_FALSE(client()->did_receive_response());
+ content::ResourceResponseInfo response_info;
+ response_info.mime_type = kFtpDirMimeType;
+ peer()->OnReceivedResponse(response_info);
+ EXPECT_TRUE(client()->did_receive_response());
+ }
+
+ void DoReceiveDataFtp() {
+ peer()->OnReceivedData(kFtpDirListing, strlen(kFtpDirListing),
+ strlen(kFtpDirListing));
+ // The FTP delegate should modify the data the client sees.
+ EXPECT_NE(kFtpDirListing, client()->received_data());
+ }
+
+ void DoReceiveResponseMultipart() {
+ EXPECT_FALSE(client()->did_receive_response());
+ content::ResourceResponseInfo response_info;
+ response_info.headers = new net::HttpResponseHeaders(
+ net::HttpUtil::AssembleRawHeaders(kMultipartResponseHeaders,
+ strlen(kMultipartResponseHeaders)));
+ response_info.mime_type = kMultipartResponseMimeType;
+ peer()->OnReceivedResponse(response_info);
+ EXPECT_TRUE(client()->did_receive_response());
+ }
+
+ void DoReceiveDataMultipart() {
+ peer()->OnReceivedData(kMultipartResponse, strlen(kMultipartResponse),
+ strlen(kMultipartResponse));
+ // Multipart delegate should modify the data the client sees.
+ EXPECT_NE(kMultipartResponse, client()->received_data());
+ }
+
+ TestWebURLLoaderClient* client() { return &client_; }
+ TestBridge* bridge() { return dispatcher_.bridge(); }
+ RequestPeer* peer() { return bridge()->peer(); }
+ base::MessageLoop* message_loop() { return &message_loop_; }
+
+ private:
+ TestResourceDispatcher dispatcher_;
+ TestWebURLLoaderClient client_;
+
+ base::MessageLoop message_loop_;
+};
+
+TEST_F(WebURLLoaderImplTest, Success) {
+ DoStartAsyncRequest();
+ DoReceiveResponse();
+ DoReceiveData();
+ DoCompleteRequest();
+ EXPECT_FALSE(bridge()->canceled());
+ EXPECT_EQ(kTestData, client()->received_data());
+}
+
+TEST_F(WebURLLoaderImplTest, Redirect) {
+ DoStartAsyncRequest();
+ DoReceiveRedirect();
+ DoReceiveResponse();
+ DoReceiveData();
+ DoCompleteRequest();
+ EXPECT_FALSE(bridge()->canceled());
+ EXPECT_EQ(kTestData, client()->received_data());
+}
+
+TEST_F(WebURLLoaderImplTest, Failure) {
+ DoStartAsyncRequest();
+ DoReceiveResponse();
+ DoReceiveData();
+ DoFailRequest();
+ EXPECT_FALSE(bridge()->canceled());
+}
+
+// The client may delete the WebURLLoader during any callback from the loader.
+// These tests make sure that doesn't result in a crash.
+TEST_F(WebURLLoaderImplTest, DeleteOnReceiveRedirect) {
+ client()->set_delete_on_receive_redirect();
+ DoStartAsyncRequest();
+ DoReceiveRedirect();
+ EXPECT_FALSE(bridge());
+}
+
+TEST_F(WebURLLoaderImplTest, DeleteOnReceiveResponse) {
+ client()->set_delete_on_receive_response();
+ DoStartAsyncRequest();
+ DoReceiveResponse();
+ EXPECT_FALSE(bridge());
+}
+
+TEST_F(WebURLLoaderImplTest, DeleteOnReceiveData) {
+ client()->set_delete_on_receive_data();
+ DoStartAsyncRequest();
+ DoReceiveResponse();
+ DoReceiveData();
+ EXPECT_FALSE(bridge());
+}
+
+TEST_F(WebURLLoaderImplTest, DeleteOnFinish) {
+ client()->set_delete_on_finish();
+ DoStartAsyncRequest();
+ DoReceiveResponse();
+ DoReceiveData();
+ DoCompleteRequest();
+ EXPECT_FALSE(bridge());
+}
+
+TEST_F(WebURLLoaderImplTest, DeleteOnFail) {
+ client()->set_delete_on_fail();
+ DoStartAsyncRequest();
+ DoReceiveResponse();
+ DoReceiveData();
+ DoFailRequest();
+ EXPECT_FALSE(bridge());
+}
+
+TEST_F(WebURLLoaderImplTest, DeleteBeforeResponseDataURL) {
+ blink::WebURLRequest request;
+ request.initialize();
+ request.setURL(GURL("data:text/html;charset=utf-8,blah!"));
+ client()->loader()->loadAsynchronously(request, client());
+ client()->DeleteLoader();
+ message_loop()->RunUntilIdle();
+ EXPECT_FALSE(client()->did_receive_response());
+ EXPECT_FALSE(bridge());
+}
+
+// Data URL tests.
+
+TEST_F(WebURLLoaderImplTest, DataURL) {
+ blink::WebURLRequest request;
+ request.initialize();
+ request.setURL(GURL("data:text/html;charset=utf-8,blah!"));
+ client()->loader()->loadAsynchronously(request, client());
+ message_loop()->RunUntilIdle();
+ EXPECT_EQ("blah!", client()->received_data());
+ EXPECT_TRUE(client()->did_finish());
+ EXPECT_EQ(net::OK, client()->error().reason);
+ EXPECT_EQ("", client()->error().domain.utf8());
+}
+
+TEST_F(WebURLLoaderImplTest, DataURLDeleteOnReceiveResponse) {
+ blink::WebURLRequest request;
+ request.initialize();
+ request.setURL(GURL("data:text/html;charset=utf-8,blah!"));
+ client()->set_delete_on_receive_response();
+ client()->loader()->loadAsynchronously(request, client());
+ message_loop()->RunUntilIdle();
+ EXPECT_TRUE(client()->did_receive_response());
+ EXPECT_EQ("", client()->received_data());
+ EXPECT_FALSE(client()->did_finish());
+ EXPECT_FALSE(bridge());
+}
+
+TEST_F(WebURLLoaderImplTest, DataURLDeleteOnReceiveData) {
+ blink::WebURLRequest request;
+ request.initialize();
+ request.setURL(GURL("data:text/html;charset=utf-8,blah!"));
+ client()->set_delete_on_receive_data();
+ client()->loader()->loadAsynchronously(request, client());
+ message_loop()->RunUntilIdle();
+ EXPECT_TRUE(client()->did_receive_response());
+ EXPECT_EQ("blah!", client()->received_data());
+ EXPECT_FALSE(client()->did_finish());
+ EXPECT_FALSE(bridge());
+}
+
+TEST_F(WebURLLoaderImplTest, DataURLDeleteOnFinisha) {
+ blink::WebURLRequest request;
+ request.initialize();
+ request.setURL(GURL("data:text/html;charset=utf-8,blah!"));
+ client()->set_delete_on_finish();
+ client()->loader()->loadAsynchronously(request, client());
+ message_loop()->RunUntilIdle();
+ EXPECT_TRUE(client()->did_receive_response());
+ EXPECT_EQ("blah!", client()->received_data());
+ EXPECT_TRUE(client()->did_finish());
+ EXPECT_FALSE(bridge());
+}
+
+// FTP integration tests. These are focused more on safe deletion than correct
+// parsing of FTP responses.
+
+TEST_F(WebURLLoaderImplTest, Ftp) {
+ DoStartAsyncRequest();
+ DoReceiveResponseFtp();
+ DoReceiveDataFtp();
+ DoCompleteRequest();
+ EXPECT_FALSE(bridge()->canceled());
+}
+
+TEST_F(WebURLLoaderImplTest, FtpDeleteOnReceiveResponse) {
+ client()->set_delete_on_receive_response();
+ DoStartAsyncRequest();
+ DoReceiveResponseFtp();
+
+ // No data should have been received.
+ EXPECT_EQ("", client()->received_data());
+ EXPECT_FALSE(bridge());
+}
+
+TEST_F(WebURLLoaderImplTest, FtpDeleteOnReceiveFirstData) {
+ client()->set_delete_on_receive_data();
+ DoStartAsyncRequest();
+ // Some data is sent in ReceiveResponse for FTP requests, so the bridge should
+ // be deleted here.
+ DoReceiveResponseFtp();
+
+ EXPECT_NE("", client()->received_data());
+ EXPECT_FALSE(bridge());
+}
+
+TEST_F(WebURLLoaderImplTest, FtpDeleteOnReceiveMoreData) {
+ DoStartAsyncRequest();
+ DoReceiveResponseFtp();
+ DoReceiveDataFtp();
+
+ // Directory listings are only parsed once the request completes, so this will
+ // cancel in DoReceiveDataFtp, before the request finishes.
+ client()->set_delete_on_receive_data();
+ peer()->OnCompletedRequest(net::OK, false, false, "", base::TimeTicks(),
+ strlen(kTestData));
+ EXPECT_FALSE(client()->did_finish());
+
+ EXPECT_FALSE(bridge());
+}
+
+TEST_F(WebURLLoaderImplTest, FtpDeleteOnFinish) {
+ client()->set_delete_on_finish();
+ DoStartAsyncRequest();
+ DoReceiveResponseFtp();
+ DoReceiveDataFtp();
+ DoCompleteRequest();
+ EXPECT_FALSE(bridge());
+}
+
+TEST_F(WebURLLoaderImplTest, FtpDeleteOnFail) {
+ client()->set_delete_on_fail();
+ DoStartAsyncRequest();
+ DoReceiveResponseFtp();
+ DoReceiveDataFtp();
+ DoFailRequest();
+ EXPECT_FALSE(bridge());
+}
+
+// Multipart integration tests. These are focused more on safe deletion than
+// correct parsing of Multipart responses.
+
+TEST_F(WebURLLoaderImplTest, Multipart) {
+ client()->set_expect_multipart_response();
+ DoStartAsyncRequest();
+ DoReceiveResponseMultipart();
+ DoReceiveDataMultipart();
+ DoCompleteRequest();
+ EXPECT_EQ(kTestData, client()->received_data());
+ EXPECT_FALSE(bridge()->canceled());
+}
+
+TEST_F(WebURLLoaderImplTest, MultipartDeleteOnReceiveFirstResponse) {
+ client()->set_expect_multipart_response();
+ client()->set_delete_on_receive_response();
+ DoStartAsyncRequest();
+ DoReceiveResponseMultipart();
+ EXPECT_EQ("", client()->received_data());
+ EXPECT_FALSE(bridge());
+}
+
+TEST_F(WebURLLoaderImplTest, MultipartDeleteOnReceiveSecondResponse) {
+ client()->set_expect_multipart_response();
+ DoStartAsyncRequest();
+ DoReceiveResponseMultipart();
+ client()->set_delete_on_receive_response();
+ DoReceiveDataMultipart();
+ EXPECT_EQ("", client()->received_data());
+ EXPECT_FALSE(bridge());
+}
+
+TEST_F(WebURLLoaderImplTest, MultipartDeleteOnReceiveFirstData) {
+ client()->set_expect_multipart_response();
+ client()->set_delete_on_receive_data();
+ DoStartAsyncRequest();
+ DoReceiveResponseMultipart();
+ DoReceiveDataMultipart();
+ EXPECT_EQ("bl", client()->received_data());
+ EXPECT_FALSE(bridge());
+}
+
+TEST_F(WebURLLoaderImplTest, MultipartDeleteOnReceiveMoreData) {
+ client()->set_expect_multipart_response();
+ DoStartAsyncRequest();
+ DoReceiveResponseMultipart();
+ DoReceiveDataMultipart();
+ // For multipart responses, the delegate may send some data when notified
+ // of a request completing.
+ client()->set_delete_on_receive_data();
+ peer()->OnCompletedRequest(net::OK, false, false, "", base::TimeTicks(),
+ strlen(kTestData));
+ EXPECT_FALSE(client()->did_finish());
+ EXPECT_EQ(kTestData, client()->received_data());
+ EXPECT_FALSE(bridge());
+}
+
+TEST_F(WebURLLoaderImplTest, MultipartDeleteFinish) {
+ client()->set_expect_multipart_response();
+ client()->set_delete_on_finish();
+ DoStartAsyncRequest();
+ DoReceiveResponseMultipart();
+ DoReceiveDataMultipart();
+ DoCompleteRequest();
+ EXPECT_EQ(kTestData, client()->received_data());
+ EXPECT_FALSE(bridge());
+}
+
+TEST_F(WebURLLoaderImplTest, MultipartDeleteFail) {
+ client()->set_expect_multipart_response();
+ client()->set_delete_on_fail();
+ DoStartAsyncRequest();
+ DoReceiveResponseMultipart();
+ DoReceiveDataMultipart();
+ DoFailRequest();
+ EXPECT_FALSE(bridge());
+}
+
+} // namespace
+} // namespace content