| OLD | NEW | 
|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "config.h" | 5 #include "config.h" | 
| 6 #include "modules/fetch/BodyStreamBuffer.h" | 6 #include "modules/fetch/BodyStreamBuffer.h" | 
| 7 | 7 | 
| 8 #include "core/dom/DOMArrayBuffer.h" | 8 #include "core/dom/DOMArrayBuffer.h" | 
|  | 9 #include "core/dom/DOMTypedArray.h" | 
| 9 #include "core/dom/ExceptionCode.h" | 10 #include "core/dom/ExceptionCode.h" | 
|  | 11 #include "modules/fetch/DataConsumerHandleUtil.h" | 
|  | 12 #include "platform/blob/BlobData.h" | 
| 10 | 13 | 
| 11 namespace blink { | 14 namespace blink { | 
| 12 | 15 | 
| 13 BodyStreamBuffer* BodyStreamBuffer::createEmpty() | 16 namespace { | 
| 14 { | 17 | 
| 15     return BodyStreamBuffer::create(createFetchDataConsumerHandleFromWebHandle(c
     reateDoneDataConsumerHandle())); | 18 class LoaderHolder final : public GarbageCollectedFinalized<LoaderHolder>, publi
     c FetchDataLoader::Client { | 
| 16 } | 19     WTF_MAKE_NONCOPYABLE(LoaderHolder); | 
| 17 | 20     USING_GARBAGE_COLLECTED_MIXIN(LoaderHolder); | 
| 18 FetchDataConsumerHandle* BodyStreamBuffer::handle() const |  | 
| 19 { |  | 
| 20     ASSERT(!m_fetchDataLoader); |  | 
| 21     ASSERT(!m_drainingStreamNotificationClient); |  | 
| 22     return m_handle.get(); |  | 
| 23 } |  | 
| 24 |  | 
| 25 PassOwnPtr<FetchDataConsumerHandle> BodyStreamBuffer::releaseHandle() |  | 
| 26 { |  | 
| 27     ASSERT(!m_fetchDataLoader); |  | 
| 28     ASSERT(!m_drainingStreamNotificationClient); |  | 
| 29     return m_handle.release(); |  | 
| 30 } |  | 
| 31 |  | 
| 32 class ClientWithFinishNotification final : public GarbageCollectedFinalized<Clie
     ntWithFinishNotification>, public FetchDataLoader::Client { |  | 
| 33     USING_GARBAGE_COLLECTED_MIXIN(ClientWithFinishNotification); |  | 
| 34 public: | 21 public: | 
| 35     ClientWithFinishNotification(BodyStreamBuffer* buffer, FetchDataLoader::Clie
     nt* client) | 22     LoaderHolder(BodyStreamBuffer* buffer, FetchDataLoader* loader, FetchDataLoa
     der::Client* client) : m_buffer(buffer), m_loader(loader), m_client(client) {} | 
| 36         : m_buffer(buffer) | 23 | 
| 37         , m_client(client) | 24     void start(PassOwnPtr<FetchDataConsumerHandle> handle) { m_loader->start(han
     dle.get(), this); } | 
| 38     { | 25 | 
| 39     } | 26     void didFetchDataLoadedBlobHandle(PassRefPtr<BlobDataHandle> blobDataHandle)
      override | 
| 40 | 27     { | 
| 41     DEFINE_INLINE_VIRTUAL_TRACE() | 28         m_buffer->endLoading(this, createFetchDataConsumerHandleFromWebHandle(cr
     eateDoneDataConsumerHandle())); | 
|  | 29         m_client->didFetchDataLoadedBlobHandle(blobDataHandle); | 
|  | 30     } | 
|  | 31 | 
|  | 32     void didFetchDataLoadedArrayBuffer(PassRefPtr<DOMArrayBuffer> arrayBuffer) o
     verride | 
|  | 33     { | 
|  | 34         m_buffer->endLoading(this, createFetchDataConsumerHandleFromWebHandle(cr
     eateDoneDataConsumerHandle())); | 
|  | 35         m_client->didFetchDataLoadedArrayBuffer(arrayBuffer); | 
|  | 36     } | 
|  | 37 | 
|  | 38     void didFetchDataLoadedString(const String& string) override | 
|  | 39     { | 
|  | 40         m_buffer->endLoading(this, createFetchDataConsumerHandleFromWebHandle(cr
     eateDoneDataConsumerHandle())); | 
|  | 41         m_client->didFetchDataLoadedString(string); | 
|  | 42     } | 
|  | 43 | 
|  | 44     void didFetchDataLoadedStream() override | 
|  | 45     { | 
|  | 46         m_buffer->endLoading(this, createFetchDataConsumerHandleFromWebHandle(cr
     eateDoneDataConsumerHandle())); | 
|  | 47         m_client->didFetchDataLoadedStream(); | 
|  | 48     } | 
|  | 49 | 
|  | 50     void didFetchDataLoadFailed() override | 
|  | 51     { | 
|  | 52         m_buffer->endLoading(this, createFetchDataConsumerHandleFromWebHandle(cr
     eateUnexpectedErrorDataConsumerHandle())); | 
|  | 53         m_client->didFetchDataLoadFailed(); | 
|  | 54     } | 
|  | 55 | 
|  | 56     DEFINE_INLINE_TRACE() | 
| 42     { | 57     { | 
| 43         visitor->trace(m_buffer); | 58         visitor->trace(m_buffer); | 
|  | 59         visitor->trace(m_loader); | 
| 44         visitor->trace(m_client); | 60         visitor->trace(m_client); | 
| 45         FetchDataLoader::Client::trace(visitor); | 61         FetchDataLoader::Client::trace(visitor); | 
| 46     } | 62     } | 
| 47 | 63 | 
| 48 private: | 64 private: | 
| 49     void didFetchDataLoadedBlobHandle(PassRefPtr<BlobDataHandle> blobDataHandle)
      override |  | 
| 50     { |  | 
| 51         if (m_client) |  | 
| 52             m_client->didFetchDataLoadedBlobHandle(blobDataHandle); |  | 
| 53         m_buffer->didFetchDataLoadFinished(); |  | 
| 54     } |  | 
| 55     void didFetchDataLoadedArrayBuffer(PassRefPtr<DOMArrayBuffer> arrayBuffer) o
     verride |  | 
| 56     { |  | 
| 57         if (m_client) |  | 
| 58             m_client->didFetchDataLoadedArrayBuffer(arrayBuffer); |  | 
| 59         m_buffer->didFetchDataLoadFinished(); |  | 
| 60     } |  | 
| 61     void didFetchDataLoadedString(const String& str) override |  | 
| 62     { |  | 
| 63         if (m_client) |  | 
| 64             m_client->didFetchDataLoadedString(str); |  | 
| 65         m_buffer->didFetchDataLoadFinished(); |  | 
| 66     } |  | 
| 67     void didFetchDataLoadedStream() override |  | 
| 68     { |  | 
| 69         if (m_client) |  | 
| 70             m_client->didFetchDataLoadedStream(); |  | 
| 71         m_buffer->didFetchDataLoadFinished(); |  | 
| 72     } |  | 
| 73     void didFetchDataLoadFailed() override |  | 
| 74     { |  | 
| 75         if (m_client) |  | 
| 76             m_client->didFetchDataLoadFailed(); |  | 
| 77         m_buffer->didFetchDataLoadFinished(); |  | 
| 78     } |  | 
| 79 |  | 
| 80     Member<BodyStreamBuffer> m_buffer; | 65     Member<BodyStreamBuffer> m_buffer; | 
|  | 66     Member<FetchDataLoader> m_loader; | 
| 81     Member<FetchDataLoader::Client> m_client; | 67     Member<FetchDataLoader::Client> m_client; | 
| 82 }; | 68 }; | 
| 83 | 69 | 
| 84 void BodyStreamBuffer::setDrainingStreamNotificationClient(DrainingStreamNotific
     ationClient* client) | 70 } // namespace | 
| 85 { | 71 | 
| 86     ASSERT(!m_fetchDataLoader); | 72 BodyStreamBuffer::BodyStreamBuffer(PassOwnPtr<FetchDataConsumerHandle> handle) | 
| 87     ASSERT(!m_drainingStreamNotificationClient); | 73     : m_handle(handle) | 
| 88     m_drainingStreamNotificationClient = client; | 74     , m_reader(m_handle ? m_handle->obtainReader(this) : nullptr) | 
| 89 } | 75     , m_stream(new ReadableByteStream(this, new ReadableByteStream::StrictStrate
     gy)) | 
| 90 | 76     , m_lockLevel(0) | 
| 91 void BodyStreamBuffer::startLoading(FetchDataLoader* fetchDataLoader, FetchDataL
     oader::Client* client) | 77     , m_hasBody(m_handle) | 
| 92 { | 78     , m_streamNeedsMore(false) | 
| 93     ASSERT(!m_fetchDataLoader); | 79 { | 
| 94     m_fetchDataLoader = fetchDataLoader; | 80     if (m_hasBody) { | 
| 95     m_fetchDataLoader->start(m_handle.get(), new ClientWithFinishNotification(th
     is, client)); | 81         m_stream->didSourceStart(); | 
| 96 } | 82     } else { | 
| 97 | 83         // a null body corresponds to an empty stream. | 
| 98 void BodyStreamBuffer::doDrainingStreamNotification() | 84         close(); | 
| 99 { | 85     } | 
| 100     ASSERT(!m_fetchDataLoader); | 86 } | 
| 101     DrainingStreamNotificationClient* client = m_drainingStreamNotificationClien
     t; | 87 | 
| 102     m_drainingStreamNotificationClient.clear(); | 88 PassOwnPtr<FetchDataConsumerHandle> BodyStreamBuffer::lock(ExecutionContext* exe
     cutionContext) | 
| 103     if (client) | 89 { | 
| 104         client->didFetchDataLoadFinishedFromDrainingStream(); | 90     ASSERT(!isLocked()); | 
| 105 } | 91     ++m_lockLevel; | 
| 106 | 92     m_reader = nullptr; | 
| 107 void BodyStreamBuffer::clearDrainingStreamNotification() | 93     OwnPtr<FetchDataConsumerHandle> handle = m_handle.release(); | 
| 108 { | 94     if (ReadableStream::Closed == m_stream->stateInternal() || !m_hasBody) | 
| 109     ASSERT(!m_fetchDataLoader); | 95         return createFetchDataConsumerHandleFromWebHandle(createDoneDataConsumer
     Handle()); | 
| 110     m_drainingStreamNotificationClient.clear(); | 96     if (ReadableStream::Errored == m_stream->stateInternal()) | 
| 111 } | 97         return createFetchDataConsumerHandleFromWebHandle(createUnexpectedErrorD
     ataConsumerHandle()); | 
| 112 | 98 | 
| 113 void BodyStreamBuffer::didFetchDataLoadFinished() | 99     TrackExceptionState exceptionState; | 
| 114 { | 100     m_streamReader = m_stream->getBytesReader(executionContext, exceptionState); | 
| 115     ASSERT(m_fetchDataLoader); | 101     return handle.release(); | 
| 116     m_fetchDataLoader.clear(); | 102 } | 
| 117     doDrainingStreamNotification(); | 103 | 
| 118 } | 104 void BodyStreamBuffer::unlock(PassOwnPtr<FetchDataConsumerHandle> handle) | 
| 119 | 105 { | 
| 120 DrainingBodyStreamBuffer::~DrainingBodyStreamBuffer() | 106     ASSERT(m_lockLevel > 0); | 
| 121 { | 107     if (m_streamReader) { | 
| 122     if (m_buffer) | 108         m_streamReader->releaseLock(); | 
| 123         m_buffer->doDrainingStreamNotification(); | 109         m_streamReader = nullptr; | 
| 124 } | 110     } | 
| 125 | 111     --m_lockLevel; | 
| 126 void DrainingBodyStreamBuffer::startLoading(FetchDataLoader* fetchDataLoader, Fe
     tchDataLoader::Client* client) | 112     if (!m_hasBody) | 
| 127 { | 113         return; | 
| 128     if (!m_buffer) | 114     ASSERT(handle); | 
| 129         return; | 115     if (ReadableStream::Closed == m_stream->stateInternal() || ReadableStream::E
     rrored == m_stream->stateInternal()) { | 
| 130 | 116         m_handle = handle; | 
| 131     m_buffer->startLoading(fetchDataLoader, client); | 117         return; | 
| 132     m_buffer.clear(); | 118     } | 
| 133 } | 119     ASSERT(!m_handle); | 
| 134 | 120     m_handle = handle; | 
| 135 BodyStreamBuffer* DrainingBodyStreamBuffer::leakBuffer() | 121     m_reader = m_handle->obtainReader(this); | 
| 136 { | 122     // We need to update the stream state synchronously. | 
| 137     if (!m_buffer) | 123     didGetReadable(); | 
| 138         return nullptr; | 124 } | 
| 139 | 125 | 
| 140     m_buffer->clearDrainingStreamNotification(); | 126 void BodyStreamBuffer::startLoading(ExecutionContext* executionContext, FetchDat
     aLoader* loader, FetchDataLoader::Client* client) | 
| 141     BodyStreamBuffer* buffer = m_buffer; | 127 { | 
| 142     m_buffer.clear(); | 128     OwnPtr<FetchDataConsumerHandle> handle = lock(executionContext); | 
| 143     return buffer; | 129     auto holder = new LoaderHolder(this, loader, client); | 
| 144 } | 130     m_loaders.add(holder); | 
| 145 | 131     holder->start(handle.release()); | 
| 146 PassRefPtr<BlobDataHandle> DrainingBodyStreamBuffer::drainAsBlobDataHandle(Fetch
     DataConsumerHandle::Reader::BlobSizePolicy blobSizePolicy) | 132 } | 
| 147 { | 133 | 
| 148     if (!m_buffer) | 134 void BodyStreamBuffer::pullSource() | 
| 149         return nullptr; | 135 { | 
| 150 | 136     ASSERT(!m_streamNeedsMore); | 
| 151     RefPtr<BlobDataHandle> blobDataHandle = m_buffer->m_handle->obtainReader(nul
     lptr)->drainAsBlobDataHandle(blobSizePolicy); | 137     m_streamNeedsMore = true; | 
| 152     if (!blobDataHandle) | 138     processData(); | 
| 153         return nullptr; | 139 } | 
| 154     m_buffer->doDrainingStreamNotification(); | 140 | 
| 155     m_buffer.clear(); | 141 ScriptPromise BodyStreamBuffer::cancelSource(ScriptState* scriptState, ScriptVal
     ue) | 
| 156     return blobDataHandle.release(); | 142 { | 
| 157 } | 143     close(); | 
| 158 | 144     return ScriptPromise::cast(scriptState, v8::Undefined(scriptState->isolate()
     )); | 
| 159 DrainingBodyStreamBuffer::DrainingBodyStreamBuffer(BodyStreamBuffer* buffer, Bod
     yStreamBuffer::DrainingStreamNotificationClient* client) | 145 } | 
| 160     : m_buffer(buffer) | 146 | 
| 161 { | 147 void BodyStreamBuffer::didGetReadable() | 
| 162     ASSERT(client); | 148 { | 
| 163     m_buffer->setDrainingStreamNotificationClient(client); | 149     if (!m_reader) | 
|  | 150         return; | 
|  | 151 | 
|  | 152     if (!m_streamNeedsMore) { | 
|  | 153         // Perform zero-length read to call close()/error() early. | 
|  | 154         size_t readSize; | 
|  | 155         WebDataConsumerHandle::Result result = m_reader->read(nullptr, 0, WebDat
     aConsumerHandle::FlagNone, &readSize); | 
|  | 156         switch (result) { | 
|  | 157         case WebDataConsumerHandle::Ok: | 
|  | 158         case WebDataConsumerHandle::ShouldWait: | 
|  | 159             return; | 
|  | 160         case WebDataConsumerHandle::Done: | 
|  | 161             close(); | 
|  | 162             return; | 
|  | 163         case WebDataConsumerHandle::Busy: | 
|  | 164         case WebDataConsumerHandle::ResourceExhausted: | 
|  | 165         case WebDataConsumerHandle::UnexpectedError: | 
|  | 166             error(); | 
|  | 167             return; | 
|  | 168         } | 
|  | 169         return; | 
|  | 170     } | 
|  | 171     processData(); | 
|  | 172 } | 
|  | 173 | 
|  | 174 void BodyStreamBuffer::endLoading(FetchDataLoader::Client* client, PassOwnPtr<Fe
     tchDataConsumerHandle> handle) | 
|  | 175 { | 
|  | 176     ASSERT(m_loaders.contains(client)); | 
|  | 177     m_loaders.remove(client); | 
|  | 178     unlock(handle); | 
|  | 179 } | 
|  | 180 | 
|  | 181 void BodyStreamBuffer::processData() | 
|  | 182 { | 
|  | 183     ASSERT(m_reader); | 
|  | 184     while (m_streamNeedsMore) { | 
|  | 185         const void* buffer; | 
|  | 186         size_t available; | 
|  | 187         WebDataConsumerHandle::Result result = m_reader->beginRead(&buffer, WebD
     ataConsumerHandle::FlagNone, &available); | 
|  | 188         switch (result) { | 
|  | 189         case WebDataConsumerHandle::Ok: | 
|  | 190             m_streamNeedsMore = m_stream->enqueue(DOMUint8Array::create(static_c
     ast<const unsigned char*>(buffer), available)); | 
|  | 191             m_reader->endRead(available); | 
|  | 192             break; | 
|  | 193 | 
|  | 194         case WebDataConsumerHandle::Done: | 
|  | 195             close(); | 
|  | 196             return; | 
|  | 197 | 
|  | 198         case WebDataConsumerHandle::ShouldWait: | 
|  | 199             return; | 
|  | 200 | 
|  | 201         case WebDataConsumerHandle::Busy: | 
|  | 202         case WebDataConsumerHandle::ResourceExhausted: | 
|  | 203         case WebDataConsumerHandle::UnexpectedError: | 
|  | 204             error(); | 
|  | 205             return; | 
|  | 206         } | 
|  | 207     } | 
|  | 208 } | 
|  | 209 | 
|  | 210 void BodyStreamBuffer::close() | 
|  | 211 { | 
|  | 212     m_reader = nullptr; | 
|  | 213     m_stream->close(); | 
|  | 214 } | 
|  | 215 | 
|  | 216 void BodyStreamBuffer::error() | 
|  | 217 { | 
|  | 218     m_reader = nullptr; | 
|  | 219     m_stream->error(DOMException::create(NetworkError, "network error")); | 
| 164 } | 220 } | 
| 165 | 221 | 
| 166 } // namespace blink | 222 } // namespace blink | 
| OLD | NEW | 
|---|