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