merged GH #2641: Implement DataURIStream for extracting data from data URIs

This commit is contained in:
Günter Obiltschnig 2020-01-24 10:41:35 +01:00
parent a052c627cc
commit 66d96744b1
9 changed files with 417 additions and 2 deletions

View File

@ -30,7 +30,7 @@ objects = ArchiveStrategy Ascii ASCIIEncoding AsyncChannel \
FileStreamFactory URIStreamFactory URIStreamOpener UTF32Encoding UTF16Encoding UTF8Encoding UTF8String \
Unicode UnicodeConverter Windows1250Encoding Windows1251Encoding Windows1252Encoding \
UUID UUIDGenerator Void Var VarHolder VarIterator Format Pipe PipeImpl PipeStream SharedMemory \
MemoryStream FileStream AtomicCounter
MemoryStream FileStream AtomicCounter DataURIStream DataURIStreamFactory
zlib_objects = adler32 compress crc32 deflate \
infback inffast inflate inftrees trees zutil

View File

@ -0,0 +1,78 @@
//
// DataURIStream.h
//
// Library: Foundation
// Package: Streams
// Module: DataURIStreamFactory
//
// Definition of the DataURIStream class.
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Foundation_DataURIStream_INCLUDED
#define Foundation_DataURIStream_INCLUDED
#include "Poco/Foundation.h"
#include <istream>
#include <memory>
namespace Poco {
class Base64Decoder;
class MemoryInputStream;
class URI;
class Foundation_API DataURIStreamIOS: public virtual std::ios
/// The base class for DataURIStream.
///
/// This class is needed to ensure the correct initialization
/// order of the stream buffer and base classes.
{
public:
DataURIStreamIOS(const URI& uri);
~DataURIStreamIOS();
std::streambuf* rdbuf();
protected:
std::streambuf* _buf;
private:
DataURIStreamIOS(const DataURIStreamIOS&);
DataURIStreamIOS& operator = (const DataURIStreamIOS&);
std::string _data;
std::unique_ptr<MemoryInputStream> _memoryStream;
std::unique_ptr<Base64Decoder> _base64Decoder;
};
class Foundation_API DataURIStream: public DataURIStreamIOS, public std::istream
/// An input stream for reading data from a data URI.
/// For example, when constructed from "data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D" it reads "Hello, World!".
{
public:
DataURIStream(const URI& uri);
/// Creates a DataURIStream for the given data URI,
/// ready for reading data.
/// Throws a DataFormatException exception if the data is incorrect format.
~DataURIStream();
/// Destroys the DataURIStream.
private:
DataURIStream(const DataURIStream&);
DataURIStream& operator = (const DataURIStream&);
};
} // namespace Poco
#endif // Foundation_DataURIStream_INCLUDED

View File

@ -0,0 +1,58 @@
//
// DataURIStreamFactory.h
//
// Library: Foundation
// Package: URI
// Module: DataURIStreamFactory
//
// Definition of the DataURIStreamFactory class.
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Foundation_DataURIStreamFactory_INCLUDED
#define Foundation_DataURIStreamFactory_INCLUDED
#include "Poco/Foundation.h"
#include "Poco/URIStreamFactory.h"
namespace Poco {
class Foundation_API DataURIStreamFactory: public URIStreamFactory
/// An implementation of the URIStreamFactory interface
/// that read data from data URIs.
/// For example, for URI "data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D" it read "Hello, World!".
{
public:
DataURIStreamFactory();
/// Creates the DataURIStreamFactory.
~DataURIStreamFactory();
/// Destroys the DataURIStreamFactory.
std::istream* open(const URI& uri);
/// Creates an input stream returning decoded data from the given data URI.
///
/// Throws a DataFormatException exception if the data is incorrect format.
static void registerFactory();
/// Registers the DataURIStreamFactory with the
/// default URIStreamOpener instance.
static void unregisterFactory();
/// Unregisters the DataURIStreamFactory with the
/// default URIStreamOpener instance.
};
} // namespace Poco
#endif // Foundation_DataURIStreamFactory_INCLUDED

View File

@ -0,0 +1,72 @@
//
// DataURIStream.cpp
//
// Library: Foundation
// Package: Streams
// Module: DataURIStreamFactory
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/DataURIStream.h"
#include "Poco/Base64Decoder.h"
#include "Poco/Exception.h"
#include "Poco/MemoryStream.h"
#include "Poco/Path.h"
#include "Poco/StreamUtil.h"
#include "Poco/URI.h"
#include <string.h>
namespace Poco {
DataURIStreamIOS::DataURIStreamIOS(const URI& uri)
{
poco_assert (uri.getScheme() == "data");
const std::string& path = uri.getPath();
size_t comma = path.find(',');
if (comma == std::string::npos)
throw DataFormatException();
_data = path.substr(comma + 1);
_memoryStream.reset(new MemoryInputStream(_data.data(), _data.length()));
constexpr char base64[] = ";base64";
const size_t base64Len = strlen(base64);
if ((comma >= base64Len) && !path.compare(comma - base64Len, base64Len, base64, base64Len))
{
_base64Decoder.reset(new Base64Decoder(*_memoryStream, 0));
_buf = _base64Decoder->rdbuf();
}
else
_buf = _memoryStream->rdbuf();
poco_ios_init(_buf);
}
DataURIStreamIOS::~DataURIStreamIOS()
{
}
std::streambuf* DataURIStreamIOS::rdbuf()
{
return _buf;
}
DataURIStream::DataURIStream(const URI& uri): DataURIStreamIOS(uri), std::istream(_buf)
{
}
DataURIStream::~DataURIStream()
{
}
} // namespace Poco

View File

