| // 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 "modules/fetch/Response.h" |
| |
| #include "bindings/core/v8/ExceptionState.h" |
| #include "bindings/core/v8/ScriptState.h" |
| #include "bindings/core/v8/V8BindingForTesting.h" |
| #include "core/dom/Document.h" |
| #include "core/frame/Frame.h" |
| #include "core/testing/DummyPageHolder.h" |
| #include "modules/fetch/BodyStreamBuffer.h" |
| #include "modules/fetch/BytesConsumer.h" |
| #include "modules/fetch/BytesConsumerTestUtil.h" |
| #include "modules/fetch/DataConsumerHandleTestUtil.h" |
| #include "modules/fetch/FetchResponseData.h" |
| #include "platform/blob/BlobData.h" |
| #include "platform/testing/UnitTestHelpers.h" |
| #include "public/platform/modules/serviceworker/WebServiceWorkerResponse.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "wtf/PtrUtil.h" |
| #include "wtf/Vector.h" |
| #include <memory> |
| |
| namespace blink { |
| namespace { |
| |
| std::unique_ptr<WebServiceWorkerResponse> createTestWebServiceWorkerResponse() { |
| const KURL url(ParsedURLString, "http://www.webresponse.com/"); |
| const unsigned short status = 200; |
| const String statusText = "the best status text"; |
| struct { |
| const char* key; |
| const char* value; |
| } headers[] = {{"cache-control", "no-cache"}, |
| {"set-cookie", "foop"}, |
| {"foo", "bar"}, |
| {0, 0}}; |
| Vector<WebURL> urlList; |
| urlList.push_back(url); |
| std::unique_ptr<WebServiceWorkerResponse> webResponse = |
| WTF::makeUnique<WebServiceWorkerResponse>(); |
| webResponse->setURLList(urlList); |
| webResponse->setStatus(status); |
| webResponse->setStatusText(statusText); |
| webResponse->setResponseType(WebServiceWorkerResponseTypeDefault); |
| for (int i = 0; headers[i].key; ++i) |
| webResponse->setHeader(WebString::fromUTF8(headers[i].key), |
| WebString::fromUTF8(headers[i].value)); |
| return webResponse; |
| } |
| |
| TEST(ServiceWorkerResponseTest, FromFetchResponseData) { |
| std::unique_ptr<DummyPageHolder> page = |
| DummyPageHolder::create(IntSize(1, 1)); |
| const KURL url(ParsedURLString, "http://www.response.com"); |
| |
| FetchResponseData* fetchResponseData = FetchResponseData::create(); |
| Vector<KURL> urlList; |
| urlList.push_back(url); |
| fetchResponseData->setURLList(urlList); |
| Response* response = Response::create(&page->document(), fetchResponseData); |
| ASSERT(response); |
| EXPECT_EQ(url, response->url()); |
| } |
| |
| TEST(ServiceWorkerResponseTest, FromWebServiceWorkerResponse) { |
| V8TestingScope scope; |
| std::unique_ptr<WebServiceWorkerResponse> webResponse = |
| createTestWebServiceWorkerResponse(); |
| Response* response = Response::create(scope.getScriptState(), *webResponse); |
| ASSERT(response); |
| ASSERT_EQ(1u, webResponse->urlList().size()); |
| EXPECT_EQ(webResponse->urlList()[0], response->url()); |
| EXPECT_EQ(webResponse->status(), response->status()); |
| EXPECT_STREQ(webResponse->statusText().utf8().c_str(), |
| response->statusText().utf8().data()); |
| |
| Headers* responseHeaders = response->headers(); |
| |
| WebVector<WebString> keys = webResponse->getHeaderKeys(); |
| EXPECT_EQ(keys.size(), responseHeaders->headerList()->size()); |
| for (size_t i = 0, max = keys.size(); i < max; ++i) { |
| WebString key = keys[i]; |
| DummyExceptionStateForTesting exceptionState; |
| EXPECT_STREQ(webResponse->getHeader(key).utf8().c_str(), |
| responseHeaders->get(key, exceptionState).utf8().data()); |
| EXPECT_FALSE(exceptionState.hadException()); |
| } |
| } |
| |
| TEST(ServiceWorkerResponseTest, FromWebServiceWorkerResponseDefault) { |
| V8TestingScope scope; |
| std::unique_ptr<WebServiceWorkerResponse> webResponse = |
| createTestWebServiceWorkerResponse(); |
| webResponse->setResponseType(WebServiceWorkerResponseTypeDefault); |
| Response* response = Response::create(scope.getScriptState(), *webResponse); |
| |
| Headers* responseHeaders = response->headers(); |
| DummyExceptionStateForTesting exceptionState; |
| EXPECT_STREQ( |
| "foop", responseHeaders->get("set-cookie", exceptionState).utf8().data()); |
| EXPECT_STREQ("bar", |
| responseHeaders->get("foo", exceptionState).utf8().data()); |
| EXPECT_STREQ( |
| "no-cache", |
| responseHeaders->get("cache-control", exceptionState).utf8().data()); |
| EXPECT_FALSE(exceptionState.hadException()); |
| } |
| |
| TEST(ServiceWorkerResponseTest, FromWebServiceWorkerResponseBasic) { |
| V8TestingScope scope; |
| std::unique_ptr<WebServiceWorkerResponse> webResponse = |
| createTestWebServiceWorkerResponse(); |
| webResponse->setResponseType(WebServiceWorkerResponseTypeBasic); |
| Response* response = Response::create(scope.getScriptState(), *webResponse); |
| |
| Headers* responseHeaders = response->headers(); |
| DummyExceptionStateForTesting exceptionState; |
| EXPECT_STREQ( |
| "", responseHeaders->get("set-cookie", exceptionState).utf8().data()); |
| EXPECT_STREQ("bar", |
| responseHeaders->get("foo", exceptionState).utf8().data()); |
| EXPECT_STREQ( |
| "no-cache", |
| responseHeaders->get("cache-control", exceptionState).utf8().data()); |
| EXPECT_FALSE(exceptionState.hadException()); |
| } |
| |
| TEST(ServiceWorkerResponseTest, FromWebServiceWorkerResponseCORS) { |
| V8TestingScope scope; |
| std::unique_ptr<WebServiceWorkerResponse> webResponse = |
| createTestWebServiceWorkerResponse(); |
| webResponse->setResponseType(WebServiceWorkerResponseTypeCORS); |
| Response* response = Response::create(scope.getScriptState(), *webResponse); |
| |
| Headers* responseHeaders = response->headers(); |
| DummyExceptionStateForTesting exceptionState; |
| EXPECT_STREQ( |
| "", responseHeaders->get("set-cookie", exceptionState).utf8().data()); |
| EXPECT_STREQ("", responseHeaders->get("foo", exceptionState).utf8().data()); |
| EXPECT_STREQ( |
| "no-cache", |
| responseHeaders->get("cache-control", exceptionState).utf8().data()); |
| EXPECT_FALSE(exceptionState.hadException()); |
| } |
| |
| TEST(ServiceWorkerResponseTest, FromWebServiceWorkerResponseOpaque) { |
| V8TestingScope scope; |
| std::unique_ptr<WebServiceWorkerResponse> webResponse = |
| createTestWebServiceWorkerResponse(); |
| webResponse->setResponseType(WebServiceWorkerResponseTypeOpaque); |
| Response* response = Response::create(scope.getScriptState(), *webResponse); |
| |
| Headers* responseHeaders = response->headers(); |
| DummyExceptionStateForTesting exceptionState; |
| EXPECT_STREQ( |
| "", responseHeaders->get("set-cookie", exceptionState).utf8().data()); |
| EXPECT_STREQ("", responseHeaders->get("foo", exceptionState).utf8().data()); |
| EXPECT_STREQ( |
| "", responseHeaders->get("cache-control", exceptionState).utf8().data()); |
| EXPECT_FALSE(exceptionState.hadException()); |
| } |
| |
| void checkResponseStream(ScriptState* scriptState, |
| Response* response, |
| bool checkResponseBodyStreamBuffer) { |
| BodyStreamBuffer* originalInternal = response->internalBodyBuffer(); |
| if (checkResponseBodyStreamBuffer) { |
| EXPECT_EQ(response->bodyBuffer(), originalInternal); |
| } else { |
| EXPECT_FALSE(response->bodyBuffer()); |
| } |
| |
| DummyExceptionStateForTesting exceptionState; |
| Response* clonedResponse = response->clone(scriptState, exceptionState); |
| EXPECT_FALSE(exceptionState.hadException()); |
| |
| if (!response->internalBodyBuffer()) |
| FAIL() << "internalBodyBuffer() must not be null."; |
| if (!clonedResponse->internalBodyBuffer()) |
| FAIL() << "internalBodyBuffer() must not be null."; |
| EXPECT_TRUE(response->internalBodyBuffer()); |
| EXPECT_TRUE(clonedResponse->internalBodyBuffer()); |
| EXPECT_TRUE(response->internalBodyBuffer()); |
| EXPECT_TRUE(clonedResponse->internalBodyBuffer()); |
| EXPECT_NE(response->internalBodyBuffer(), originalInternal); |
| EXPECT_NE(clonedResponse->internalBodyBuffer(), originalInternal); |
| EXPECT_NE(response->internalBodyBuffer(), |
| clonedResponse->internalBodyBuffer()); |
| if (checkResponseBodyStreamBuffer) { |
| EXPECT_EQ(response->bodyBuffer(), response->internalBodyBuffer()); |
| EXPECT_EQ(clonedResponse->bodyBuffer(), |
| clonedResponse->internalBodyBuffer()); |
| } else { |
| EXPECT_FALSE(response->bodyBuffer()); |
| EXPECT_FALSE(clonedResponse->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); |
| clonedResponse->internalBodyBuffer()->startLoading( |
| FetchDataLoader::createLoaderAsString(), client2); |
| blink::testing::runPendingTasks(); |
| } |
| |
| BodyStreamBuffer* createHelloWorldBuffer(ScriptState* scriptState) { |
| using Command = BytesConsumerTestUtil::Command; |
| BytesConsumerTestUtil::ReplayingBytesConsumer* src = |
| new BytesConsumerTestUtil::ReplayingBytesConsumer( |
| scriptState->getExecutionContext()); |
| src->add(Command(Command::Data, "Hello, ")); |
| src->add(Command(Command::Data, "world")); |
| src->add(Command(Command::Done)); |
| return new BodyStreamBuffer(scriptState, src); |
| } |
| |
| TEST(ServiceWorkerResponseTest, BodyStreamBufferCloneDefault) { |
| V8TestingScope scope; |
| BodyStreamBuffer* buffer = createHelloWorldBuffer(scope.getScriptState()); |
| FetchResponseData* fetchResponseData = |
| FetchResponseData::createWithBuffer(buffer); |
| Vector<KURL> urlList; |
| urlList.push_back(KURL(ParsedURLString, "http://www.response.com")); |
| fetchResponseData->setURLList(urlList); |
| Response* response = |
| Response::create(scope.getExecutionContext(), fetchResponseData); |
| EXPECT_EQ(response->internalBodyBuffer(), buffer); |
| checkResponseStream(scope.getScriptState(), response, true); |
| } |
| |
| TEST(ServiceWorkerResponseTest, BodyStreamBufferCloneBasic) { |
| V8TestingScope scope; |
| BodyStreamBuffer* buffer = createHelloWorldBuffer(scope.getScriptState()); |
| FetchResponseData* fetchResponseData = |
| FetchResponseData::createWithBuffer(buffer); |
| Vector<KURL> urlList; |
| urlList.push_back(KURL(ParsedURLString, "http://www.response.com")); |
| fetchResponseData->setURLList(urlList); |
| fetchResponseData = fetchResponseData->createBasicFilteredResponse(); |
| Response* response = |
| Response::create(scope.getExecutionContext(), fetchResponseData); |
| EXPECT_EQ(response->internalBodyBuffer(), buffer); |
| checkResponseStream(scope.getScriptState(), response, true); |
| } |
| |
| TEST(ServiceWorkerResponseTest, BodyStreamBufferCloneCORS) { |
| V8TestingScope scope; |
| BodyStreamBuffer* buffer = createHelloWorldBuffer(scope.getScriptState()); |
| FetchResponseData* fetchResponseData = |
| FetchResponseData::createWithBuffer(buffer); |
| Vector<KURL> urlList; |
| urlList.push_back(KURL(ParsedURLString, "http://www.response.com")); |
| fetchResponseData->setURLList(urlList); |
| fetchResponseData = fetchResponseData->createCORSFilteredResponse(); |
| Response* response = |
| Response::create(scope.getExecutionContext(), fetchResponseData); |
| EXPECT_EQ(response->internalBodyBuffer(), buffer); |
| checkResponseStream(scope.getScriptState(), response, true); |
| } |
| |
| TEST(ServiceWorkerResponseTest, BodyStreamBufferCloneOpaque) { |
| V8TestingScope scope; |
| BodyStreamBuffer* buffer = createHelloWorldBuffer(scope.getScriptState()); |
| FetchResponseData* fetchResponseData = |
| FetchResponseData::createWithBuffer(buffer); |
| Vector<KURL> urlList; |
| urlList.push_back(KURL(ParsedURLString, "http://www.response.com")); |
| fetchResponseData->setURLList(urlList); |
| fetchResponseData = fetchResponseData->createOpaqueFilteredResponse(); |
| Response* response = |
| Response::create(scope.getExecutionContext(), fetchResponseData); |
| 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* fetchResponseData = |
| FetchResponseData::createWithBuffer(buffer); |
| Vector<KURL> urlList; |
| urlList.push_back(KURL(ParsedURLString, "http://www.response.com")); |
| fetchResponseData->setURLList(urlList); |
| Response* response = |
| Response::create(scope.getExecutionContext(), fetchResponseData); |
| DummyExceptionStateForTesting exceptionState; |
| Response* clonedResponse = |
| response->clone(scope.getScriptState(), exceptionState); |
| EXPECT_FALSE(exceptionState.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); |
| clonedResponse->internalBodyBuffer()->startLoading( |
| FetchDataLoader::createLoaderAsString(), client2); |
| blink::testing::runPendingTasks(); |
| } |
| |
| } // namespace |
| } // namespace blink |