|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 #include "TestCommon.h" |
|
6 #include "nsIComponentRegistrar.h" |
|
7 #include "nsIStreamTransportService.h" |
|
8 #include "nsIAsyncInputStream.h" |
|
9 #include "nsIProgressEventSink.h" |
|
10 #include "nsIInterfaceRequestor.h" |
|
11 #include "nsIInterfaceRequestorUtils.h" |
|
12 #include "nsIRequest.h" |
|
13 #include "nsIServiceManager.h" |
|
14 #include "nsIComponentManager.h" |
|
15 #include "nsCOMPtr.h" |
|
16 #include "nsMemory.h" |
|
17 #include "nsStringAPI.h" |
|
18 #include "nsIFileStreams.h" |
|
19 #include "nsIStreamListener.h" |
|
20 #include "nsIFile.h" |
|
21 #include "nsNetUtil.h" |
|
22 #include "nsAutoLock.h" |
|
23 #include "prlog.h" |
|
24 #include "prenv.h" |
|
25 |
|
26 //////////////////////////////////////////////////////////////////////////////// |
|
27 |
|
28 #if defined(PR_LOGGING) |
|
29 // |
|
30 // set NSPR_LOG_MODULES=Test:5 |
|
31 // |
|
32 static PRLogModuleInfo *gTestLog = nullptr; |
|
33 #endif |
|
34 #define LOG(args) PR_LOG(gTestLog, PR_LOG_DEBUG, args) |
|
35 |
|
36 //////////////////////////////////////////////////////////////////////////////// |
|
37 |
|
38 static NS_DEFINE_CID(kStreamTransportServiceCID, NS_STREAMTRANSPORTSERVICE_CID); |
|
39 |
|
40 //////////////////////////////////////////////////////////////////////////////// |
|
41 |
|
42 #define CHUNK_SIZE 500 |
|
43 |
|
44 class MyCopier : public nsIInputStreamCallback |
|
45 , public nsIOutputStreamCallback |
|
46 { |
|
47 public: |
|
48 NS_DECL_THREADSAFE_ISUPPORTS |
|
49 |
|
50 MyCopier() |
|
51 : mLock(nullptr) |
|
52 , mInputCondition(NS_OK) |
|
53 { |
|
54 } |
|
55 |
|
56 virtual ~MyCopier() |
|
57 { |
|
58 if (mLock) |
|
59 nsAutoLock::DestroyLock(mLock); |
|
60 if (mInput) |
|
61 mInput->Close(); |
|
62 if (mOutput) |
|
63 mOutput->Close(); |
|
64 } |
|
65 |
|
66 // called on any thread |
|
67 NS_IMETHOD OnInputStreamReady(nsIAsyncInputStream *inStr) |
|
68 { |
|
69 LOG(("OnInputStreamReady\n")); |
|
70 nsAutoLock lock(mLock); |
|
71 NS_ASSERTION(inStr == mInput, "unexpected stream"); |
|
72 Process_Locked(); |
|
73 return NS_OK; |
|
74 } |
|
75 |
|
76 // called on any thread |
|
77 NS_IMETHOD OnOutputStreamReady(nsIAsyncOutputStream *outStr) |
|
78 { |
|
79 LOG(("OnOutputStreamReady\n")); |
|
80 nsAutoLock lock(mLock); |
|
81 NS_ASSERTION(outStr == mOutput, "unexpected stream"); |
|
82 Process_Locked(); |
|
83 return NS_OK; |
|
84 } |
|
85 |
|
86 void Close_Locked() |
|
87 { |
|
88 LOG(("Close_Locked\n")); |
|
89 |
|
90 mOutput->Close(); |
|
91 mOutput = 0; |
|
92 mInput->Close(); |
|
93 mInput = 0; |
|
94 |
|
95 // post done copying event |
|
96 QuitPumpingEvents(); |
|
97 } |
|
98 |
|
99 void Process_Locked() |
|
100 { |
|
101 while (1) { |
|
102 mInputCondition = NS_OK; // reset |
|
103 |
|
104 uint32_t n; |
|
105 nsresult rv = mOutput->WriteSegments(FillOutputBuffer, this, CHUNK_SIZE, &n); |
|
106 if (NS_FAILED(rv) || (n == 0)) { |
|
107 if (rv == NS_BASE_STREAM_WOULD_BLOCK) |
|
108 mOutput->AsyncWait(this, 0, 0, nullptr); |
|
109 else if (mInputCondition == NS_BASE_STREAM_WOULD_BLOCK) |
|
110 mInput->AsyncWait(this, 0, 0, nullptr); |
|
111 else |
|
112 Close_Locked(); |
|
113 break; |
|
114 } |
|
115 } |
|
116 } |
|
117 |
|
118 nsresult AsyncCopy(nsITransport *srcTrans, nsITransport *destTrans) |
|
119 { |
|
120 mLock = nsAutoLock::NewLock("MyCopier::mLock"); |
|
121 if (!mLock) |
|
122 return NS_ERROR_OUT_OF_MEMORY; |
|
123 |
|
124 nsresult rv; |
|
125 |
|
126 nsCOMPtr<nsIInputStream> inStr; |
|
127 rv = srcTrans->OpenInputStream(0, 0, 0, getter_AddRefs(inStr)); |
|
128 if (NS_FAILED(rv)) return rv; |
|
129 |
|
130 nsCOMPtr<nsIOutputStream> outStr; |
|
131 rv = destTrans->OpenOutputStream(0, 0, 0, getter_AddRefs(outStr)); |
|
132 if (NS_FAILED(rv)) return rv; |
|
133 |
|
134 mInput = do_QueryInterface(inStr); |
|
135 mOutput = do_QueryInterface(outStr); |
|
136 |
|
137 return mInput->AsyncWait(this, 0, 0, nullptr); |
|
138 } |
|
139 |
|
140 static NS_METHOD FillOutputBuffer(nsIOutputStream *outStr, |
|
141 void *closure, |
|
142 char *buffer, |
|
143 uint32_t offset, |
|
144 uint32_t count, |
|
145 uint32_t *countRead) |
|
146 { |
|
147 MyCopier *self = (MyCopier *) closure; |
|
148 |
|
149 nsresult rv = self->mInput->Read(buffer, count, countRead); |
|
150 if (NS_FAILED(rv)) |
|
151 self->mInputCondition = rv; |
|
152 else if (*countRead == 0) |
|
153 self->mInputCondition = NS_BASE_STREAM_CLOSED; |
|
154 |
|
155 return self->mInputCondition; |
|
156 } |
|
157 |
|
158 protected: |
|
159 PRLock *mLock; |
|
160 nsCOMPtr<nsIAsyncInputStream> mInput; |
|
161 nsCOMPtr<nsIAsyncOutputStream> mOutput; |
|
162 nsresult mInputCondition; |
|
163 }; |
|
164 |
|
165 NS_IMPL_ISUPPORTS(MyCopier, |
|
166 nsIInputStreamCallback, |
|
167 nsIOutputStreamCallback) |
|
168 |
|
169 //////////////////////////////////////////////////////////////////////////////// |
|
170 |
|
171 /** |
|
172 * asynchronously copy file. |
|
173 */ |
|
174 static nsresult |
|
175 RunTest(nsIFile *srcFile, nsIFile *destFile) |
|
176 { |
|
177 nsresult rv; |
|
178 |
|
179 LOG(("RunTest\n")); |
|
180 |
|
181 nsCOMPtr<nsIStreamTransportService> sts = |
|
182 do_GetService(kStreamTransportServiceCID, &rv); |
|
183 if (NS_FAILED(rv)) return rv; |
|
184 |
|
185 nsCOMPtr<nsIInputStream> srcStr; |
|
186 rv = NS_NewLocalFileInputStream(getter_AddRefs(srcStr), srcFile); |
|
187 if (NS_FAILED(rv)) return rv; |
|
188 |
|
189 nsCOMPtr<nsIOutputStream> destStr; |
|
190 rv = NS_NewLocalFileOutputStream(getter_AddRefs(destStr), destFile); |
|
191 if (NS_FAILED(rv)) return rv; |
|
192 |
|
193 nsCOMPtr<nsITransport> srcTransport; |
|
194 rv = sts->CreateInputTransport(srcStr, int64_t(-1), int64_t(-1), true, |
|
195 getter_AddRefs(srcTransport)); |
|
196 if (NS_FAILED(rv)) return rv; |
|
197 |
|
198 nsCOMPtr<nsITransport> destTransport; |
|
199 rv = sts->CreateOutputTransport(destStr, int64_t(-1), int64_t(-1), true, |
|
200 getter_AddRefs(destTransport)); |
|
201 if (NS_FAILED(rv)) return rv; |
|
202 |
|
203 MyCopier *copier = new MyCopier(); |
|
204 if (copier == nullptr) |
|
205 return NS_ERROR_OUT_OF_MEMORY; |
|
206 NS_ADDREF(copier); |
|
207 |
|
208 rv = copier->AsyncCopy(srcTransport, destTransport); |
|
209 if (NS_FAILED(rv)) return rv; |
|
210 |
|
211 PumpEvents(); |
|
212 |
|
213 NS_RELEASE(copier); |
|
214 return NS_OK; |
|
215 } |
|
216 |
|
217 //////////////////////////////////////////////////////////////////////////////// |
|
218 |
|
219 static nsresult |
|
220 RunBlockingTest(nsIFile *srcFile, nsIFile *destFile) |
|
221 { |
|
222 nsresult rv; |
|
223 |
|
224 LOG(("RunBlockingTest\n")); |
|
225 |
|
226 nsCOMPtr<nsIStreamTransportService> sts = |
|
227 do_GetService(kStreamTransportServiceCID, &rv); |
|
228 if (NS_FAILED(rv)) return rv; |
|
229 |
|
230 nsCOMPtr<nsIInputStream> srcIn; |
|
231 rv = NS_NewLocalFileInputStream(getter_AddRefs(srcIn), srcFile); |
|
232 if (NS_FAILED(rv)) return rv; |
|
233 |
|
234 nsCOMPtr<nsIOutputStream> fileOut; |
|
235 rv = NS_NewLocalFileOutputStream(getter_AddRefs(fileOut), destFile); |
|
236 if (NS_FAILED(rv)) return rv; |
|
237 |
|
238 nsCOMPtr<nsITransport> destTransport; |
|
239 rv = sts->CreateOutputTransport(fileOut, int64_t(-1), int64_t(-1), |
|
240 true, getter_AddRefs(destTransport)); |
|
241 if (NS_FAILED(rv)) return rv; |
|
242 |
|
243 nsCOMPtr<nsIOutputStream> destOut; |
|
244 rv = destTransport->OpenOutputStream(nsITransport::OPEN_BLOCKING, 100, 10, getter_AddRefs(destOut)); |
|
245 if (NS_FAILED(rv)) return rv; |
|
246 |
|
247 char buf[120]; |
|
248 uint32_t n; |
|
249 for (;;) { |
|
250 rv = srcIn->Read(buf, sizeof(buf), &n); |
|
251 if (NS_FAILED(rv) || (n == 0)) return rv; |
|
252 |
|
253 rv = destOut->Write(buf, n, &n); |
|
254 if (NS_FAILED(rv)) return rv; |
|
255 } |
|
256 |
|
257 return NS_OK; |
|
258 } |
|
259 |
|
260 //////////////////////////////////////////////////////////////////////////////// |
|
261 |
|
262 int |
|
263 main(int argc, char* argv[]) |
|
264 { |
|
265 if (test_common_init(&argc, &argv) != 0) |
|
266 return -1; |
|
267 |
|
268 nsresult rv; |
|
269 |
|
270 if (argc < 2) { |
|
271 printf("usage: %s <file-to-read>\n", argv[0]); |
|
272 return -1; |
|
273 } |
|
274 char* fileName = argv[1]; |
|
275 { |
|
276 nsCOMPtr<nsIServiceManager> servMan; |
|
277 NS_InitXPCOM2(getter_AddRefs(servMan), nullptr, nullptr); |
|
278 nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(servMan); |
|
279 NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); |
|
280 if (registrar) |
|
281 registrar->AutoRegister(nullptr); |
|
282 |
|
283 #if defined(PR_LOGGING) |
|
284 gTestLog = PR_NewLogModule("Test"); |
|
285 #endif |
|
286 |
|
287 nsCOMPtr<nsIFile> srcFile; |
|
288 rv = NS_NewNativeLocalFile(nsDependentCString(fileName), false, getter_AddRefs(srcFile)); |
|
289 if (NS_FAILED(rv)) return rv; |
|
290 |
|
291 nsCOMPtr<nsIFile> destFile; |
|
292 rv = srcFile->Clone(getter_AddRefs(destFile)); |
|
293 if (NS_FAILED(rv)) return rv; |
|
294 |
|
295 nsAutoCString leafName; |
|
296 rv = destFile->GetNativeLeafName(leafName); |
|
297 if (NS_FAILED(rv)) return rv; |
|
298 |
|
299 nsAutoCString newName(leafName); |
|
300 newName.Append(NS_LITERAL_CSTRING(".1")); |
|
301 rv = destFile->SetNativeLeafName(newName); |
|
302 if (NS_FAILED(rv)) return rv; |
|
303 |
|
304 rv = RunTest(srcFile, destFile); |
|
305 NS_ASSERTION(NS_SUCCEEDED(rv), "RunTest failed"); |
|
306 |
|
307 newName = leafName; |
|
308 newName.Append(NS_LITERAL_CSTRING(".2")); |
|
309 rv = destFile->SetNativeLeafName(newName); |
|
310 if (NS_FAILED(rv)) return rv; |
|
311 |
|
312 rv = RunBlockingTest(srcFile, destFile); |
|
313 NS_ASSERTION(NS_SUCCEEDED(rv), "RunBlockingTest failed"); |
|
314 |
|
315 // give background threads a chance to finish whatever work they may |
|
316 // be doing. |
|
317 PR_Sleep(PR_SecondsToInterval(1)); |
|
318 } // this scopes the nsCOMPtrs |
|
319 // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM |
|
320 rv = NS_ShutdownXPCOM(nullptr); |
|
321 NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed"); |
|
322 return NS_OK; |
|
323 } |