@ -0,0 +1,54 @@
//
// DataURIStreamFactory.cpp
//
// Library: Foundation
// Package: URI
// Module: DataURIStreamFactory
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/DataURIStreamFactory.h"
#include "Poco/DataURIStream.h"
#include "Poco/URI.h"
#include "Poco/URIStreamOpener.h"
namespace Poco {
DataURIStreamFactory::DataURIStreamFactory()
{
}
DataURIStreamFactory::~DataURIStreamFactory()
{
}
std::istream* DataURIStreamFactory::open(const URI& uri)
{
poco_assert (uri.getScheme() == "data");
return new DataURIStream(uri);
}
void DataURIStreamFactory::registerFactory()
{
URIStreamOpener::defaultOpener().registerStreamFactory("data", new DataURIStreamFactory);
}
void DataURIStreamFactory::unregisterFactory()
{
URIStreamOpener::defaultOpener().unregisterStreamFactory("data");
}
} // namespace Poco

View File

@ -37,7 +37,8 @@ objects = ActiveMethodTest ActivityTest ActiveDispatcherTest \
HashSetTest HashMapTest SharedMemoryTest OrderedContainersTest \
UniqueExpireCacheTest UniqueExpireLRUCacheTest UnicodeConverterTest \
TuplesTest NamedTuplesTest TypeListTest VarTest DynamicTestSuite FileStreamTest \
MemoryStreamTest ObjectPoolTest DirectoryWatcherTest DirectoryIteratorsTest
MemoryStreamTest ObjectPoolTest DirectoryWatcherTest DirectoryIteratorsTest \
DataURIStreamTest
target = testrunner
target_version = 1

View File

@ -0,0 +1,113 @@
//
// DataURIStreamTest.cpp
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "DataURIStreamTest.h"
#include "Poco/CppUnit/TestCaller.h"
#include "Poco/CppUnit/TestSuite.h"
#include "Poco/DataURIStream.h"
#include "Poco/Exception.h"
#include "Poco/URI.h"
#include "Poco/StreamCopier.h"
#include <sstream>
using Poco::DataFormatException;
using Poco::DataURIStream;
using Poco::StreamCopier;
using Poco::URI;
DataURIStreamTest::DataURIStreamTest(const std::string& name): CppUnit::TestCase(name)
{
}
DataURIStreamTest::~DataURIStreamTest()
{
}
void DataURIStreamTest::testWithBase64()
{
{
DataURIStream ds(URI("data:;base64,SGVsbG8sIFdvcmxkIQ%3D%3D"));
std::ostringstream ostr;
StreamCopier::copyStream(ds, ostr);
assertTrue (ostr.str() == "Hello, World!");
}
{
DataURIStream ds(URI("data:text/vnd-example+xyz;foo=bar;base64,R0lGODdh"));
std::ostringstream ostr;
StreamCopier::copyStream(ds, ostr);
assertTrue (ostr.str() == "GIF87a");
}
{
DataURIStream ds(URI("data:application/octet-stream;base64,A+b/7A=="));
std::ostringstream ostr;
StreamCopier::copyStream(ds, ostr);
assertTrue (ostr.str() == "\x03\xE6\xFF\xEC");
}
}
void DataURIStreamTest::testWithoutBase64()
{
{
DataURIStream ds(URI("data:,Hello%2C%20World!"));
std::ostringstream ostr;
StreamCopier::copyStream(ds, ostr);
assertTrue (ostr.str() == "Hello, World!");
}
{
DataURIStream ds(URI("data:text/plain;charset=UTF-8;page=21,the%20data:1234,5678"));
std::ostringstream ostr;
StreamCopier::copyStream(ds, ostr);
assertTrue (ostr.str() == "the data:1234,5678");
}
}
void DataURIStreamTest::testZeroLengthData()
{
{
DataURIStream ds(URI("data:text/plain;base64,"));
std::ostringstream ostr;
StreamCopier::copyStream(ds, ostr);
assertTrue (ostr.str().empty());
}
{
DataURIStream ds(URI("data:,"));
std::ostringstream ostr;
StreamCopier::copyStream(ds, ostr);
assertTrue (ostr.str().empty());
}
}
void DataURIStreamTest::setUp()
{
}
void DataURIStreamTest::tearDown()
{
}
CppUnit::Test* DataURIStreamTest::suite()
{
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("DataURIStreamTest");
CppUnit_addTest(pSuite, DataURIStreamTest, testWithBase64);
CppUnit_addTest(pSuite, DataURIStreamTest, testWithoutBase64);
CppUnit_addTest(pSuite, DataURIStreamTest, testZeroLengthData);
return pSuite;
}

View File

@ -0,0 +1,37 @@
//
// DataURIStreamTest.h
//
// Definition of the DataURItreamTest class.
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef DataURIStreamTest_INCLUDED
#define DataURIStreamTest_INCLUDED
#include "Poco/CppUnit/TestCase.h"
class DataURIStreamTest: public CppUnit::TestCase
{
public:
DataURIStreamTest(const std::string& name);
~DataURIStreamTest();
void testWithBase64();
void testWithoutBase64();
void testZeroLengthData();
void setUp();
void tearDown();
static CppUnit::Test* suite();
};
#endif // DataURIStreamTest_INCLUDED

View File

@ -23,6 +23,7 @@
#include "FileStreamTest.h"
#include "MemoryStreamTest.h"
#include "FIFOBufferStreamTest.h"
#include "DataURIStreamTest.h"
CppUnit::Test* StreamsTestSuite::suite()
@ -43,6 +44,7 @@ CppUnit::Test* StreamsTestSuite::suite()
pSuite->addTest(FileStreamTest::suite());
pSuite->addTest(MemoryStreamTest::suite());
pSuite->addTest(FIFOBufferStreamTest::suite());
pSuite->addTest(DataURIStreamTest::suite());
return pSuite;
}