diff --git a/Net/include/Poco/Net/HTTPResponse.h b/Net/include/Poco/Net/HTTPResponse.h index de280e6d41..224ad95886 100644 --- a/Net/include/Poco/Net/HTTPResponse.h +++ b/Net/include/Poco/Net/HTTPResponse.h @@ -178,6 +178,15 @@ class Net_API HTTPResponse: public HTTPMessage /// Adds the cookie to the response by /// adding a Set-Cookie header. + void removeCookie(const std::string& cookieName); + /// Removes the Set-Cookie header for the cookie with the given name, + /// if the header is present. Otherwise does nothing. + + void replaceCookie(const HTTPCookie& cookie); + /// Replaces a Set-Cookie header for the given cookie with the + /// updated cookie, or adds a new Set-Cookie header of none + /// is present for the given cookie. + void getCookies(std::vector& cookies) const; /// Returns a vector with all the cookies /// set in the response header. diff --git a/Net/include/Poco/Net/NameValueCollection.h b/Net/include/Poco/Net/NameValueCollection.h index 5f5ad2c37a..d5e07228ff 100644 --- a/Net/include/Poco/Net/NameValueCollection.h +++ b/Net/include/Poco/Net/NameValueCollection.h @@ -91,14 +91,26 @@ class Net_API NameValueCollection /// Returns an iterator pointing to the first name-value pair /// with the given name. + Iterator find(const std::string& name); + /// Returns an iterator pointing to the first name-value pair + /// with the given name. + ConstIterator begin() const; /// Returns an iterator pointing to the begin of /// the name-value pair collection. + Iterator begin(); + /// Returns an iterator pointing to the begin of + /// the name-value pair collection. + ConstIterator end() const; /// Returns an iterator pointing to the end of /// the name-value pair collection. + Iterator end(); + /// Returns an iterator pointing to the end of + /// the name-value pair collection. + bool empty() const; /// Returns true iff the header does not have any content. @@ -109,10 +121,18 @@ class Net_API NameValueCollection void erase(const std::string& name); /// Removes all name-value pairs with the given name. + void erase(Iterator it); + /// Removes the name-value pair referenced by the given iterator. + void secureErase(const std::string& name); - /// Securely erases all name-value pairs with the given name + /// Securely erases all name-value pairs with the given name, + /// by first overwriting the value with zeroes before + /// removing the value. + + void secureErase(Iterator it); + /// Securely erases the name-value pair referenced by the given iterator, /// by first overwriting the value with zeroes before - /// removing it. + /// removing the value. void clear(); /// Removes all name-value pairs and their values. @@ -135,6 +155,54 @@ inline void swap(NameValueCollection& nvc1, NameValueCollection& nvc2) noexcept } +inline NameValueCollection::ConstIterator NameValueCollection::find(const std::string& name) const +{ + return _map.find(name); +} + + +inline NameValueCollection::Iterator NameValueCollection::find(const std::string& name) +{ + return _map.find(name); +} + + +inline NameValueCollection::ConstIterator NameValueCollection::begin() const +{ + return _map.begin(); +} + + +inline NameValueCollection::Iterator NameValueCollection::begin() +{ + return _map.begin(); +} + + +inline NameValueCollection::ConstIterator NameValueCollection::end() const +{ + return _map.end(); +} + + +inline NameValueCollection::Iterator NameValueCollection::end() +{ + return _map.end(); +} + + +inline bool NameValueCollection::empty() const +{ + return _map.empty(); +} + + +inline std::size_t NameValueCollection::size() const +{ + return _map.size(); +} + + } } // namespace Poco::Net diff --git a/Net/src/HTTPResponse.cpp b/Net/src/HTTPResponse.cpp index 07496e46d2..837c1f2cd2 100644 --- a/Net/src/HTTPResponse.cpp +++ b/Net/src/HTTPResponse.cpp @@ -217,6 +217,40 @@ void HTTPResponse::addCookie(const HTTPCookie& cookie) } +void HTTPResponse::removeCookie(const std::string& cookieName) +{ + NameValueCollection::Iterator it = find(SET_COOKIE); + while (it != end() && Poco::icompare(it->first, SET_COOKIE) == 0) + { + const std::string& hv = it->second; + if (hv.size() > cookieName.size() && hv[cookieName.size()] == '=' && hv.compare(0, cookieName.size(), cookieName) == 0) + { + erase(it); + break; + } + ++it; + } +} + + +void HTTPResponse::replaceCookie(const HTTPCookie& cookie) +{ + const std::string& cookieName = cookie.getName(); + NameValueCollection::Iterator it = find(SET_COOKIE); + while (it != end() && Poco::icompare(it->first, SET_COOKIE) == 0) + { + const std::string& hv = it->second; + if (hv.size() > cookieName.size() && hv[cookieName.size()] == '=' && hv.compare(0, cookieName.size(), cookieName) == 0) + { + it->second = cookie.toString(); + return; + } + ++it; + } + add(SET_COOKIE, cookie.toString()); +} + + void HTTPResponse::getCookies(std::vector& cookies) const { cookies.clear(); diff --git a/Net/src/NameValueCollection.cpp b/Net/src/NameValueCollection.cpp index 10e657f97b..4b64328018 100644 --- a/Net/src/NameValueCollection.cpp +++ b/Net/src/NameValueCollection.cpp @@ -14,6 +14,7 @@ #include "Poco/Net/NameValueCollection.h" #include "Poco/Exception.h" +#include "Poco/String.h" #include @@ -121,39 +122,15 @@ bool NameValueCollection::has(const std::string& name) const } -NameValueCollection::ConstIterator NameValueCollection::find(const std::string& name) const -{ - return _map.find(name); -} - - -NameValueCollection::ConstIterator NameValueCollection::begin() const -{ - return _map.begin(); -} - - -NameValueCollection::ConstIterator NameValueCollection::end() const -{ - return _map.end(); -} - - -bool NameValueCollection::empty() const -{ - return _map.empty(); -} - - -std::size_t NameValueCollection::size() const +void NameValueCollection::erase(const std::string& name) { - return _map.size(); + _map.erase(name); } -void NameValueCollection::erase(const std::string& name) +void NameValueCollection::erase(Iterator it) { - _map.erase(name); + _map.erase(it); } @@ -169,6 +146,13 @@ void NameValueCollection::secureErase(const std::string& name) } +void NameValueCollection::secureErase(Iterator it) +{ + Poco::secureClear(it->second); + _map.erase(it); +} + + void NameValueCollection::clear() { _map.clear(); diff --git a/Net/testsuite/src/HTTPResponseTest.cpp b/Net/testsuite/src/HTTPResponseTest.cpp index 7844547cef..f28ec40e2b 100644 --- a/Net/testsuite/src/HTTPResponseTest.cpp +++ b/Net/testsuite/src/HTTPResponseTest.cpp @@ -201,6 +201,47 @@ void HTTPResponseTest::testCookies() } +void HTTPResponseTest::testReplaceCookie() +{ + HTTPResponse response; + HTTPCookie cookie1("cookie1", "value1"); + response.replaceCookie(cookie1); // cookie does not exist, will add cookie + std::vector cookies; + response.getCookies(cookies); + assertTrue (cookies.size() == 1); + assertTrue (cookie1.getName() == cookies[0].getName()); + assertTrue (cookie1.getValue() == cookies[0].getValue()); + + HTTPCookie cookie1new("cookie1", "value2"); + response.replaceCookie(cookie1new); + cookies.clear(); + response.getCookies(cookies); + assertTrue (cookies.size() == 1); + assertTrue (cookie1new.getName() == cookies[0].getName()); + assertTrue (cookie1new.getValue() == cookies[0].getValue()); +} + + +void HTTPResponseTest::testRemoveCookie() +{ + HTTPResponse response; + HTTPCookie cookie1("cookie1", "value1"); + response.addCookie(cookie1); + std::vector cookies; + response.getCookies(cookies); + assertTrue (cookies.size() == 1); + assertTrue (cookie1.getName() == cookies[0].getName()); + assertTrue (cookie1.getValue() == cookies[0].getValue()); + + response.removeCookie("cookie1"); + cookies.clear(); + response.getCookies(cookies); + assertTrue (cookies.size() == 0); + + response.removeCookie("cookie2"); // should do nothing +} + + void HTTPResponseTest::setUp() { } @@ -224,6 +265,8 @@ CppUnit::Test* HTTPResponseTest::suite() CppUnit_addTest(pSuite, HTTPResponseTest, testInvalid2); CppUnit_addTest(pSuite, HTTPResponseTest, testInvalid3); CppUnit_addTest(pSuite, HTTPResponseTest, testCookies); + CppUnit_addTest(pSuite, HTTPResponseTest, testReplaceCookie); + CppUnit_addTest(pSuite, HTTPResponseTest, testRemoveCookie); return pSuite; } diff --git a/Net/testsuite/src/HTTPResponseTest.h b/Net/testsuite/src/HTTPResponseTest.h index 7e4258655a..6bf32481b0 100644 --- a/Net/testsuite/src/HTTPResponseTest.h +++ b/Net/testsuite/src/HTTPResponseTest.h @@ -33,6 +33,8 @@ class HTTPResponseTest: public CppUnit::TestCase void testInvalid2(); void testInvalid3(); void testCookies(); + void testReplaceCookie(); + void testRemoveCookie(); void setUp(); void tearDown();