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"
10 #include "mozilla/ProfilerLabels.h"
14 nsIncrementalStreamLoader::nsIncrementalStreamLoader() = default;
17 nsIncrementalStreamLoader::Init(nsIIncrementalStreamLoaderObserver
* observer
) {
18 NS_ENSURE_ARG_POINTER(observer
);
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
)
33 nsIncrementalStreamLoader::GetNumBytesRead(uint32_t* aNumBytes
) {
34 *aNumBytes
= mBytesRead
;
38 /* readonly attribute nsIRequest request; */
40 nsIncrementalStreamLoader::GetRequest(nsIRequest
** aRequest
) {
41 *aRequest
= do_AddRef(mRequest
).take();
46 nsIncrementalStreamLoader::OnStartRequest(nsIRequest
* request
) {
47 nsCOMPtr
<nsIChannel
> chan(do_QueryInterface(request
));
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
;
62 if (!mData
.initCapacity(contentLength
)) {
63 return NS_ERROR_OUT_OF_MEMORY
;
71 nsIncrementalStreamLoader::OnStopRequest(nsIRequest
* request
,
73 AUTO_PROFILER_LABEL("nsIncrementalStreamLoader::OnStopRequest", NETWORK
);
76 // provide nsIIncrementalStreamLoader::request during call to
79 size_t length
= mData
.length();
80 uint8_t* elems
= mData
.extractOrCopyRawBuffer();
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
);
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;
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
,
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
;
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.
144 if (consumedCount
> reportCount
) {
146 return NS_ERROR_INVALID_ARG
;
149 if (consumedCount
== length
) {
150 free(elems
); // good case -- fully consumed data
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
);
165 nsIncrementalStreamLoader::OnDataAvailable(nsIRequest
* request
,
166 nsIInputStream
* inStr
,
167 uint64_t sourceOffset
,
170 // provide nsIIncrementalStreamLoader::request during call to
175 nsresult rv
= inStr
->ReadSegments(WriteSegmentFun
, this, count
, &countRead
);
177 NS_ENSURE_SUCCESS(rv
, rv
);
178 mBytesRead
+= countRead
;
182 void nsIncrementalStreamLoader::ReleaseData() { mData
.clearAndFree(); }
185 nsIncrementalStreamLoader::CheckListenerChain() { return NS_OK
; }
188 nsIncrementalStreamLoader::OnDataFinished(nsresult aStatus
) { return NS_OK
; }