diff options
Diffstat (limited to 'netwerk/streamconv/test')
-rw-r--r-- | netwerk/streamconv/test/Converters.cpp | 140 | ||||
-rw-r--r-- | netwerk/streamconv/test/Converters.h | 52 | ||||
-rw-r--r-- | netwerk/streamconv/test/TestStreamConv.cpp | 261 | ||||
-rw-r--r-- | netwerk/streamconv/test/moz.build | 22 |
4 files changed, 475 insertions, 0 deletions
diff --git a/netwerk/streamconv/test/Converters.cpp b/netwerk/streamconv/test/Converters.cpp new file mode 100644 index 000000000..61b114d77 --- /dev/null +++ b/netwerk/streamconv/test/Converters.cpp @@ -0,0 +1,140 @@ +#include "Converters.h" +#include "nsIStringStream.h" +#include "nsCOMPtr.h" +#include "nsComponentManagerUtils.h" + +#include <stdio.h> + +////////////////////////////////////////////////// +// TestConverter +////////////////////////////////////////////////// + +#define NS_TESTCONVERTER_CID \ +{ /* B8A067B0-4450-11d3-A16E-0050041CAF44 */ \ + 0xb8a067b0, \ + 0x4450, \ + 0x11d3, \ + {0xa1, 0x6e, 0x00, 0x50, 0x04, 0x1c, 0xaf, 0x44} \ +} + +NS_DEFINE_CID(kTestConverterCID, NS_TESTCONVERTER_CID); + +NS_IMPL_ISUPPORTS(TestConverter, + nsIStreamConverter, + nsIStreamListener, + nsIRequestObserver) + +TestConverter::TestConverter() { +} + +// Convert aFromStream (of type aFromType), to _retval (nsIInputStream of type aToType). +// This Convert method simply converts the stream byte-by-byte, to the first character +// in the aToType "string". +NS_IMETHODIMP +TestConverter::Convert(nsIInputStream *aFromStream, + const char *aFromType, + const char *aToType, + nsISupports *ctxt, + nsIInputStream **_retval) { + char buf[1024+1]; + uint32_t read; + nsresult rv = aFromStream->Read(buf, 1024, &read); + if (NS_FAILED(rv) || read == 0) return rv; + + // verify that the data we're converting matches the from type + // if it doesn't then we're being handed the wrong data. + char fromChar = *aFromType; + + if (fromChar != buf[0]) { + printf("We're receiving %c, but are supposed to have %c.\n", buf[0], fromChar); + return NS_ERROR_FAILURE; + } + + + // Get the first character + char toChar = *aToType; + + for (uint32_t i = 0; i < read; i++) + buf[i] = toChar; + + buf[read] = '\0'; + + nsCOMPtr<nsIStringInputStream> str + (do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = str->SetData(buf, read); + NS_ENSURE_SUCCESS(rv, rv); + + NS_ADDREF(*_retval = str); + return NS_OK; +} + +/* This method initializes any internal state before the stream converter + * begins asynchronous conversion */ +NS_IMETHODIMP +TestConverter::AsyncConvertData(const char *aFromType, + const char *aToType, + nsIStreamListener *aListener, + nsISupports *ctxt) { + NS_ASSERTION(aListener, "null listener"); + + mListener = aListener; + + // based on these types, setup internal state to handle the appropriate conversion. + fromType = aFromType; + toType = aToType; + + return NS_OK; +} + +// nsIStreamListener method +/* This method handles asyncronous conversion of data. */ +NS_IMETHODIMP +TestConverter::OnDataAvailable(nsIRequest* request, + nsISupports *ctxt, + nsIInputStream *inStr, + uint64_t sourceOffset, + uint32_t count) { + nsresult rv; + nsCOMPtr<nsIInputStream> convertedStream; + // just make a syncronous call to the Convert() method. + // Anything can happen here, I just happen to be using the sync call to + // do the actual conversion. + rv = Convert(inStr, fromType.get(), toType.get(), ctxt, getter_AddRefs(convertedStream)); + if (NS_FAILED(rv)) return rv; + + uint64_t len = 0; + convertedStream->Available(&len); + + uint64_t offset = sourceOffset; + while (len > 0) { + uint32_t count = saturated(len); + rv = mListener->OnDataAvailable(request, ctxt, convertedStream, offset, count); + if (NS_FAILED(rv)) return rv; + + offset += count; + len -= count; + } + return NS_OK; +} + +// nsIRequestObserver methods +/* These methods just pass through directly to the mListener */ +NS_IMETHODIMP +TestConverter::OnStartRequest(nsIRequest* request, nsISupports *ctxt) { + return mListener->OnStartRequest(request, ctxt); +} + +NS_IMETHODIMP +TestConverter::OnStopRequest(nsIRequest* request, nsISupports *ctxt, + nsresult aStatus) { + return mListener->OnStopRequest(request, ctxt, aStatus); +} + +nsresult +CreateTestConverter(nsISupports* aOuter, REFNSIID aIID, void** aResult) +{ + nsCOMPtr<nsISupports> conv = new TestConverter(); + return conv->QueryInterface(aIID, aResult); +} diff --git a/netwerk/streamconv/test/Converters.h b/netwerk/streamconv/test/Converters.h new file mode 100644 index 000000000..d7203262c --- /dev/null +++ b/netwerk/streamconv/test/Converters.h @@ -0,0 +1,52 @@ +#ifndef Converters_h___ +#define Converters_h___ + +#include "nsIStreamConverter.h" +#include "nsIFactory.h" +#include "nsCOMPtr.h" +#include "nsStringAPI.h" + +#include <algorithm> + +/* This file defines stream converter components, and their accompanying factory class. + * These converters implement the nsIStreamConverter interface and support both + * asynchronous and synchronous stream conversion. + */ + +/////////////////////////////////////////////// +// TestConverter + +extern const nsCID kTestConverterCID; + +class TestConverter : public nsIStreamConverter { + virtual ~TestConverter() {} +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIREQUESTOBSERVER + NS_DECL_NSISTREAMLISTENER + + TestConverter(); + + // nsIStreamConverter methods + NS_IMETHOD Convert(nsIInputStream *aFromStream, const char *aFromType, + const char *aToType, nsISupports *ctxt, nsIInputStream **_retval) override; + + + NS_IMETHOD AsyncConvertData(const char *aFromType, const char *aToType, + nsIStreamListener *aListener, nsISupports *ctxt) override; + + // member data + nsCOMPtr<nsIStreamListener> mListener; + nsCString fromType; + nsCString toType; +}; + +nsresult CreateTestConverter(nsISupports* aOuter, REFNSIID aIID, void** aResult); + +static inline uint32_t +saturated(uint64_t aValue) +{ + return (uint32_t) std::min(aValue, (uint64_t) UINT32_MAX); +} + +#endif /* !Converters_h___ */ diff --git a/netwerk/streamconv/test/TestStreamConv.cpp b/netwerk/streamconv/test/TestStreamConv.cpp new file mode 100644 index 000000000..68b85fdd7 --- /dev/null +++ b/netwerk/streamconv/test/TestStreamConv.cpp @@ -0,0 +1,261 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsIServiceManager.h" +#include "nsIStreamConverterService.h" +#include "nsIStreamConverter.h" +#include "nsICategoryManager.h" +#include "mozilla/Module.h" +#include "nsXULAppAPI.h" +#include "nsIStringStream.h" +#include "nsCOMPtr.h" +#include "nsThreadUtils.h" +#include "mozilla/Attributes.h" +#include "nsMemory.h" +#include "nsServiceManagerUtils.h" +#include "nsComponentManagerUtils.h" +#include "nsIRequest.h" +#include "nsNetCID.h" +#include "nsNetUtil.h" + +#define ASYNC_TEST // undefine this if you want to test sycnronous conversion. + +///////////////////////////////// +// Event pump setup +///////////////////////////////// +#ifdef XP_WIN +#include <windows.h> +#endif + +static int gKeepRunning = 0; +///////////////////////////////// +// Event pump END +///////////////////////////////// + + +///////////////////////////////// +// Test converters include +///////////////////////////////// +#include "Converters.h" + +// CID setup +static NS_DEFINE_CID(kStreamConverterServiceCID, NS_STREAMCONVERTERSERVICE_CID); + +//////////////////////////////////////////////////////////////////////// +// EndListener - This listener is the final one in the chain. It +// receives the fully converted data, although it doesn't do anything with +// the data. +//////////////////////////////////////////////////////////////////////// +class EndListener final : public nsIStreamListener { + ~EndListener() {} +public: + // nsISupports declaration + NS_DECL_ISUPPORTS + + EndListener() {} + + // nsIStreamListener method + NS_IMETHOD OnDataAvailable(nsIRequest* request, nsISupports *ctxt, nsIInputStream *inStr, + uint64_t sourceOffset, uint32_t count) override + { + nsresult rv; + uint32_t read; + uint64_t len64; + rv = inStr->Available(&len64); + if (NS_FAILED(rv)) return rv; + uint32_t len = (uint32_t)std::min(len64, (uint64_t)(UINT32_MAX - 1)); + + char *buffer = (char*)moz_xmalloc(len + 1); + if (!buffer) return NS_ERROR_OUT_OF_MEMORY; + + rv = inStr->Read(buffer, len, &read); + buffer[len] = '\0'; + if (NS_SUCCEEDED(rv)) { + printf("CONTEXT %p: Received %u bytes and the following data: \n %s\n\n", + static_cast<void*>(ctxt), read, buffer); + } + free(buffer); + + return NS_OK; + } + + // nsIRequestObserver methods + NS_IMETHOD OnStartRequest(nsIRequest* request, nsISupports *ctxt) override { return NS_OK; } + + NS_IMETHOD OnStopRequest(nsIRequest* request, nsISupports *ctxt, + nsresult aStatus) override { return NS_OK; } +}; + +NS_IMPL_ISUPPORTS(EndListener, + nsIStreamListener, + nsIRequestObserver) + +//////////////////////////////////////////////////////////////////////// +// EndListener END +//////////////////////////////////////////////////////////////////////// + +nsresult SendData(const char * aData, nsIStreamListener* aListener, nsIRequest* request) { + nsresult rv; + + nsCOMPtr<nsIStringInputStream> dataStream + (do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = dataStream->SetData(aData, strlen(aData)); + NS_ENSURE_SUCCESS(rv, rv); + + uint64_t avail = 0; + dataStream->Available(&avail); + + uint64_t offset = 0; + while (avail > 0) { + uint32_t count = saturated(avail); + rv = aListener->OnDataAvailable(request, nullptr, dataStream, + offset, count); + if (NS_FAILED(rv)) return rv; + + offset += count; + avail -= count; + } + return NS_OK; +} +#define SEND_DATA(x) SendData(x, converterListener, request) + +static const mozilla::Module::CIDEntry kTestCIDs[] = { + { &kTestConverterCID, false, nullptr, CreateTestConverter }, + { nullptr } +}; + +static const mozilla::Module::ContractIDEntry kTestContracts[] = { + { NS_ISTREAMCONVERTER_KEY "?from=a/foo&to=b/foo", &kTestConverterCID }, + { NS_ISTREAMCONVERTER_KEY "?from=b/foo&to=c/foo", &kTestConverterCID }, + { NS_ISTREAMCONVERTER_KEY "?from=b/foo&to=d/foo", &kTestConverterCID }, + { NS_ISTREAMCONVERTER_KEY "?from=c/foo&to=d/foo", &kTestConverterCID }, + { NS_ISTREAMCONVERTER_KEY "?from=d/foo&to=e/foo", &kTestConverterCID }, + { NS_ISTREAMCONVERTER_KEY "?from=d/foo&to=f/foo", &kTestConverterCID }, + { NS_ISTREAMCONVERTER_KEY "?from=t/foo&to=k/foo", &kTestConverterCID }, + { nullptr } +}; + +static const mozilla::Module::CategoryEntry kTestCategories[] = { + { NS_ISTREAMCONVERTER_KEY, "?from=a/foo&to=b/foo", "x" }, + { NS_ISTREAMCONVERTER_KEY, "?from=b/foo&to=c/foo", "x" }, + { NS_ISTREAMCONVERTER_KEY, "?from=b/foo&to=d/foo", "x" }, + { NS_ISTREAMCONVERTER_KEY, "?from=c/foo&to=d/foo", "x" }, + { NS_ISTREAMCONVERTER_KEY, "?from=d/foo&to=e/foo", "x" }, + { NS_ISTREAMCONVERTER_KEY, "?from=d/foo&to=f/foo", "x" }, + { NS_ISTREAMCONVERTER_KEY, "?from=t/foo&to=k/foo", "x" }, + { nullptr } +}; + +static const mozilla::Module kTestModule = { + mozilla::Module::kVersion, + kTestCIDs, + kTestContracts, + kTestCategories +}; + +int +main(int argc, char* argv[]) +{ + nsresult rv; + { + XRE_AddStaticComponent(&kTestModule); + + nsCOMPtr<nsIServiceManager> servMan; + NS_InitXPCOM2(getter_AddRefs(servMan), nullptr, nullptr); + + nsCOMPtr<nsIThread> thread = do_GetCurrentThread(); + + nsCOMPtr<nsICategoryManager> catman = + do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv); + if (NS_FAILED(rv)) return -1; + nsCString previous; + + nsCOMPtr<nsIStreamConverterService> StreamConvService = + do_GetService(kStreamConverterServiceCID, &rv); + if (NS_FAILED(rv)) return -1; + + // Define the *from* content type and *to* content-type for conversion. + static const char fromStr[] = "a/foo"; + static const char toStr[] = "c/foo"; + +#ifdef ASYNC_TEST + // ASYNCHRONOUS conversion + + // Build up a channel that represents the content we're + // starting the transaction with. + // + // sample multipart mixed content-type string: + // "multipart/x-mixed-replacE;boundary=thisrandomstring" +#if 0 + nsCOMPtr<nsIChannel> channel; + nsCOMPtr<nsIURI> dummyURI; + rv = NS_NewURI(getter_AddRefs(dummyURI), "http://meaningless"); + if (NS_FAILED(rv)) return -1; + + rv = NS_NewInputStreamChannel(getter_AddRefs(channel), + dummyURI, + nullptr, // inStr + "text/plain", // content-type + -1); // XXX fix contentLength + if (NS_FAILED(rv)) return -1; + + nsCOMPtr<nsIRequest> request(do_QueryInterface(channel)); +#endif + + nsCOMPtr<nsIRequest> request; + + // setup a listener to receive the converted data. This guy is the end + // listener in the chain, he wants the fully converted (toType) data. + // An example of this listener in mozilla would be the DocLoader. + nsIStreamListener *dataReceiver = new EndListener(); + NS_ADDREF(dataReceiver); + + // setup a listener to push the data into. This listener sits inbetween the + // unconverted data of fromType, and the final listener in the chain (in this case + // the dataReceiver. + nsIStreamListener *converterListener = nullptr; + rv = StreamConvService->AsyncConvertData(fromStr, toStr, + dataReceiver, nullptr, &converterListener); + if (NS_FAILED(rv)) return -1; + NS_RELEASE(dataReceiver); + + // at this point we have a stream listener to push data to, and the one + // that will receive the converted data. Let's mimic On*() calls and get the conversion + // going. Typically these On*() calls would be made inside their respective wrappers On*() + // methods. + rv = converterListener->OnStartRequest(request, nullptr); + if (NS_FAILED(rv)) return -1; + + rv = SEND_DATA("aaa"); + if (NS_FAILED(rv)) return -1; + + rv = SEND_DATA("aaa"); + if (NS_FAILED(rv)) return -1; + + // Finish the request. + rv = converterListener->OnStopRequest(request, nullptr, rv); + if (NS_FAILED(rv)) return -1; + + NS_RELEASE(converterListener); +#else + // SYNCHRONOUS conversion + nsCOMPtr<nsIInputStream> convertedData; + rv = StreamConvService->Convert(inputData, fromStr, toStr, + nullptr, getter_AddRefs(convertedData)); + if (NS_FAILED(rv)) return -1; +#endif + + // Enter the message pump to allow the URL load to proceed. + while ( gKeepRunning ) { + if (!NS_ProcessNextEvent(thread)) + break; + } + } // this scopes the nsCOMPtrs + // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM + NS_ShutdownXPCOM(nullptr); + return 0; +} diff --git a/netwerk/streamconv/test/moz.build b/netwerk/streamconv/test/moz.build new file mode 100644 index 000000000..ea081559b --- /dev/null +++ b/netwerk/streamconv/test/moz.build @@ -0,0 +1,22 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +GeckoProgram('TestStreamConv', linkage='dependent') + +UNIFIED_SOURCES += [ + 'Converters.cpp', + 'TestStreamConv.cpp', +] + +if CONFIG['OS_ARCH'] == 'WINNT': + DEFINES['NGPREFS'] = True + if CONFIG['GNU_CXX']: + LDFLAGS += ['-mconsole'] + else: + LDFLAGS += ['-SUBSYSTEM:CONSOLE'] + +if CONFIG['GNU_CXX']: + CXXFLAGS += ['-Wno-error=shadow'] |