|
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 "nsPISocketTransportService.h" |
|
8 #include "nsISocketTransport.h" |
|
9 #include "nsIAsyncInputStream.h" |
|
10 #include "nsIAsyncOutputStream.h" |
|
11 #include "nsIProgressEventSink.h" |
|
12 #include "nsIInterfaceRequestor.h" |
|
13 #include "nsIInterfaceRequestorUtils.h" |
|
14 #include "nsIRequest.h" |
|
15 #include "nsIServiceManager.h" |
|
16 #include "nsIComponentManager.h" |
|
17 #include "nsCOMPtr.h" |
|
18 #include "nsMemory.h" |
|
19 #include "nsStringAPI.h" |
|
20 #include "nsIDNSService.h" |
|
21 #include "nsIFileStreams.h" |
|
22 #include "nsIStreamListener.h" |
|
23 #include "nsIFile.h" |
|
24 #include "nsNetUtil.h" |
|
25 #include "nsAutoLock.h" |
|
26 #include "prlog.h" |
|
27 |
|
28 //////////////////////////////////////////////////////////////////////////////// |
|
29 |
|
30 #if defined(PR_LOGGING) |
|
31 // |
|
32 // set NSPR_LOG_MODULES=Test:5 |
|
33 // |
|
34 static PRLogModuleInfo *gTestLog = nullptr; |
|
35 #endif |
|
36 #define LOG(args) PR_LOG(gTestLog, PR_LOG_DEBUG, args) |
|
37 |
|
38 //////////////////////////////////////////////////////////////////////////////// |
|
39 |
|
40 static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID); |
|
41 |
|
42 //////////////////////////////////////////////////////////////////////////////// |
|
43 |
|
44 class MyHandler : public nsIOutputStreamCallback |
|
45 , public nsIInputStreamCallback |
|
46 { |
|
47 public: |
|
48 NS_DECL_THREADSAFE_ISUPPORTS |
|
49 |
|
50 MyHandler(const char *path, |
|
51 nsIAsyncInputStream *in, |
|
52 nsIAsyncOutputStream *out) |
|
53 : mInput(in) |
|
54 , mOutput(out) |
|
55 , mWriteOffset(0) |
|
56 { |
|
57 mBuf.Assign(NS_LITERAL_CSTRING("GET ")); |
|
58 mBuf.Append(path); |
|
59 mBuf.Append(NS_LITERAL_CSTRING(" HTTP/1.0\r\n\r\n")); |
|
60 } |
|
61 virtual ~MyHandler() {} |
|
62 |
|
63 // called on any thread |
|
64 NS_IMETHOD OnOutputStreamReady(nsIAsyncOutputStream *out) |
|
65 { |
|
66 LOG(("OnOutputStreamReady\n")); |
|
67 |
|
68 nsresult rv; |
|
69 uint32_t n, count = mBuf.Length() - mWriteOffset; |
|
70 |
|
71 rv = out->Write(mBuf.get() + mWriteOffset, count, &n); |
|
72 |
|
73 LOG((" write returned [rv=%x count=%u]\n", rv, n)); |
|
74 |
|
75 if (NS_FAILED(rv) || (n == 0)) { |
|
76 if (rv != NS_BASE_STREAM_WOULD_BLOCK) { |
|
77 LOG((" done writing; starting to read\n")); |
|
78 mInput->AsyncWait(this, 0, 0, nullptr); |
|
79 return NS_OK; |
|
80 } |
|
81 } |
|
82 |
|
83 mWriteOffset += n; |
|
84 |
|
85 return out->AsyncWait(this, 0, 0, nullptr); |
|
86 } |
|
87 |
|
88 // called on any thread |
|
89 NS_IMETHOD OnInputStreamReady(nsIAsyncInputStream *in) |
|
90 { |
|
91 LOG(("OnInputStreamReady\n")); |
|
92 |
|
93 nsresult rv; |
|
94 uint32_t n; |
|
95 char buf[500]; |
|
96 |
|
97 rv = in->Read(buf, sizeof(buf), &n); |
|
98 |
|
99 LOG((" read returned [rv=%x count=%u]\n", rv, n)); |
|
100 |
|
101 if (NS_FAILED(rv) || (n == 0)) { |
|
102 if (rv != NS_BASE_STREAM_WOULD_BLOCK) { |
|
103 QuitPumpingEvents(); |
|
104 return NS_OK; |
|
105 } |
|
106 } |
|
107 |
|
108 return in->AsyncWait(this, 0, 0, nullptr); |
|
109 } |
|
110 |
|
111 private: |
|
112 nsCOMPtr<nsIAsyncInputStream> mInput; |
|
113 nsCOMPtr<nsIAsyncOutputStream> mOutput; |
|
114 nsCString mBuf; |
|
115 uint32_t mWriteOffset; |
|
116 }; |
|
117 |
|
118 NS_IMPL_ISUPPORTS(MyHandler, |
|
119 nsIOutputStreamCallback, |
|
120 nsIInputStreamCallback) |
|
121 |
|
122 //////////////////////////////////////////////////////////////////////////////// |
|
123 |
|
124 /** |
|
125 * create transport, open streams, and close |
|
126 */ |
|
127 static nsresult |
|
128 RunCloseTest(nsISocketTransportService *sts, |
|
129 const char *host, int port, |
|
130 uint32_t inFlags, uint32_t outFlags) |
|
131 { |
|
132 nsresult rv; |
|
133 |
|
134 LOG(("RunCloseTest\n")); |
|
135 |
|
136 nsCOMPtr<nsISocketTransport> transport; |
|
137 rv = sts->CreateTransport(nullptr, 0, |
|
138 nsDependentCString(host), port, nullptr, |
|
139 getter_AddRefs(transport)); |
|
140 if (NS_FAILED(rv)) return rv; |
|
141 |
|
142 nsCOMPtr<nsIInputStream> in; |
|
143 rv = transport->OpenInputStream(inFlags, 0, 0, getter_AddRefs(in)); |
|
144 nsCOMPtr<nsIAsyncInputStream> asyncIn = do_QueryInterface(in, &rv); |
|
145 if (NS_FAILED(rv)) return rv; |
|
146 |
|
147 nsCOMPtr<nsIOutputStream> out; |
|
148 rv = transport->OpenOutputStream(outFlags, 0, 0, getter_AddRefs(out)); |
|
149 nsCOMPtr<nsIAsyncOutputStream> asyncOut = do_QueryInterface(out, &rv); |
|
150 if (NS_FAILED(rv)) return rv; |
|
151 |
|
152 LOG(("waiting 1 second before closing transport and streams...\n")); |
|
153 PR_Sleep(PR_SecondsToInterval(1)); |
|
154 |
|
155 // let nsCOMPtr destructors close everything... |
|
156 return NS_OK; |
|
157 } |
|
158 |
|
159 |
|
160 /** |
|
161 * asynchronously read socket stream |
|
162 */ |
|
163 static nsresult |
|
164 RunTest(nsISocketTransportService *sts, |
|
165 const char *host, int port, const char *path, |
|
166 uint32_t inFlags, uint32_t outFlags) |
|
167 { |
|
168 nsresult rv; |
|
169 |
|
170 LOG(("RunTest\n")); |
|
171 |
|
172 nsCOMPtr<nsISocketTransport> transport; |
|
173 rv = sts->CreateTransport(nullptr, 0, |
|
174 nsDependentCString(host), port, nullptr, |
|
175 getter_AddRefs(transport)); |
|
176 if (NS_FAILED(rv)) return rv; |
|
177 |
|
178 nsCOMPtr<nsIInputStream> in; |
|
179 rv = transport->OpenInputStream(inFlags, 0, 0, getter_AddRefs(in)); |
|
180 nsCOMPtr<nsIAsyncInputStream> asyncIn = do_QueryInterface(in, &rv); |
|
181 if (NS_FAILED(rv)) return rv; |
|
182 |
|
183 nsCOMPtr<nsIOutputStream> out; |
|
184 rv = transport->OpenOutputStream(outFlags, 0, 0, getter_AddRefs(out)); |
|
185 nsCOMPtr<nsIAsyncOutputStream> asyncOut = do_QueryInterface(out, &rv); |
|
186 if (NS_FAILED(rv)) return rv; |
|
187 |
|
188 MyHandler *handler = new MyHandler(path, asyncIn, asyncOut); |
|
189 if (handler == nullptr) |
|
190 return NS_ERROR_OUT_OF_MEMORY; |
|
191 NS_ADDREF(handler); |
|
192 |
|
193 rv = asyncOut->AsyncWait(handler, 0, 0, nullptr); |
|
194 |
|
195 if (NS_SUCCEEDED(rv)) |
|
196 PumpEvents(); |
|
197 |
|
198 NS_RELEASE(handler); |
|
199 |
|
200 return NS_OK; |
|
201 } |
|
202 |
|
203 //////////////////////////////////////////////////////////////////////////////// |
|
204 |
|
205 int |
|
206 main(int argc, char* argv[]) |
|
207 { |
|
208 if (test_common_init(&argc, &argv) != 0) |
|
209 return -1; |
|
210 |
|
211 nsresult rv; |
|
212 |
|
213 if (argc < 4) { |
|
214 printf("usage: TestSocketTransport <host> <port> <path>\n"); |
|
215 return -1; |
|
216 } |
|
217 |
|
218 { |
|
219 nsCOMPtr<nsIServiceManager> servMan; |
|
220 NS_InitXPCOM2(getter_AddRefs(servMan), nullptr, nullptr); |
|
221 nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(servMan); |
|
222 NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); |
|
223 if (registrar) |
|
224 registrar->AutoRegister(nullptr); |
|
225 |
|
226 #if defined(PR_LOGGING) |
|
227 gTestLog = PR_NewLogModule("Test"); |
|
228 #endif |
|
229 |
|
230 // Make sure the DNS service is initialized on the main thread |
|
231 nsCOMPtr<nsIDNSService> dns = |
|
232 do_GetService(NS_DNSSERVICE_CONTRACTID, &rv); |
|
233 if (NS_FAILED(rv)) return rv; |
|
234 |
|
235 nsCOMPtr<nsPISocketTransportService> sts = |
|
236 do_GetService(kSocketTransportServiceCID, &rv); |
|
237 if (NS_FAILED(rv)) return rv; |
|
238 |
|
239 LOG(("phase 1 tests...\n")); |
|
240 |
|
241 LOG(("flags = { OPEN_UNBUFFERED, OPEN_UNBUFFERED }\n")); |
|
242 rv = RunCloseTest(sts, argv[1], atoi(argv[2]), |
|
243 nsITransport::OPEN_UNBUFFERED, |
|
244 nsITransport::OPEN_UNBUFFERED); |
|
245 NS_ASSERTION(NS_SUCCEEDED(rv), "RunCloseTest failed"); |
|
246 |
|
247 LOG(("flags = { OPEN_BUFFERED, OPEN_UNBUFFERED }\n")); |
|
248 rv = RunCloseTest(sts, argv[1], atoi(argv[2]), |
|
249 0 /* nsITransport::OPEN_BUFFERED */, |
|
250 nsITransport::OPEN_UNBUFFERED); |
|
251 NS_ASSERTION(NS_SUCCEEDED(rv), "RunCloseTest failed"); |
|
252 |
|
253 LOG(("flags = { OPEN_UNBUFFERED, OPEN_BUFFERED }\n")); |
|
254 rv = RunCloseTest(sts, argv[1], atoi(argv[2]), |
|
255 nsITransport::OPEN_UNBUFFERED, |
|
256 0 /*nsITransport::OPEN_BUFFERED */); |
|
257 NS_ASSERTION(NS_SUCCEEDED(rv), "RunCloseTest failed"); |
|
258 |
|
259 LOG(("flags = { OPEN_BUFFERED, OPEN_BUFFERED }\n")); |
|
260 rv = RunCloseTest(sts, argv[1], atoi(argv[2]), |
|
261 0 /*nsITransport::OPEN_BUFFERED */, |
|
262 0 /*nsITransport::OPEN_BUFFERED */); |
|
263 NS_ASSERTION(NS_SUCCEEDED(rv), "RunCloseTest failed"); |
|
264 |
|
265 LOG(("calling Shutdown on socket transport service:\n")); |
|
266 sts->Shutdown(); |
|
267 |
|
268 LOG(("calling Init on socket transport service:\n")); |
|
269 sts->Init(); |
|
270 |
|
271 LOG(("phase 2 tests...\n")); |
|
272 |
|
273 LOG(("flags = { OPEN_UNBUFFERED, OPEN_UNBUFFERED }\n")); |
|
274 rv = RunTest(sts, argv[1], atoi(argv[2]), argv[3], |
|
275 nsITransport::OPEN_UNBUFFERED, |
|
276 nsITransport::OPEN_UNBUFFERED); |
|
277 NS_ASSERTION(NS_SUCCEEDED(rv), "RunTest failed"); |
|
278 |
|
279 LOG(("flags = { OPEN_BUFFERED, OPEN_UNBUFFERED }\n")); |
|
280 rv = RunTest(sts, argv[1], atoi(argv[2]), argv[3], |
|
281 0 /* nsITransport::OPEN_BUFFERED */, |
|
282 nsITransport::OPEN_UNBUFFERED); |
|
283 NS_ASSERTION(NS_SUCCEEDED(rv), "RunTest failed"); |
|
284 |
|
285 LOG(("flags = { OPEN_UNBUFFERED, OPEN_BUFFERED }\n")); |
|
286 rv = RunTest(sts, argv[1], atoi(argv[2]), argv[3], |
|
287 nsITransport::OPEN_UNBUFFERED, |
|
288 0 /*nsITransport::OPEN_BUFFERED */); |
|
289 NS_ASSERTION(NS_SUCCEEDED(rv), "RunTest failed"); |
|
290 |
|
291 LOG(("flags = { OPEN_BUFFERED, OPEN_BUFFERED }\n")); |
|
292 rv = RunTest(sts, argv[1], atoi(argv[2]), argv[3], |
|
293 0 /*nsITransport::OPEN_BUFFERED */, |
|
294 0 /*nsITransport::OPEN_BUFFERED */); |
|
295 NS_ASSERTION(NS_SUCCEEDED(rv), "RunTest failed"); |
|
296 |
|
297 LOG(("waiting 1 second before calling Shutdown...\n")); |
|
298 PR_Sleep(PR_SecondsToInterval(1)); |
|
299 |
|
300 LOG(("calling Shutdown on socket transport service:\n")); |
|
301 sts->Shutdown(); |
|
302 |
|
303 // give background threads a chance to finish whatever work they may |
|
304 // be doing. |
|
305 LOG(("waiting 1 second before exiting...\n")); |
|
306 PR_Sleep(PR_SecondsToInterval(1)); |
|
307 } // this scopes the nsCOMPtrs |
|
308 // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM |
|
309 rv = NS_ShutdownXPCOM(nullptr); |
|
310 NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed"); |
|
311 return 0; |
|
312 } |