Bug 1878930 - s/RawBuffer/Span/: TexImage: GetRangeFromData. r=gfx-reviewers,lsalzman
[gecko.git] / netwerk / base / nsIncrementalStreamLoader.cpp
blobf4437b5269cfd38a7505e81cfaa11ca2f7031f5d
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsIncrementalStreamLoader.h"
7 #include "nsIInputStream.h"
8 #include "nsIChannel.h"
9 #include "nsError.h"
10 #include "mozilla/ProfilerLabels.h"
12 #include <limits>
14 nsIncrementalStreamLoader::nsIncrementalStreamLoader() = default;
16 NS_IMETHODIMP
17 nsIncrementalStreamLoader::Init(nsIIncrementalStreamLoaderObserver* observer) {
18 NS_ENSURE_ARG_POINTER(observer);
19 mObserver = observer;
20 return NS_OK;
23 nsresult nsIncrementalStreamLoader::Create(REFNSIID aIID, void** aResult) {
24 RefPtr<nsIncrementalStreamLoader> it = new nsIncrementalStreamLoader();
25 return it->QueryInterface(aIID, aResult);
28 NS_IMPL_ISUPPORTS(nsIncrementalStreamLoader, nsIIncrementalStreamLoader,
29 nsIRequestObserver, nsIStreamListener,
30 nsIThreadRetargetableStreamListener)
32 NS_IMETHODIMP
33 nsIncrementalStreamLoader::GetNumBytesRead(uint32_t* aNumBytes) {
34 *aNumBytes = mBytesRead;
35 return NS_OK;
38 /* readonly attribute nsIRequest request; */
39 NS_IMETHODIMP
40 nsIncrementalStreamLoader::GetRequest(nsIRequest** aRequest) {
41 *aRequest = do_AddRef(mRequest).take();
42 return NS_OK;
45 NS_IMETHODIMP
46 nsIncrementalStreamLoader::OnStartRequest(nsIRequest* request) {
47 nsCOMPtr<nsIChannel> chan(do_QueryInterface(request));
48 if (chan) {
49 int64_t contentLength = -1;
50 chan->GetContentLength(&contentLength);
51 if (contentLength >= 0) {
52 // On 64bit platforms size of uint64_t coincides with the size of size_t,
53 // so we want to compare with the minimum from size_t and int64_t.
54 if (static_cast<uint64_t>(contentLength) >
55 std::min(std::numeric_limits<size_t>::max(),
56 static_cast<size_t>(std::numeric_limits<int64_t>::max()))) {
57 // Too big to fit into size_t, so let's bail.
58 return NS_ERROR_OUT_OF_MEMORY;
61 // preallocate buffer
62 if (!mData.initCapacity(contentLength)) {
63 return NS_ERROR_OUT_OF_MEMORY;
67 return NS_OK;
70 NS_IMETHODIMP
71 nsIncrementalStreamLoader::OnStopRequest(nsIRequest* request,
72 nsresult aStatus) {
73 AUTO_PROFILER_LABEL("nsIncrementalStreamLoader::OnStopRequest", NETWORK);
75 if (mObserver) {
76 // provide nsIIncrementalStreamLoader::request during call to
77 // OnStreamComplete
78 mRequest = request;
79 size_t length = mData.length();
80 uint8_t* elems = mData.extractOrCopyRawBuffer();
81 nsresult rv =
82 mObserver->OnStreamComplete(this, mContext, aStatus, length, elems);
83 if (rv != NS_SUCCESS_ADOPTED_DATA) {
84 // The observer didn't take ownership of the extracted data buffer, so
85 // put it back into mData.
86 mData.replaceRawBuffer(elems, length);
88 // done.. cleanup
89 ReleaseData();
90 mRequest = nullptr;
91 mObserver = nullptr;
93 return NS_OK;
96 nsresult nsIncrementalStreamLoader::WriteSegmentFun(
97 nsIInputStream* inStr, void* closure, const char* fromSegment,
98 uint32_t toOffset, uint32_t count, uint32_t* writeCount) {
99 nsIncrementalStreamLoader* self = (nsIncrementalStreamLoader*)closure;
101 const uint8_t* data = reinterpret_cast<const uint8_t*>(fromSegment);
102 uint32_t consumedCount = 0;
103 nsresult rv;
104 if (self->mData.empty()) {
105 // Shortcut when observer wants to keep the listener's buffer empty.
106 rv = self->mObserver->OnIncrementalData(self, self->mContext, count, data,
107 &consumedCount);
109 if (rv != NS_OK) {
110 return rv;
113 if (consumedCount > count) {
114 return NS_ERROR_INVALID_ARG;
117 if (consumedCount < count) {
118 if (!self->mData.append(fromSegment + consumedCount,
119 count - consumedCount)) {
120 self->mData.clearAndFree();
121 return NS_ERROR_OUT_OF_MEMORY;
124 } else {
125 // We have some non-consumed data from previous OnIncrementalData call,
126 // appending new data and reporting combined data.
127 if (!self->mData.append(fromSegment, count)) {
128 self->mData.clearAndFree();
129 return NS_ERROR_OUT_OF_MEMORY;
131 size_t length = self->mData.length();
132 uint32_t reportCount = length > UINT32_MAX ? UINT32_MAX : (uint32_t)length;
133 uint8_t* elems = self->mData.extractOrCopyRawBuffer();
135 rv = self->mObserver->OnIncrementalData(self, self->mContext, reportCount,
136 elems, &consumedCount);
138 // We still own elems, freeing its memory when exiting scope.
139 if (rv != NS_OK) {
140 free(elems);
141 return rv;
144 if (consumedCount > reportCount) {
145 free(elems);
146 return NS_ERROR_INVALID_ARG;
149 if (consumedCount == length) {
150 free(elems); // good case -- fully consumed data
151 } else {
152 // Adopting elems back (at least its portion).
153 self->mData.replaceRawBuffer(elems, length);
154 if (consumedCount > 0) {
155 self->mData.erase(self->mData.begin() + consumedCount);
160 *writeCount = count;
161 return NS_OK;
164 NS_IMETHODIMP
165 nsIncrementalStreamLoader::OnDataAvailable(nsIRequest* request,
166 nsIInputStream* inStr,
167 uint64_t sourceOffset,
168 uint32_t count) {
169 if (mObserver) {
170 // provide nsIIncrementalStreamLoader::request during call to
171 // OnStreamComplete
172 mRequest = request;
174 uint32_t countRead;
175 nsresult rv = inStr->ReadSegments(WriteSegmentFun, this, count, &countRead);
176 mRequest = nullptr;
177 NS_ENSURE_SUCCESS(rv, rv);
178 mBytesRead += countRead;
179 return rv;
182 void nsIncrementalStreamLoader::ReleaseData() { mData.clearAndFree(); }
184 NS_IMETHODIMP
185 nsIncrementalStreamLoader::CheckListenerChain() { return NS_OK; }
187 NS_IMETHODIMP
188 nsIncrementalStreamLoader::OnDataFinished(nsresult aStatus) { return NS_OK; }