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