From 4e35d35f73b9cdc81474ce1546eb5ea33d876d50 Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Mon, 10 Oct 2011 17:11:14 +0000 Subject: [PATCH] Expose size limits on storage in API, and add overflow detection logic to replay cache. --- xmltooling/impl/MemoryStorageService.cpp | 9 ++++ xmltooling/util/ReplayCache.cpp | 35 ++++++++++++-- xmltooling/util/ReplayCache.h | 2 + xmltooling/util/StorageService.cpp | 33 +++++++++++++ xmltooling/util/StorageService.h | 82 +++++++++++++++++++++++++------- 5 files changed, 139 insertions(+), 22 deletions(-) diff --git a/xmltooling/impl/MemoryStorageService.cpp b/xmltooling/impl/MemoryStorageService.cpp index 60d2c63..7547d07 100644 --- a/xmltooling/impl/MemoryStorageService.cpp +++ b/xmltooling/impl/MemoryStorageService.cpp @@ -40,6 +40,11 @@ using namespace std; using xercesc::DOMElement; +namespace { + // Reasonably extended sizes to avoid callers needing to shrink unduly. + static const XMLTOOL_DLLLOCAL StorageService::Capabilities g_memCaps(0x4000, 0x4000, 0x4000); +}; + namespace xmltooling { class XMLTOOL_DLLLOCAL MemoryStorageService : public StorageService { @@ -47,6 +52,10 @@ namespace xmltooling { MemoryStorageService(const DOMElement* e); virtual ~MemoryStorageService(); + const Capabilities& getCapabilities() const { + return g_memCaps; + } + bool createString(const char* context, const char* key, const char* value, time_t expiration); int readString(const char* context, const char* key, string* pvalue=nullptr, time_t* pexpiration=nullptr, int version=0); int updateString(const char* context, const char* key, const char* value=nullptr, time_t expiration=0, int version=0); diff --git a/xmltooling/util/ReplayCache.cpp b/xmltooling/util/ReplayCache.cpp index 63eb26a..a457cb4 100644 --- a/xmltooling/util/ReplayCache.cpp +++ b/xmltooling/util/ReplayCache.cpp @@ -25,16 +25,19 @@ */ #include "internal.h" +#include "logging.h" +#include "security/SecurityHelper.h" #include "util/ReplayCache.h" -#include "util/StorageService.h" +using namespace xmltooling::logging; using namespace xmltooling; using namespace std; -ReplayCache::ReplayCache(StorageService* storage) : m_owned(storage==nullptr), m_storage(storage) +ReplayCache::ReplayCache(StorageService* storage) + : m_owned(storage==nullptr), + m_storage(storage ? storage : XMLToolingConfig::getConfig().StorageServiceManager.newPlugin(MEMORY_STORAGE_SERVICE, nullptr)), + m_storageCaps(m_storage->getCapabilities()) { - if (!m_storage) - m_storage = XMLToolingConfig::getConfig().StorageServiceManager.newPlugin(MEMORY_STORAGE_SERVICE, nullptr); } ReplayCache::~ReplayCache() @@ -45,6 +48,30 @@ ReplayCache::~ReplayCache() bool ReplayCache::check(const char* context, const char* s, time_t expires) { + if (strlen(context) > m_storageCaps.getContextSize()) { + // This is a design/coding failure. + Category::getInstance(XMLTOOLING_LOGCAT".ReplayCache").error( + "context (%s) too long for StorageService (limit %u)", context, m_storageCaps.getContextSize() + ); + return false; + } + else if (strlen(s) > m_storageCaps.getKeySize()) { + // This is something to work around with a hash. +#ifndef XMLTOOLING_NO_XMLSEC + string h = SecurityHelper::doHash("SHA1", s, strlen(s)); + // In storage already? + if (m_storage->readString(context, h.c_str())) + return false; + m_storage->createString(context, h.c_str(), "x", expires); + return true; +#else + Category::getInstance(XMLTOOLING_LOGCAT".ReplayCache").error( + "key (%s) too long for StorageService (limit %u)", s, m_storageCaps.getKeySize() + ); + return false; +#endif + } + // In storage already? if (m_storage->readString(context, s)) return false; diff --git a/xmltooling/util/ReplayCache.h b/xmltooling/util/ReplayCache.h index 6c95ee7..c0fdf29 100644 --- a/xmltooling/util/ReplayCache.h +++ b/xmltooling/util/ReplayCache.h @@ -28,6 +28,7 @@ #define __xmltooling_replay_h__ #include +#include namespace xmltooling { @@ -74,6 +75,7 @@ namespace xmltooling { private: bool m_owned; StorageService* m_storage; + const StorageService::Capabilities& m_storageCaps; }; }; diff --git a/xmltooling/util/StorageService.cpp b/xmltooling/util/StorageService.cpp index 42266b1..a9f3f36 100644 --- a/xmltooling/util/StorageService.cpp +++ b/xmltooling/util/StorageService.cpp @@ -30,6 +30,10 @@ using namespace xmltooling; using namespace std; +namespace { + static const XMLTOOL_DLLLOCAL StorageService::Capabilities g_ssCaps(255, 255, 255); +}; + namespace xmltooling { XMLTOOL_DLLLOCAL PluginManager::Factory MemoryStorageServiceFactory; }; @@ -47,3 +51,32 @@ StorageService::StorageService() StorageService::~StorageService() { } + +const StorageService::Capabilities& StorageService::getCapabilities() const +{ + return g_ssCaps; +} + +StorageService::Capabilities::Capabilities(unsigned int contextSize, unsigned int keySize, unsigned int stringSize) + : m_contextSize(contextSize), m_keySize(keySize), m_stringSize(stringSize) +{ +} + +StorageService::Capabilities::~Capabilities() +{ +} + +unsigned int StorageService::Capabilities::getContextSize() const +{ + return m_contextSize; +} + +unsigned int StorageService::Capabilities::getKeySize() const +{ + return m_keySize; +} + +unsigned int StorageService::Capabilities::getStringSize() const +{ + return m_stringSize; +} diff --git a/xmltooling/util/StorageService.h b/xmltooling/util/StorageService.h index 8bbe681..01c17f2 100644 --- a/xmltooling/util/StorageService.h +++ b/xmltooling/util/StorageService.h @@ -42,19 +42,65 @@ namespace xmltooling { * Keys need to be unique only within a given context, so multiple * components can share a single storage service safely as long as they * use different labels. + * + *

The allowable sizes for contexts, keys, and short values can vary + * and be reported by the implementation to callers, but MUST be at least + * 255 bytes. */ class XMLTOOL_API StorageService { MAKE_NONCOPYABLE(StorageService); public: virtual ~StorageService(); + + class XMLTOOL_API Capabilities { + MAKE_NONCOPYABLE(Capabilities); + unsigned int m_contextSize, m_keySize, m_stringSize; + public: + /** + * Constructor. + * + * @param contextSize max size of context labels in characters + * @param keysize max size of keys in characters + * @param stringSize max size of string values in characters + */ + Capabilities(unsigned int contextSize, unsigned int keySize, unsigned int stringSize); + ~Capabilities(); + + /** + * Returns max size of context labels in characters + * @return max size of context labels in characters + */ + unsigned int getContextSize() const; + + /** + * Returns max size of keys in characters + * @return max size of keys in characters + */ + unsigned int getKeySize() const; + + /** + * Returns max size of string values in characters + * @return max size of string values in characters + */ + unsigned int getStringSize() const; + }; /** + * Returns the capabilities of the underlying service. + *

If implementations support only the 255 character minimum, the default + * implementation of this method will suffice. + * + * @return a reference to an interface to access the service's capabilities + */ + virtual const Capabilities& getCapabilities() const; + + /** * Creates a new "short" record in the storage service. * - * @param context a storage context label of up to 255 bytes - * @param key null-terminated unique key of up to 255 bytes - * @param value null-terminated value of up to 255 bytes to store + * @param context a storage context label + * @param key null-terminated unique key + * @param value null-terminated value * @param expiration an expiration timestamp, after which the record can be purged * @return true iff record was inserted, false iff a duplicate was found * @@ -67,8 +113,8 @@ namespace xmltooling { * *

The version parameter can be set for "If-Modified-Since" semantics. * - * @param context a storage context label of up to 255 bytes - * @param key null-terminated unique key of up to 255 bytes + * @param context a storage context label + * @param key null-terminated unique key * @param pvalue location in which to return the record value * @param pexpiration location in which to return the expiration timestamp * @param version if > 0, only copy back data if newer than supplied version @@ -83,9 +129,9 @@ namespace xmltooling { /** * Updates an existing "short" record in the storage service. * - * @param context a storage context label of up to 255 bytes - * @param key null-terminated unique key of up to 255 bytes - * @param value null-terminated value of up to 255 bytes to store, or nullptr to leave alone + * @param context a storage context label + * @param key null-terminated unique key + * @param value null-terminated value to store, or nullptr to leave alone * @param expiration a new expiration timestamp, or 0 to leave alone * @param version if > 0, only update if the current version matches this value * @return the version of the record after update, 0 if no record exists, or -1 if the version @@ -100,8 +146,8 @@ namespace xmltooling { /** * Deletes an existing "short" record from the storage service. * - * @param context a storage context label of up to 255 bytes - * @param key null-terminated unique key of up to 255 bytes + * @param context a storage context label + * @param key null-terminated unique key * @return true iff the record existed and was deleted * * @throws IOException raised if errors occur in the deletion process @@ -111,8 +157,8 @@ namespace xmltooling { /** * Creates a new "long" record in the storage service. * - * @param context a storage context label of up to 255 bytes - * @param key null-terminated unique key of up to 255 bytes + * @param context a storage context label + * @param key null-terminated unique key * @param value null-terminated value of arbitrary length * @param expiration an expiration timestamp, after which the record can be purged * @return true iff record was inserted, false iff a duplicate was found @@ -126,8 +172,8 @@ namespace xmltooling { * *

The version parameter can be set for "If-Modified-Since" semantics. * - * @param context a storage context label of up to 255 bytes - * @param key null-terminated unique key of up to 255 bytes + * @param context a storage context label + * @param key null-terminated unique key * @param pvalue location in which to return the record value * @param pexpiration location in which to return the expiration timestamp * @param version if > 0, only copy back data if newer than supplied version @@ -142,8 +188,8 @@ namespace xmltooling { /** * Updates an existing "long" record in the storage service. * - * @param context a storage context label of up to 255 bytes - * @param key null-terminated unique key of up to 255 bytes + * @param context a storage context label + * @param key null-terminated unique key * @param value null-terminated value of arbitrary length to store, or nullptr to leave alone * @param expiration a new expiration timestamp, or 0 to leave alone * @param version if > 0, only update if the current version matches this value @@ -159,8 +205,8 @@ namespace xmltooling { /** * Deletes an existing "long" record from the storage service. * - * @param context a storage context label of up to 255 bytes - * @param key null-terminated unique key of up to 255 bytes + * @param context a storage context label + * @param key null-terminated unique key * @return true iff the record existed and was deleted * * @throws IOException raised if errors occur in the deletion process -- 2.1.4