enh(Net): Poco::Net::HTTPResponse: add replaceCookie() and removeCookie() #4825

This commit is contained in:
Günter Obiltschnig 2024-12-19 10:46:06 +01:00
parent 3f76ad60c3
commit 854d8c89d6
6 changed files with 172 additions and 32 deletions

View File

@ -178,6 +178,15 @@ public:
/// 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<HTTPCookie>& cookies) const;
/// Returns a vector with all the cookies
/// set in the response header.

View File

@ -91,14 +91,26 @@ public:
/// 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 @@ public:
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 it.
/// 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 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

View File

@ -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<HTTPCookie>& cookies) const
{
cookies.clear();

View File

@ -14,6 +14,7 @@
#include "Poco/Net/NameValueCollection.h"
#include "Poco/Exception.h"
#include "Poco/String.h"
#include <algorithm>
@ -121,42 +122,18 @@ 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
{
return _map.size();
}
void NameValueCollection::erase(const std::string& name)
{
_map.erase(name);
}
void NameValueCollection::erase(Iterator it)
{
_map.erase(it);
}
void NameValueCollection::secureErase(const std::string& name)
{
Iterator it = _map.find(name);
@ -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();

View File

@ -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<HTTPCookie> 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<HTTPCookie> 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;
}

View File

@ -33,6 +33,8 @@ public:
void testInvalid2();
void testInvalid3();
void testCookies();
void testReplaceCookie();
void testRemoveCookie();
void setUp();
void tearDown();