blob: 61a7f59190b74b64bd7037b558a655dcdd6c1424 [file] [log] [blame]
// 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 "core/fetch/Response.h"
#include <memory>
#include "bindings/core/v8/ExceptionState.h"
#include "bindings/core/v8/V8BindingForTesting.h"
#include "core/dom/ExecutionContext.h"
#include "core/fetch/BodyStreamBuffer.h"
#include "core/fetch/BytesConsumer.h"
#include "core/fetch/BytesConsumerTestUtil.h"
#include "core/fetch/DataConsumerHandleTestUtil.h"
#include "core/fetch/FetchResponseData.h"
#include "core/frame/Frame.h"
#include "core/testing/DummyPageHolder.h"
#include "platform/bindings/ScriptState.h"
#include "platform/blob/BlobData.h"
#include "platform/testing/UnitTestHelpers.h"
#include "platform/wtf/Vector.h"
#include "public/platform/modules/fetch/fetch_api_request.mojom-blink.h"
#include "public/platform/modules/serviceworker/WebServiceWorkerResponse.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace blink {
namespace {
std::unique_ptr<WebServiceWorkerResponse> CreateTestWebServiceWorkerResponse() {
const KURL url("http://www.webresponse.com/");
const unsigned short kStatus = 200;
const String status_text = "the best status text";
struct {
const char* key;
const char* value;
} headers[] = {{"cache-control", "no-cache"},
{"set-cookie", "foop"},
{"foo", "bar"},
{nullptr, nullptr}};
Vector<WebURL> url_list;
url_list.push_back(url);
std::unique_ptr<WebServiceWorkerResponse> web_response =
std::make_unique<WebServiceWorkerResponse>();
web_response->SetURLList(url_list);
web_response->SetStatus(kStatus);
web_response->SetStatusText(status_text);
web_response->SetResponseType(network::mojom::FetchResponseType::kDefault);
for (int i = 0; headers[i].key; ++i) {
web_response->SetHeader(WebString::FromUTF8(headers[i].key),
WebString::FromUTF8(headers[i].value));
}
return web_response;
}
TEST(ServiceWorkerResponseTest, FromFetchResponseData) {
std::unique_ptr<DummyPageHolder> page =
DummyPageHolder::Create(IntSize(1, 1));
const KURL url("http://www.response.com");
FetchResponseData* fetch_response_data = FetchResponseData::Create();
Vector<KURL> url_list;
url_list.push_back(url);
fetch_response_data->SetURLList(url_list);
Response* response =
Response::Create(&page->GetDocument(), fetch_response_data);
DCHECK(response);
EXPECT_EQ(url, response->url());
}
TEST(ServiceWorkerResponseTest, FromWebServiceWorkerResponse) {
V8TestingScope scope;
std::unique_ptr<WebServiceWorkerResponse> web_response =
CreateTestWebServiceWorkerResponse();
Response* response = Response::Create(scope.GetScriptState(), *web_response);
DCHECK(response);
ASSERT_EQ(1u, web_response->UrlList().size());
EXPECT_EQ(web_response->UrlList()[0], response->url());
EXPECT_EQ(web_response->Status(), response->status());
EXPECT_STREQ(web_response->StatusText().Utf8().c_str(),
response->statusText().Utf8().data());
Headers* response_headers = response->headers();
WebVector<WebString> keys = web_response->GetHeaderKeys();
EXPECT_EQ(keys.size(), response_headers->HeaderList()->size());
for (size_t i = 0, max = keys.size(); i < max; ++i) {
WebString key = keys[i];
DummyExceptionStateForTesting exception_state;
EXPECT_STREQ(web_response->GetHeader(key).Utf8().c_str(),
response_headers->get(key, exception_state).Utf8().data());
EXPECT_FALSE(exception_state.HadException());
}
}
TEST(ServiceWorkerResponseTest, FromWebServiceWorkerResponseDefault) {
V8TestingScope scope;
std::unique_ptr<WebServiceWorkerResponse> web_response =
CreateTestWebServiceWorkerResponse();
web_response->SetResponseType(network::mojom::FetchResponseType::kDefault);
Response* response = Response::Create(scope.GetScriptState(), *web_response);
Headers* response_headers = response->headers();
DummyExceptionStateForTesting exception_state;
EXPECT_STREQ(
"foop",
response_headers->get("set-cookie", exception_state).Utf8().data());
EXPECT_STREQ("bar",
response_headers->get("foo", exception_state).Utf8().data());
EXPECT_STREQ(
"no-cache",
response_headers->get("cache-control", exception_state).Utf8().data());
EXPECT_FALSE(exception_state.HadException());
}
TEST(ServiceWorkerResponseTest, FromWebServiceWorkerResponseBasic) {
V8TestingScope scope;
std::unique_ptr<WebServiceWorkerResponse> web_response =
CreateTestWebServiceWorkerResponse();
web_response->SetResponseType(network::mojom::FetchResponseType::kBasic);
Response* response = Response::Create(scope.GetScriptState(), *web_response);
Headers* response_headers = response->headers();
DummyExceptionStateForTesting exception_state;
EXPECT_STREQ(
"", response_headers->get("set-cookie", exception_state).Utf8().data());
EXPECT_STREQ("bar",
response_headers->get("foo", exception_state).Utf8().data());
EXPECT_STREQ(
"no-cache",
response_headers->get("cache-control", exception_state).Utf8().data());
EXPECT_FALSE(exception_state.HadException());
}
TEST(ServiceWorkerResponseTest, FromWebServiceWorkerResponseCORS) {
V8TestingScope scope;
std::unique_ptr<WebServiceWorkerResponse> web_response =
CreateTestWebServiceWorkerResponse();
web_response->SetResponseType(network::mojom::FetchResponseType::kCORS);
Response* response = Response::Create(scope.GetScriptState(), *web_response);
Headers* response_headers = response->headers();
DummyExceptionStateForTesting exception_state;
EXPECT_STREQ(
"", response_headers->get("set-cookie", exception_state).Utf8().data());
EXPECT_STREQ("", response_headers->get("foo", exception_state).Utf8().data());
EXPECT_STREQ(
"no-cache",
response_headers->get("cache-control", exception_state).Utf8().data());
EXPECT_FALSE(exception_state.HadException());
}
TEST(ServiceWorkerResponseTest, FromWebServiceWorkerResponseOpaque) {
V8TestingScope scope;
std::unique_ptr<WebServiceWorkerResponse> web_response =
CreateTestWebServiceWorkerResponse();
web_response->SetResponseType(network::mojom::FetchResponseType::kOpaque);
Response* response = Response::Create(scope.GetScriptState(), *web_response);
Headers* response_headers = response->headers();
DummyExceptionStateForTesting exception_state;
EXPECT_STREQ(
"", response_headers->get("set-cookie", exception_state).Utf8().data());
EXPECT_STREQ("", response_headers->get("foo", exception_state).Utf8().data());
EXPECT_STREQ(
"",
response_headers->get("cache-control", exception_state).Utf8().data());
EXPECT_FALSE(exception_state.HadException());
}
void CheckResponseStream(ScriptState* script_state,
Response* response,
bool check_response_body_stream_buffer) {
BodyStreamBuffer* original_internal = response->InternalBodyBuffer();
if (check_response_body_stream_buffer) {
EXPECT_EQ(response->BodyBuffer(), original_internal);
} else {
EXPECT_FALSE(response->BodyBuffer());
}
DummyExceptionStateForTesting exception_state;
Response* cloned_response = response->clone(script_state, exception_state);
EXPECT_FALSE(exception_state.HadException());
if (!response->InternalBodyBuffer())
FAIL() << "internalBodyBuffer() must not be null.";
if (!cloned_response->InternalBodyBuffer())
FAIL() << "internalBodyBuffer() must not be null.";
EXPECT_TRUE(response->InternalBodyBuffer());
EXPECT_TRUE(cloned_response->InternalBodyBuffer());
EXPECT_TRUE(response->InternalBodyBuffer());
EXPECT_TRUE(cloned_response->InternalBodyBuffer());
EXPECT_NE(response->InternalBodyBuffer(), original_internal);
EXPECT_NE(cloned_response->InternalBodyBuffer(), original_internal);
EXPECT_NE(response->InternalBodyBuffer(),
cloned_response->InternalBodyBuffer());
if (check_response_body_stream_buffer) {
EXPECT_EQ(response->BodyBuffer(), response->InternalBodyBuffer());
EXPECT_EQ(cloned_response->BodyBuffer(),
cloned_response->InternalBodyBuffer());
} else {
EXPECT_FALSE(response->BodyBuffer());
EXPECT_FALSE(cloned_response->BodyBuffer());
}
BytesConsumerTestUtil::MockFetchDataLoaderClient* client1 =
new BytesConsumerTestUtil::MockFetchDataLoaderClient();
BytesConsumerTestUtil::MockFetchDataLoaderClient* client2 =
new BytesConsumerTestUtil::MockFetchDataLoaderClient();
EXPECT_CALL(*client1, DidFetchDataLoadedString(String("Hello, world")));
EXPECT_CALL(*client2, DidFetchDataLoadedString(String("Hello, world")));
response->InternalBodyBuffer()->StartLoading(
FetchDataLoader::CreateLoaderAsString(), client1);
cloned_response->InternalBodyBuffer()->StartLoading(
FetchDataLoader::CreateLoaderAsString(), client2);
blink::testing::RunPendingTasks();
}
BodyStreamBuffer* CreateHelloWorldBuffer(ScriptState* script_state) {
using BytesConsumerCommand = BytesConsumerTestUtil::Command;
BytesConsumerTestUtil::ReplayingBytesConsumer* src =
new BytesConsumerTestUtil::ReplayingBytesConsumer(
ExecutionContext::From(script_state));
src->Add(BytesConsumerCommand(BytesConsumerCommand::kData, "Hello, "));
src->Add(BytesConsumerCommand(BytesConsumerCommand::kData, "world"));
src->Add(BytesConsumerCommand(BytesConsumerCommand::kDone));
return new BodyStreamBuffer(script_state, src);
}
TEST(ServiceWorkerResponseTest, BodyStreamBufferCloneDefault) {
V8TestingScope scope;
BodyStreamBuffer* buffer = CreateHelloWorldBuffer(scope.GetScriptState());
FetchResponseData* fetch_response_data =
FetchResponseData::CreateWithBuffer(buffer);
Vector<KURL> url_list;
url_list.push_back(KURL("http://www.response.com"));
fetch_response_data->SetURLList(url_list);
Response* response =
Response::Create(scope.GetExecutionContext(), fetch_response_data);
EXPECT_EQ(response->InternalBodyBuffer(), buffer);
CheckResponseStream(scope.GetScriptState(), response, true);
}
TEST(ServiceWorkerResponseTest, BodyStreamBufferCloneBasic) {
V8TestingScope scope;
BodyStreamBuffer* buffer = CreateHelloWorldBuffer(scope.GetScriptState());
FetchResponseData* fetch_response_data =
FetchResponseData::CreateWithBuffer(buffer);
Vector<KURL> url_list;
url_list.push_back(KURL("http://www.response.com"));
fetch_response_data->SetURLList(url_list);
fetch_response_data = fetch_response_data->CreateBasicFilteredResponse();
Response* response =
Response::Create(scope.GetExecutionContext(), fetch_response_data);
EXPECT_EQ(response->InternalBodyBuffer(), buffer);
CheckResponseStream(scope.GetScriptState(), response, true);
}
TEST(ServiceWorkerResponseTest, BodyStreamBufferCloneCORS) {
V8TestingScope scope;
BodyStreamBuffer* buffer = CreateHelloWorldBuffer(scope.GetScriptState());
FetchResponseData* fetch_response_data =
FetchResponseData::CreateWithBuffer(buffer);
Vector<KURL> url_list;
url_list.push_back(KURL("http://www.response.com"));
fetch_response_data->SetURLList(url_list);
fetch_response_data = fetch_response_data->CreateCORSFilteredResponse({});
Response* response =
Response::Create(scope.GetExecutionContext(), fetch_response_data);
EXPECT_EQ(response->InternalBodyBuffer(), buffer);
CheckResponseStream(scope.GetScriptState(), response, true);
}
TEST(ServiceWorkerResponseTest, BodyStreamBufferCloneOpaque) {
V8TestingScope scope;
BodyStreamBuffer* buffer = CreateHelloWorldBuffer(scope.GetScriptState());
FetchResponseData* fetch_response_data =
FetchResponseData::CreateWithBuffer(buffer);
Vector<KURL> url_list;
url_list.push_back(KURL("http://www.response.com"));
fetch_response_data->SetURLList(url_list);
fetch_response_data = fetch_response_data->CreateOpaqueFilteredResponse();
Response* response =
Response::Create(scope.GetExecutionContext(), fetch_response_data);
EXPECT_EQ(response->InternalBodyBuffer(), buffer);
CheckResponseStream(scope.GetScriptState(), response, false);
}
TEST(ServiceWorkerResponseTest, BodyStreamBufferCloneError) {
V8TestingScope scope;
BodyStreamBuffer* buffer = new BodyStreamBuffer(
scope.GetScriptState(),
BytesConsumer::CreateErrored(BytesConsumer::Error()));
FetchResponseData* fetch_response_data =
FetchResponseData::CreateWithBuffer(buffer);
Vector<KURL> url_list;
url_list.push_back(KURL("http://www.response.com"));
fetch_response_data->SetURLList(url_list);
Response* response =
Response::Create(scope.GetExecutionContext(), fetch_response_data);
DummyExceptionStateForTesting exception_state;
Response* cloned_response =
response->clone(scope.GetScriptState(), exception_state);
EXPECT_FALSE(exception_state.HadException());
BytesConsumerTestUtil::MockFetchDataLoaderClient* client1 =
new BytesConsumerTestUtil::MockFetchDataLoaderClient();
BytesConsumerTestUtil::MockFetchDataLoaderClient* client2 =
new BytesConsumerTestUtil::MockFetchDataLoaderClient();
EXPECT_CALL(*client1, DidFetchDataLoadFailed());
EXPECT_CALL(*client2, DidFetchDataLoadFailed());
response->InternalBodyBuffer()->StartLoading(
FetchDataLoader::CreateLoaderAsString(), client1);
cloned_response->InternalBodyBuffer()->StartLoading(
FetchDataLoader::CreateLoaderAsString(), client2);
blink::testing::RunPendingTasks();
}
} // namespace
} // namespace blink