| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "modules/fetch/FetchBlobDataConsumerHandle.h" | |
| 6 | |
| 7 #include "core/dom/ExecutionContext.h" | |
| 8 #include "core/fetch/FetchInitiatorTypeNames.h" | |
| 9 #include "core/loader/ThreadableLoaderClient.h" | |
| 10 #include "modules/fetch/CompositeDataConsumerHandle.h" | |
| 11 #include "modules/fetch/CrossThreadHolder.h" | |
| 12 #include "modules/fetch/DataConsumerHandleUtil.h" | |
| 13 #include "platform/blob/BlobRegistry.h" | |
| 14 #include "platform/blob/BlobURL.h" | |
| 15 #include "platform/network/ResourceRequest.h" | |
| 16 #include "wtf/PtrUtil.h" | |
| 17 #include <memory> | |
| 18 | |
| 19 namespace blink { | |
| 20 | |
| 21 using Result = FetchBlobDataConsumerHandle::Result; | |
| 22 | |
| 23 namespace { | |
| 24 | |
| 25 // Object graph: | |
| 26 // +-------------+ | |
| 27 // |ReaderContext| | |
| 28 // +-------------+ +-----------+ +---+ | | | |
| 29 // |LoaderContext|<-|CTH::Bridge|<->|CTH|<-| | | |
| 30 // +-------------+ +-----------+ +---+ +-------------+ | |
| 31 // | | |
| 32 // +--> ThreadableLoader | |
| 33 // | |
| 34 // When the loader thread is stopped, CrossThreadHolder::Bridge and | |
| 35 // LoaderContext (and thus ThreadableLoader) is destructed: | |
| 36 // +-------------+ | |
| 37 // |ReaderContext| | |
| 38 // +---+ | | | |
| 39 // |CTH|<-| | | |
| 40 // +---+ +-------------+ | |
| 41 // and the rest will be destructed when ReaderContext is destructed. | |
| 42 // | |
| 43 // When ReaderContext is destructed, CrossThreadHolder is destructed: | |
| 44 // | |
| 45 // +-------------+ +-----------+ | |
| 46 // |LoaderContext|<-|CTH::Bridge| | |
| 47 // +-------------+ +-----------+ | |
| 48 // | | |
| 49 // +--> ThreadableLoader | |
| 50 // and the rest will be shortly destructed when CrossThreadHolder::Bridge | |
| 51 // is garbage collected. | |
| 52 | |
| 53 // LoaderContext is created and destructed on the same thread | |
| 54 // (call this thread loader thread). | |
| 55 // All methods must be called on the loader thread. | |
| 56 class LoaderContext { | |
| 57 public: | |
| 58 virtual ~LoaderContext() { } | |
| 59 virtual void start(ExecutionContext*) = 0; | |
| 60 }; | |
| 61 | |
| 62 // All methods must be called on the loader thread. | |
| 63 class BlobLoaderContext final | |
| 64 : public LoaderContext | |
| 65 , public ThreadableLoaderClient { | |
| 66 public: | |
| 67 BlobLoaderContext(CompositeDataConsumerHandle::Updater* updater, PassRefPtr<
BlobDataHandle> blobDataHandle, FetchBlobDataConsumerHandle::LoaderFactory* load
erFactory) | |
| 68 : m_updater(updater) | |
| 69 , m_blobDataHandle(blobDataHandle) | |
| 70 , m_loaderFactory(loaderFactory) | |
| 71 , m_receivedResponse(false) { } | |
| 72 | |
| 73 ~BlobLoaderContext() override | |
| 74 { | |
| 75 if (m_loader && !m_receivedResponse) | |
| 76 m_updater->update(createUnexpectedErrorDataConsumerHandle()); | |
| 77 if (m_loader) { | |
| 78 m_loader->cancel(); | |
| 79 m_loader = nullptr; | |
| 80 } | |
| 81 if (!m_registeredBlobURL.isEmpty()) | |
| 82 BlobRegistry::revokePublicBlobURL(m_registeredBlobURL); | |
| 83 } | |
| 84 | |
| 85 void start(ExecutionContext* executionContext) override | |
| 86 { | |
| 87 ASSERT(executionContext->isContextThread()); | |
| 88 ASSERT(!m_loader); | |
| 89 | |
| 90 m_registeredBlobURL = BlobURL::createPublicURL(executionContext->getSecu
rityOrigin()); | |
| 91 if (m_registeredBlobURL.isEmpty()) { | |
| 92 m_updater->update(createUnexpectedErrorDataConsumerHandle()); | |
| 93 return; | |
| 94 } | |
| 95 BlobRegistry::registerPublicBlobURL(executionContext->getSecurityOrigin(
), m_registeredBlobURL, m_blobDataHandle); | |
| 96 | |
| 97 m_loader = createLoader(executionContext, this); | |
| 98 ASSERT(m_loader); | |
| 99 | |
| 100 ResourceRequest request(m_registeredBlobURL); | |
| 101 request.setRequestContext(WebURLRequest::RequestContextInternal); | |
| 102 request.setUseStreamOnResponse(true); | |
| 103 // We intentionally skip 'setExternalRequestStateFromRequestorAddressSpa
ce', as 'data:' can never be external. | |
| 104 m_loader->start(request); | |
| 105 } | |
| 106 | |
| 107 private: | |
| 108 ThreadableLoader* createLoader(ExecutionContext* executionContext, Threadabl
eLoaderClient* client) const | |
| 109 { | |
| 110 ThreadableLoaderOptions options; | |
| 111 options.preflightPolicy = ConsiderPreflight; | |
| 112 options.crossOriginRequestPolicy = DenyCrossOriginRequests; | |
| 113 options.contentSecurityPolicyEnforcement = DoNotEnforceContentSecurityPo
licy; | |
| 114 options.initiator = FetchInitiatorTypeNames::internal; | |
| 115 | |
| 116 ResourceLoaderOptions resourceLoaderOptions; | |
| 117 resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData; | |
| 118 | |
| 119 return m_loaderFactory->create(*executionContext, client, options, resou
rceLoaderOptions); | |
| 120 } | |
| 121 | |
| 122 // ThreadableLoaderClient | |
| 123 void didReceiveResponse(unsigned long, const ResourceResponse&, std::unique_
ptr<WebDataConsumerHandle> handle) override | |
| 124 { | |
| 125 ASSERT(!m_receivedResponse); | |
| 126 m_receivedResponse = true; | |
| 127 if (!handle) { | |
| 128 // Here we assume WebURLLoader must return the response body as | |
| 129 // |WebDataConsumerHandle| since we call | |
| 130 // request.setUseStreamOnResponse(). | |
| 131 m_updater->update(createUnexpectedErrorDataConsumerHandle()); | |
| 132 return; | |
| 133 } | |
| 134 m_updater->update(std::move(handle)); | |
| 135 } | |
| 136 | |
| 137 void didFinishLoading(unsigned long, double) override | |
| 138 { | |
| 139 m_loader = nullptr; | |
| 140 } | |
| 141 | |
| 142 void didFail(const ResourceError&) override | |
| 143 { | |
| 144 if (!m_receivedResponse) | |
| 145 m_updater->update(createUnexpectedErrorDataConsumerHandle()); | |
| 146 m_loader = nullptr; | |
| 147 } | |
| 148 | |
| 149 void didFailRedirectCheck() override | |
| 150 { | |
| 151 // We don't expect redirects for Blob loading. | |
| 152 ASSERT_NOT_REACHED(); | |
| 153 } | |
| 154 | |
| 155 Persistent<CompositeDataConsumerHandle::Updater> m_updater; | |
| 156 | |
| 157 RefPtr<BlobDataHandle> m_blobDataHandle; | |
| 158 Persistent<FetchBlobDataConsumerHandle::LoaderFactory> m_loaderFactory; | |
| 159 Persistent<ThreadableLoader> m_loader; | |
| 160 KURL m_registeredBlobURL; | |
| 161 | |
| 162 bool m_receivedResponse; | |
| 163 }; | |
| 164 | |
| 165 class DefaultLoaderFactory final : public FetchBlobDataConsumerHandle::LoaderFac
tory { | |
| 166 public: | |
| 167 ThreadableLoader* create( | |
| 168 ExecutionContext& executionContext, | |
| 169 ThreadableLoaderClient* client, | |
| 170 const ThreadableLoaderOptions& options, | |
| 171 const ResourceLoaderOptions& resourceLoaderOptions) override | |
| 172 { | |
| 173 return ThreadableLoader::create(executionContext, client, options, resou
rceLoaderOptions); | |
| 174 } | |
| 175 }; | |
| 176 | |
| 177 } // namespace | |
| 178 | |
| 179 // ReaderContext is referenced from FetchBlobDataConsumerHandle and | |
| 180 // ReaderContext::ReaderImpl. | |
| 181 // All functions/members must be called/accessed only on the reader thread, | |
| 182 // except for constructor, destructor, and obtainReader(). | |
| 183 class FetchBlobDataConsumerHandle::ReaderContext final : public ThreadSafeRefCou
nted<ReaderContext> { | |
| 184 public: | |
| 185 class ReaderImpl : public FetchDataConsumerHandle::Reader { | |
| 186 public: | |
| 187 ReaderImpl(Client* client, PassRefPtr<ReaderContext> readerContext, std:
:unique_ptr<WebDataConsumerHandle::Reader> reader) | |
| 188 : m_readerContext(readerContext) | |
| 189 , m_reader(std::move(reader)) | |
| 190 , m_notifier(client) { } | |
| 191 ~ReaderImpl() override { } | |
| 192 | |
| 193 Result read(void* data, size_t size, Flags flags, size_t* readSize) over
ride | |
| 194 { | |
| 195 if (m_readerContext->drained()) | |
| 196 return Done; | |
| 197 Result r = m_reader->read(data, size, flags, readSize); | |
| 198 if (!(size == 0 && (r == Ok || r == ShouldWait))) { | |
| 199 // We read non-empty data, so we cannot use the blob data | |
| 200 // handle which represents the whole data. | |
| 201 m_readerContext->clearBlobDataHandleForDrain(); | |
| 202 m_readerContext->ensureStartLoader(); | |
| 203 } | |
| 204 return r; | |
| 205 } | |
| 206 | |
| 207 Result beginRead(const void** buffer, Flags flags, size_t* available) ov
erride | |
| 208 { | |
| 209 if (m_readerContext->drained()) | |
| 210 return Done; | |
| 211 m_readerContext->ensureStartLoader(); | |
| 212 m_readerContext->clearBlobDataHandleForDrain(); | |
| 213 return m_reader->beginRead(buffer, flags, available); | |
| 214 } | |
| 215 | |
| 216 Result endRead(size_t readSize) override | |
| 217 { | |
| 218 return m_reader->endRead(readSize); | |
| 219 } | |
| 220 | |
| 221 PassRefPtr<BlobDataHandle> drainAsBlobDataHandle(BlobSizePolicy blobSize
Policy) override | |
| 222 { | |
| 223 if (!m_readerContext->m_blobDataHandleForDrain) | |
| 224 return nullptr; | |
| 225 if (blobSizePolicy == DisallowBlobWithInvalidSize && m_readerContext
->m_blobDataHandleForDrain->size() == UINT64_MAX) | |
| 226 return nullptr; | |
| 227 RefPtr<BlobDataHandle> blobDataHandle = m_readerContext->m_blobDataH
andleForDrain; | |
| 228 m_readerContext->setDrained(); | |
| 229 m_readerContext->clearBlobDataHandleForDrain(); | |
| 230 return blobDataHandle.release(); | |
| 231 } | |
| 232 | |
| 233 PassRefPtr<EncodedFormData> drainAsFormData() override | |
| 234 { | |
| 235 RefPtr<BlobDataHandle> handle = drainAsBlobDataHandle(AllowBlobWithI
nvalidSize); | |
| 236 if (!handle) | |
| 237 return nullptr; | |
| 238 RefPtr<EncodedFormData> formData = EncodedFormData::create(); | |
| 239 formData->appendBlob(handle->uuid(), handle); | |
| 240 return formData.release(); | |
| 241 } | |
| 242 | |
| 243 private: | |
| 244 RefPtr<ReaderContext> m_readerContext; | |
| 245 std::unique_ptr<WebDataConsumerHandle::Reader> m_reader; | |
| 246 NotifyOnReaderCreationHelper m_notifier; | |
| 247 }; | |
| 248 | |
| 249 ReaderContext(ExecutionContext* executionContext, PassRefPtr<BlobDataHandle>
blobDataHandle, FetchBlobDataConsumerHandle::LoaderFactory* loaderFactory) | |
| 250 : m_blobDataHandleForDrain(blobDataHandle) | |
| 251 , m_loaderStarted(false) | |
| 252 , m_drained(false) | |
| 253 { | |
| 254 CompositeDataConsumerHandle::Updater* updater = nullptr; | |
| 255 m_handle = CompositeDataConsumerHandle::create(createWaitingDataConsumer
Handle(), &updater); | |
| 256 m_loaderContextHolder = CrossThreadHolder<LoaderContext>::create(executi
onContext, wrapUnique(new BlobLoaderContext(updater, m_blobDataHandleForDrain, l
oaderFactory))); | |
| 257 } | |
| 258 | |
| 259 std::unique_ptr<FetchDataConsumerHandle::Reader> obtainReader(WebDataConsume
rHandle::Client* client) | |
| 260 { | |
| 261 return wrapUnique(new ReaderImpl(client, this, m_handle->obtainReader(cl
ient))); | |
| 262 } | |
| 263 | |
| 264 private: | |
| 265 void ensureStartLoader() | |
| 266 { | |
| 267 if (m_loaderStarted) | |
| 268 return; | |
| 269 m_loaderStarted = true; | |
| 270 m_loaderContextHolder->postTask(crossThreadBind(&LoaderContext::start)); | |
| 271 } | |
| 272 | |
| 273 void clearBlobDataHandleForDrain() | |
| 274 { | |
| 275 m_blobDataHandleForDrain.clear(); | |
| 276 } | |
| 277 | |
| 278 bool drained() const { return m_drained; } | |
| 279 void setDrained() { m_drained = true; } | |
| 280 | |
| 281 std::unique_ptr<WebDataConsumerHandle> m_handle; | |
| 282 RefPtr<BlobDataHandle> m_blobDataHandleForDrain; | |
| 283 std::unique_ptr<CrossThreadHolder<LoaderContext>> m_loaderContextHolder; | |
| 284 | |
| 285 bool m_loaderStarted; | |
| 286 bool m_drained; | |
| 287 }; | |
| 288 | |
| 289 FetchBlobDataConsumerHandle::FetchBlobDataConsumerHandle(ExecutionContext* execu
tionContext, PassRefPtr<BlobDataHandle> blobDataHandle, LoaderFactory* loaderFac
tory) | |
| 290 : m_readerContext(adoptRef(new ReaderContext(executionContext, std::move(blo
bDataHandle), loaderFactory))) | |
| 291 { | |
| 292 } | |
| 293 | |
| 294 FetchBlobDataConsumerHandle::~FetchBlobDataConsumerHandle() | |
| 295 { | |
| 296 } | |
| 297 | |
| 298 std::unique_ptr<FetchDataConsumerHandle> FetchBlobDataConsumerHandle::create(Exe
cutionContext* executionContext, PassRefPtr<BlobDataHandle> blobDataHandle, Load
erFactory* loaderFactory) | |
| 299 { | |
| 300 if (!blobDataHandle) | |
| 301 return createFetchDataConsumerHandleFromWebHandle(createDoneDataConsumer
Handle()); | |
| 302 | |
| 303 return wrapUnique(new FetchBlobDataConsumerHandle(executionContext, std::mov
e(blobDataHandle), loaderFactory)); | |
| 304 } | |
| 305 | |
| 306 std::unique_ptr<FetchDataConsumerHandle> FetchBlobDataConsumerHandle::create(Exe
cutionContext* executionContext, PassRefPtr<BlobDataHandle> blobDataHandle) | |
| 307 { | |
| 308 if (!blobDataHandle) | |
| 309 return createFetchDataConsumerHandleFromWebHandle(createDoneDataConsumer
Handle()); | |
| 310 | |
| 311 return wrapUnique(new FetchBlobDataConsumerHandle(executionContext, std::mov
e(blobDataHandle), new DefaultLoaderFactory)); | |
| 312 } | |
| 313 | |
| 314 std::unique_ptr<FetchDataConsumerHandle::Reader> FetchBlobDataConsumerHandle::ob
tainFetchDataReader(Client* client) | |
| 315 { | |
| 316 return m_readerContext->obtainReader(client); | |
| 317 } | |
| 318 | |
| 319 } // namespace blink | |
| OLD | NEW |