|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
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 "nsIServiceManager.h" |
|
7 #include "nsIStreamConverterService.h" |
|
8 #include "nsIStreamConverter.h" |
|
9 #include "nsICategoryManager.h" |
|
10 #include "mozilla/Module.h" |
|
11 #include "nsXULAppAPI.h" |
|
12 #include "nsIStringStream.h" |
|
13 #include "nsCOMPtr.h" |
|
14 #include "nsThreadUtils.h" |
|
15 #include "mozilla/Attributes.h" |
|
16 #include "nsMemory.h" |
|
17 #include "nsServiceManagerUtils.h" |
|
18 #include "nsComponentManagerUtils.h" |
|
19 #include "nsIRequest.h" |
|
20 #include "nsNetCID.h" |
|
21 |
|
22 #define ASYNC_TEST // undefine this if you want to test sycnronous conversion. |
|
23 |
|
24 ///////////////////////////////// |
|
25 // Event pump setup |
|
26 ///////////////////////////////// |
|
27 #ifdef XP_WIN |
|
28 #include <windows.h> |
|
29 #endif |
|
30 |
|
31 static int gKeepRunning = 0; |
|
32 ///////////////////////////////// |
|
33 // Event pump END |
|
34 ///////////////////////////////// |
|
35 |
|
36 |
|
37 ///////////////////////////////// |
|
38 // Test converters include |
|
39 ///////////////////////////////// |
|
40 #include "Converters.h" |
|
41 |
|
42 // CID setup |
|
43 static NS_DEFINE_CID(kStreamConverterServiceCID, NS_STREAMCONVERTERSERVICE_CID); |
|
44 |
|
45 //////////////////////////////////////////////////////////////////////// |
|
46 // EndListener - This listener is the final one in the chain. It |
|
47 // receives the fully converted data, although it doesn't do anything with |
|
48 // the data. |
|
49 //////////////////////////////////////////////////////////////////////// |
|
50 class EndListener MOZ_FINAL : public nsIStreamListener { |
|
51 public: |
|
52 // nsISupports declaration |
|
53 NS_DECL_ISUPPORTS |
|
54 |
|
55 EndListener() {} |
|
56 |
|
57 // nsIStreamListener method |
|
58 NS_IMETHOD OnDataAvailable(nsIRequest* request, nsISupports *ctxt, nsIInputStream *inStr, |
|
59 uint64_t sourceOffset, uint32_t count) |
|
60 { |
|
61 nsresult rv; |
|
62 uint32_t read; |
|
63 uint64_t len64; |
|
64 rv = inStr->Available(&len64); |
|
65 if (NS_FAILED(rv)) return rv; |
|
66 uint32_t len = (uint32_t)std::min(len64, (uint64_t)(UINT32_MAX - 1)); |
|
67 |
|
68 char *buffer = (char*)nsMemory::Alloc(len + 1); |
|
69 if (!buffer) return NS_ERROR_OUT_OF_MEMORY; |
|
70 |
|
71 rv = inStr->Read(buffer, len, &read); |
|
72 buffer[len] = '\0'; |
|
73 if (NS_SUCCEEDED(rv)) { |
|
74 printf("CONTEXT %p: Received %u bytes and the following data: \n %s\n\n", |
|
75 static_cast<void*>(ctxt), read, buffer); |
|
76 } |
|
77 nsMemory::Free(buffer); |
|
78 |
|
79 return NS_OK; |
|
80 } |
|
81 |
|
82 // nsIRequestObserver methods |
|
83 NS_IMETHOD OnStartRequest(nsIRequest* request, nsISupports *ctxt) { return NS_OK; } |
|
84 |
|
85 NS_IMETHOD OnStopRequest(nsIRequest* request, nsISupports *ctxt, |
|
86 nsresult aStatus) { return NS_OK; } |
|
87 }; |
|
88 |
|
89 NS_IMPL_ISUPPORTS(EndListener, |
|
90 nsIStreamListener, |
|
91 nsIRequestObserver) |
|
92 |
|
93 //////////////////////////////////////////////////////////////////////// |
|
94 // EndListener END |
|
95 //////////////////////////////////////////////////////////////////////// |
|
96 |
|
97 nsresult SendData(const char * aData, nsIStreamListener* aListener, nsIRequest* request) { |
|
98 nsresult rv; |
|
99 |
|
100 nsCOMPtr<nsIStringInputStream> dataStream |
|
101 (do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv)); |
|
102 NS_ENSURE_SUCCESS(rv, rv); |
|
103 |
|
104 rv = dataStream->SetData(aData, strlen(aData)); |
|
105 NS_ENSURE_SUCCESS(rv, rv); |
|
106 |
|
107 uint64_t avail = 0; |
|
108 dataStream->Available(&avail); |
|
109 |
|
110 uint64_t offset = 0; |
|
111 while (avail > 0) { |
|
112 uint32_t count = saturated(avail); |
|
113 rv = aListener->OnDataAvailable(request, nullptr, dataStream, |
|
114 offset, count); |
|
115 if (NS_FAILED(rv)) return rv; |
|
116 |
|
117 offset += count; |
|
118 avail -= count; |
|
119 } |
|
120 return NS_OK; |
|
121 } |
|
122 #define SEND_DATA(x) SendData(x, converterListener, request) |
|
123 |
|
124 static const mozilla::Module::CIDEntry kTestCIDs[] = { |
|
125 { &kTestConverterCID, false, nullptr, CreateTestConverter }, |
|
126 { nullptr } |
|
127 }; |
|
128 |
|
129 static const mozilla::Module::ContractIDEntry kTestContracts[] = { |
|
130 { NS_ISTREAMCONVERTER_KEY "?from=a/foo&to=b/foo", &kTestConverterCID }, |
|
131 { NS_ISTREAMCONVERTER_KEY "?from=b/foo&to=c/foo", &kTestConverterCID }, |
|
132 { NS_ISTREAMCONVERTER_KEY "?from=b/foo&to=d/foo", &kTestConverterCID }, |
|
133 { NS_ISTREAMCONVERTER_KEY "?from=c/foo&to=d/foo", &kTestConverterCID }, |
|
134 { NS_ISTREAMCONVERTER_KEY "?from=d/foo&to=e/foo", &kTestConverterCID }, |
|
135 { NS_ISTREAMCONVERTER_KEY "?from=d/foo&to=f/foo", &kTestConverterCID }, |
|
136 { NS_ISTREAMCONVERTER_KEY "?from=t/foo&to=k/foo", &kTestConverterCID }, |
|
137 { nullptr } |
|
138 }; |
|
139 |
|
140 static const mozilla::Module::CategoryEntry kTestCategories[] = { |
|
141 { NS_ISTREAMCONVERTER_KEY, "?from=a/foo&to=b/foo", "x" }, |
|
142 { NS_ISTREAMCONVERTER_KEY, "?from=b/foo&to=c/foo", "x" }, |
|
143 { NS_ISTREAMCONVERTER_KEY, "?from=b/foo&to=d/foo", "x" }, |
|
144 { NS_ISTREAMCONVERTER_KEY, "?from=c/foo&to=d/foo", "x" }, |
|
145 { NS_ISTREAMCONVERTER_KEY, "?from=d/foo&to=e/foo", "x" }, |
|
146 { NS_ISTREAMCONVERTER_KEY, "?from=d/foo&to=f/foo", "x" }, |
|
147 { NS_ISTREAMCONVERTER_KEY, "?from=t/foo&to=k/foo", "x" }, |
|
148 { nullptr } |
|
149 }; |
|
150 |
|
151 static const mozilla::Module kTestModule = { |
|
152 mozilla::Module::kVersion, |
|
153 kTestCIDs, |
|
154 kTestContracts, |
|
155 kTestCategories |
|
156 }; |
|
157 |
|
158 int |
|
159 main(int argc, char* argv[]) |
|
160 { |
|
161 nsresult rv; |
|
162 { |
|
163 XRE_AddStaticComponent(&kTestModule); |
|
164 |
|
165 nsCOMPtr<nsIServiceManager> servMan; |
|
166 NS_InitXPCOM2(getter_AddRefs(servMan), nullptr, nullptr); |
|
167 |
|
168 nsCOMPtr<nsIThread> thread = do_GetCurrentThread(); |
|
169 |
|
170 nsCOMPtr<nsICategoryManager> catman = |
|
171 do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv); |
|
172 if (NS_FAILED(rv)) return -1; |
|
173 nsCString previous; |
|
174 |
|
175 nsCOMPtr<nsIStreamConverterService> StreamConvService = |
|
176 do_GetService(kStreamConverterServiceCID, &rv); |
|
177 if (NS_FAILED(rv)) return -1; |
|
178 |
|
179 // Define the *from* content type and *to* content-type for conversion. |
|
180 static const char fromStr[] = "a/foo"; |
|
181 static const char toStr[] = "c/foo"; |
|
182 |
|
183 #ifdef ASYNC_TEST |
|
184 // ASYNCHRONOUS conversion |
|
185 |
|
186 // Build up a channel that represents the content we're |
|
187 // starting the transaction with. |
|
188 // |
|
189 // sample multipart mixed content-type string: |
|
190 // "multipart/x-mixed-replacE;boundary=thisrandomstring" |
|
191 #if 0 |
|
192 nsCOMPtr<nsIChannel> channel; |
|
193 nsCOMPtr<nsIURI> dummyURI; |
|
194 rv = NS_NewURI(getter_AddRefs(dummyURI), "http://meaningless"); |
|
195 if (NS_FAILED(rv)) return -1; |
|
196 |
|
197 rv = NS_NewInputStreamChannel(getter_AddRefs(channel), |
|
198 dummyURI, |
|
199 nullptr, // inStr |
|
200 "text/plain", // content-type |
|
201 -1); // XXX fix contentLength |
|
202 if (NS_FAILED(rv)) return -1; |
|
203 |
|
204 nsCOMPtr<nsIRequest> request(do_QueryInterface(channel)); |
|
205 #endif |
|
206 |
|
207 nsCOMPtr<nsIRequest> request; |
|
208 |
|
209 // setup a listener to receive the converted data. This guy is the end |
|
210 // listener in the chain, he wants the fully converted (toType) data. |
|
211 // An example of this listener in mozilla would be the DocLoader. |
|
212 nsIStreamListener *dataReceiver = new EndListener(); |
|
213 NS_ADDREF(dataReceiver); |
|
214 |
|
215 // setup a listener to push the data into. This listener sits inbetween the |
|
216 // unconverted data of fromType, and the final listener in the chain (in this case |
|
217 // the dataReceiver. |
|
218 nsIStreamListener *converterListener = nullptr; |
|
219 rv = StreamConvService->AsyncConvertData(fromStr, toStr, |
|
220 dataReceiver, nullptr, &converterListener); |
|
221 if (NS_FAILED(rv)) return -1; |
|
222 NS_RELEASE(dataReceiver); |
|
223 |
|
224 // at this point we have a stream listener to push data to, and the one |
|
225 // that will receive the converted data. Let's mimic On*() calls and get the conversion |
|
226 // going. Typically these On*() calls would be made inside their respective wrappers On*() |
|
227 // methods. |
|
228 rv = converterListener->OnStartRequest(request, nullptr); |
|
229 if (NS_FAILED(rv)) return -1; |
|
230 |
|
231 rv = SEND_DATA("aaa"); |
|
232 if (NS_FAILED(rv)) return -1; |
|
233 |
|
234 rv = SEND_DATA("aaa"); |
|
235 if (NS_FAILED(rv)) return -1; |
|
236 |
|
237 // Finish the request. |
|
238 rv = converterListener->OnStopRequest(request, nullptr, rv); |
|
239 if (NS_FAILED(rv)) return -1; |
|
240 |
|
241 NS_RELEASE(converterListener); |
|
242 #else |
|
243 // SYNCHRONOUS conversion |
|
244 nsCOMPtr<nsIInputStream> convertedData; |
|
245 rv = StreamConvService->Convert(inputData, fromStr, toStr, |
|
246 nullptr, getter_AddRefs(convertedData)); |
|
247 if (NS_FAILED(rv)) return -1; |
|
248 #endif |
|
249 |
|
250 // Enter the message pump to allow the URL load to proceed. |
|
251 while ( gKeepRunning ) { |
|
252 if (!NS_ProcessNextEvent(thread)) |
|
253 break; |
|
254 } |
|
255 } // this scopes the nsCOMPtrs |
|
256 // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM |
|
257 NS_ShutdownXPCOM(nullptr); |
|
258 return 0; |
|
259 } |