Line data Source code
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/. */
5 :
6 : #include "nsStreamLoader.h"
7 : #include "nsIInputStream.h"
8 : #include "nsIChannel.h"
9 : #include "nsError.h"
10 : #include "GeckoProfiler.h"
11 :
12 : #include <limits>
13 :
14 : namespace mozilla {
15 : namespace net {
16 :
17 9 : nsStreamLoader::nsStreamLoader()
18 9 : : mData()
19 : {
20 9 : }
21 :
22 9 : nsStreamLoader::~nsStreamLoader()
23 : {
24 9 : }
25 :
26 : NS_IMETHODIMP
27 9 : nsStreamLoader::Init(nsIStreamLoaderObserver* aStreamObserver,
28 : nsIRequestObserver* aRequestObserver)
29 : {
30 9 : NS_ENSURE_ARG_POINTER(aStreamObserver);
31 9 : mObserver = aStreamObserver;
32 9 : mRequestObserver = aRequestObserver;
33 9 : return NS_OK;
34 : }
35 :
36 : nsresult
37 9 : nsStreamLoader::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
38 : {
39 9 : if (aOuter) return NS_ERROR_NO_AGGREGATION;
40 :
41 9 : nsStreamLoader* it = new nsStreamLoader();
42 9 : if (it == nullptr)
43 0 : return NS_ERROR_OUT_OF_MEMORY;
44 9 : NS_ADDREF(it);
45 9 : nsresult rv = it->QueryInterface(aIID, aResult);
46 9 : NS_RELEASE(it);
47 9 : return rv;
48 : }
49 :
50 201 : NS_IMPL_ISUPPORTS(nsStreamLoader, nsIStreamLoader,
51 : nsIRequestObserver, nsIStreamListener,
52 : nsIThreadRetargetableStreamListener)
53 :
54 : NS_IMETHODIMP
55 0 : nsStreamLoader::GetNumBytesRead(uint32_t* aNumBytes)
56 : {
57 0 : *aNumBytes = mData.length();
58 0 : return NS_OK;
59 : }
60 :
61 : NS_IMETHODIMP
62 8 : nsStreamLoader::GetRequest(nsIRequest **aRequest)
63 : {
64 8 : NS_IF_ADDREF(*aRequest = mRequest);
65 8 : return NS_OK;
66 : }
67 :
68 : NS_IMETHODIMP
69 9 : nsStreamLoader::OnStartRequest(nsIRequest* request, nsISupports *ctxt)
70 : {
71 18 : nsCOMPtr<nsIChannel> chan( do_QueryInterface(request) );
72 9 : if (chan) {
73 8 : int64_t contentLength = -1;
74 8 : chan->GetContentLength(&contentLength);
75 8 : if (contentLength >= 0) {
76 8 : if (uint64_t(contentLength) > std::numeric_limits<size_t>::max()) {
77 : // Too big to fit into size_t, so let's bail.
78 0 : return NS_ERROR_OUT_OF_MEMORY;
79 : }
80 : // preallocate buffer
81 8 : if (!mData.initCapacity(contentLength)) {
82 0 : return NS_ERROR_OUT_OF_MEMORY;
83 : }
84 : }
85 : }
86 9 : mContext = ctxt;
87 9 : if (mRequestObserver) {
88 0 : mRequestObserver->OnStartRequest(request, ctxt);
89 : }
90 9 : return NS_OK;
91 : }
92 :
93 : NS_IMETHODIMP
94 9 : nsStreamLoader::OnStopRequest(nsIRequest* request, nsISupports *ctxt,
95 : nsresult aStatus)
96 : {
97 18 : AUTO_PROFILER_LABEL("nsStreamLoader::OnStopRequest", NETWORK);
98 :
99 9 : if (mObserver) {
100 : // provide nsIStreamLoader::request during call to OnStreamComplete
101 9 : mRequest = request;
102 9 : size_t length = mData.length();
103 9 : uint8_t* elems = mData.extractOrCopyRawBuffer();
104 18 : nsresult rv = mObserver->OnStreamComplete(this, mContext, aStatus,
105 18 : length, elems);
106 9 : if (rv != NS_SUCCESS_ADOPTED_DATA) {
107 : // The observer didn't take ownership of the extracted data buffer, so
108 : // put it back into mData.
109 8 : mData.replaceRawBuffer(elems, length);
110 : }
111 : // done.. cleanup
112 9 : ReleaseData();
113 9 : mRequest = nullptr;
114 9 : mObserver = nullptr;
115 9 : mContext = nullptr;
116 : }
117 :
118 9 : if (mRequestObserver) {
119 0 : mRequestObserver->OnStopRequest(request, ctxt, aStatus);
120 0 : mRequestObserver = nullptr;
121 : }
122 :
123 18 : return NS_OK;
124 : }
125 :
126 : nsresult
127 10 : nsStreamLoader::WriteSegmentFun(nsIInputStream *inStr,
128 : void *closure,
129 : const char *fromSegment,
130 : uint32_t toOffset,
131 : uint32_t count,
132 : uint32_t *writeCount)
133 : {
134 10 : nsStreamLoader *self = (nsStreamLoader *) closure;
135 :
136 10 : if (!self->mData.append(fromSegment, count)) {
137 0 : self->mData.clearAndFree();
138 0 : return NS_ERROR_OUT_OF_MEMORY;
139 : }
140 :
141 10 : *writeCount = count;
142 :
143 10 : return NS_OK;
144 : }
145 :
146 : NS_IMETHODIMP
147 9 : nsStreamLoader::OnDataAvailable(nsIRequest* request, nsISupports *ctxt,
148 : nsIInputStream *inStr,
149 : uint64_t sourceOffset, uint32_t count)
150 : {
151 : uint32_t countRead;
152 9 : return inStr->ReadSegments(WriteSegmentFun, this, count, &countRead);
153 : }
154 :
155 : void
156 9 : nsStreamLoader::ReleaseData()
157 : {
158 9 : mData.clearAndFree();
159 9 : }
160 :
161 : NS_IMETHODIMP
162 1 : nsStreamLoader::CheckListenerChain()
163 : {
164 1 : return NS_OK;
165 : }
166 :
167 : } // namespace net
168 9 : } // namespace mozilla
|