1/*
2 * Copyright (C) 2016 Canon Inc.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted, provided that the following conditions
6 * are required to be met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Canon Inc. nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY CANON INC. AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL CANON INC. AND ITS CONTRIBUTORS BE LIABLE FOR
21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include "config.h"
30#include "FetchLoader.h"
31
32#include "BlobURL.h"
33#include "CachedResourceRequestInitiators.h"
34#include "ContentSecurityPolicy.h"
35#include "FetchBody.h"
36#include "FetchLoaderClient.h"
37#include "FetchRequest.h"
38#include "ResourceError.h"
39#include "ResourceRequest.h"
40#include "ScriptExecutionContext.h"
41#include "SecurityOrigin.h"
42#include "SharedBuffer.h"
43#include "TextResourceDecoder.h"
44#include "ThreadableBlobRegistry.h"
45
46namespace WebCore {
47
48FetchLoader::~FetchLoader()
49{
50 if (!m_urlForReading.isEmpty())
51 ThreadableBlobRegistry::unregisterBlobURL(m_urlForReading);
52}
53
54void FetchLoader::start(ScriptExecutionContext& context, const Blob& blob)
55{
56 return startLoadingBlobURL(context, blob.url());
57}
58
59void FetchLoader::startLoadingBlobURL(ScriptExecutionContext& context, const URL& blobURL)
60{
61 m_urlForReading = BlobURL::createPublicURL(context.securityOrigin());
62 if (m_urlForReading.isEmpty()) {
63 m_client.didFail({ errorDomainWebKitInternal, 0, URL(), "Could not create URL for Blob"_s });
64 return;
65 }
66
67 ThreadableBlobRegistry::registerBlobURL(context.securityOrigin(), m_urlForReading, blobURL);
68
69 ResourceRequest request(m_urlForReading);
70 request.setInitiatorIdentifier(context.resourceRequestIdentifier());
71 request.setHTTPMethod("GET");
72
73 ThreadableLoaderOptions options;
74 options.sendLoadCallbacks = SendCallbackPolicy::SendCallbacks;
75 options.dataBufferingPolicy = DataBufferingPolicy::DoNotBufferData;
76 options.preflightPolicy = PreflightPolicy::Consider;
77 options.credentials = FetchOptions::Credentials::Include;
78 options.mode = FetchOptions::Mode::SameOrigin;
79 options.contentSecurityPolicyEnforcement = ContentSecurityPolicyEnforcement::DoNotEnforce;
80
81 m_loader = ThreadableLoader::create(context, *this, WTFMove(request), options);
82 m_isStarted = m_loader;
83}
84
85void FetchLoader::start(ScriptExecutionContext& context, const FetchRequest& request)
86{
87 ResourceLoaderOptions resourceLoaderOptions = request.fetchOptions();
88 resourceLoaderOptions.preflightPolicy = PreflightPolicy::Consider;
89 ThreadableLoaderOptions options(resourceLoaderOptions,
90 context.shouldBypassMainWorldContentSecurityPolicy() ? ContentSecurityPolicyEnforcement::DoNotEnforce : ContentSecurityPolicyEnforcement::EnforceConnectSrcDirective,
91 String(cachedResourceRequestInitiators().fetch),
92 ResponseFilteringPolicy::Disable);
93 options.sendLoadCallbacks = SendCallbackPolicy::SendCallbacks;
94 options.dataBufferingPolicy = DataBufferingPolicy::DoNotBufferData;
95 options.sameOriginDataURLFlag = SameOriginDataURLFlag::Set;
96
97 ResourceRequest fetchRequest = request.resourceRequest();
98
99 ASSERT(context.contentSecurityPolicy());
100 auto& contentSecurityPolicy = *context.contentSecurityPolicy();
101
102 contentSecurityPolicy.upgradeInsecureRequestIfNeeded(fetchRequest, ContentSecurityPolicy::InsecureRequestType::Load);
103
104 if (!context.shouldBypassMainWorldContentSecurityPolicy() && !contentSecurityPolicy.allowConnectToSource(fetchRequest.url())) {
105 m_client.didFail({ errorDomainWebKitInternal, 0, fetchRequest.url(), "Not allowed by ContentSecurityPolicy"_s, ResourceError::Type::AccessControl });
106 return;
107 }
108
109 String referrer = request.internalRequestReferrer();
110 if (referrer == "no-referrer") {
111 options.referrerPolicy = ReferrerPolicy::NoReferrer;
112 referrer = String();
113 } else
114 referrer = (referrer == "client") ? context.url().strippedForUseAsReferrer() : URL(context.url(), referrer).strippedForUseAsReferrer();
115
116 m_loader = ThreadableLoader::create(context, *this, WTFMove(fetchRequest), options, WTFMove(referrer));
117 m_isStarted = m_loader;
118}
119
120FetchLoader::FetchLoader(FetchLoaderClient& client, FetchBodyConsumer* consumer)
121 : m_client(client)
122 , m_consumer(consumer)
123{
124}
125
126void FetchLoader::stop()
127{
128 if (m_consumer)
129 m_consumer->clean();
130 if (m_loader)
131 m_loader->cancel();
132}
133
134RefPtr<SharedBuffer> FetchLoader::startStreaming()
135{
136 ASSERT(m_consumer);
137 auto firstChunk = m_consumer->takeData();
138 m_consumer = nullptr;
139 return firstChunk;
140}
141
142void FetchLoader::didReceiveResponse(unsigned long, const ResourceResponse& response)
143{
144 m_client.didReceiveResponse(response);
145}
146
147void FetchLoader::didReceiveData(const char* value, int size)
148{
149 if (!m_consumer) {
150 m_client.didReceiveData(value, size);
151 return;
152 }
153 m_consumer->append(value, size);
154}
155
156void FetchLoader::didFinishLoading(unsigned long)
157{
158 m_client.didSucceed();
159}
160
161void FetchLoader::didFail(const ResourceError& error)
162{
163 m_client.didFail(error);
164}
165
166} // namespace WebCore
167