improved URI documentation regarding setQuery()/getQuery(); added getQueryParameters()/setQueryParameters()

This commit is contained in:
Günter Obiltschnig 2014-11-19 10:38:59 +01:00
parent 4b53f137de
commit a417d49d5d
4 changed files with 151 additions and 6 deletions

View File

@ -22,6 +22,7 @@
#include "Poco/Foundation.h"
#include <vector>
#include <utility>
namespace Poco {
@ -40,11 +41,13 @@ class Foundation_API URI
///
/// The class automatically performs a few normalizations on
/// all URIs and URI parts passed to it:
/// * scheme identifiers are converted to lower case.
/// * scheme identifiers are converted to lower case
/// * percent-encoded characters are decoded
/// * optionally, dot segments are removed from paths (see normalize())
{
public:
typedef std::vector<std::pair<std::string, std::string> > QueryParameters;
URI();
/// Creates an empty URI.
@ -159,10 +162,30 @@ public:
/// Sets the path part of the URI.
std::string getQuery() const;
/// Returns the query part of the URI.
/// Returns the decoded query part of the URI.
///
/// Note that encoded ampersand characters ('&', "%26")
/// will be decoded, which could cause ambiguities if the query
/// string contains multiple parameters and a parameter name
/// or value contains an ampersand as well.
/// In such a case it's better to use getRawQuery() or
/// getQueryParameters().
void setQuery(const std::string& query);
/// Sets the query part of the URI.
///
/// The query string will be percent-encoded. If the query
/// already contains percent-encoded characters, these
/// will be double-encoded, which is probably not what's
/// intended by the caller. Furthermore, ampersand ('&')
/// characters in the query will not be encoded. This could
/// lead to ambiguity issues if the query string contains multiple
/// name-value parameters separated by ampersand, and if any
/// name or value also contains an ampersand. In such a
/// case, it's better to use setRawQuery() with a properly
/// percent-encoded query string, or use addQueryParameter()
/// or setQueryParameters(), which take care of appropriate
/// percent encoding of parameter names and values.
void addQueryParameter(const std::string& param, const std::string& val = "");
/// Adds "param=val" to the query; "param" may not be empty.
@ -172,11 +195,24 @@ public:
/// if found in param or val.
const std::string& getRawQuery() const;
/// Returns the unencoded query part of the URI.
/// Returns the query string in raw form, which usually
/// means percent encoded.
void setRawQuery(const std::string& query);
/// Sets the query part of the URI.
///
/// The given query string must be properly percent-encoded.
QueryParameters getQueryParameters() const;
/// Returns the decoded query string parameters as a vector
/// of name-value pairs.
void setQueryParameters(const QueryParameters& params);
/// Sets the query part of the URI from a vector
/// of query parameters.
///
/// Calls addQueryParameter() for each parameter name and value.
const std::string& getFragment() const;
/// Returns the fragment part of the URI.
@ -246,6 +282,7 @@ public:
/// URI-decodes the given string by replacing percent-encoded
/// characters with the actual character. The decoded string
/// is appended to decodedStr.
///
/// When plusAsSpace is true, non-encoded plus signs in the query are decoded as spaces.
/// (http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1)

View File

@ -26,7 +26,7 @@ namespace Poco {
const std::string URI::RESERVED_PATH = "?#";
const std::string URI::RESERVED_QUERY = "#/";
const std::string URI::RESERVED_QUERY = "?#/";
const std::string URI::RESERVED_FRAGMENT = "";
const std::string URI::ILLEGAL = "%<>{}|\\\"^`";
@ -335,9 +335,9 @@ void URI::addQueryParameter(const std::string& param, const std::string& val)
{
std::string reserved(RESERVED_QUERY);
reserved += "=&";
if (!_query.empty()) _query.append(1, '&');
if (!_query.empty()) _query += '&';
encode(param, reserved, _query);
_query.append(1, '=');
_query += '=';
encode(val, reserved, _query);
}
@ -350,6 +350,56 @@ std::string URI::getQuery() const
}
URI::QueryParameters URI::getQueryParameters() const
{
QueryParameters result;
std::string::const_iterator it(_query.begin());
std::string::const_iterator end(_query.end());
while (it != end)
{
std::string name;
std::string value;
while (it != end && *it != '=' && *it != '&')
{
if (*it == '+')
name += ' ';
else
name += *it;
++it;
}
if (it != end && *it == '=')
{
++it;
while (it != end && *it != '&')
{
if (*it == '+')
value += ' ';
else
value += *it;
++it;
}
}
std::string decodedName;
std::string decodedValue;
URI::decode(name, decodedName);
URI::decode(value, decodedValue);
result.push_back(std::make_pair(decodedName, decodedValue));
if (it != end && *it == '&') ++it;
}
return result;
}
void URI::setQueryParameters(const QueryParameters& params)
{
_query.clear();
for (QueryParameters::const_iterator it = params.begin(); it != params.end(); ++it)
{
addQueryParameter(it->first, it->second);
}
}
void URI::setFragment(const std::string& fragment)
{
_fragment.clear();

View File

@ -720,6 +720,7 @@ void URITest::testSwap()
assert (uri2.toString() == "http://www.appinf.com/search.cgi?keyword=test%20encoded&scope=all#result");
}
void URITest::testOther()
{
// The search string is "hello%world"; google happens to ignore the '%'
@ -735,6 +736,18 @@ void URITest::testOther()
assert(uri.toString() == "http://google.com/search?q=hello%25world#frag%20ment");
assert(uri.getPathEtc() == "/search?q=hello%25world#frag%20ment");
uri.setQuery("q=foo&bar");
assert(uri.getQuery() == "q=foo&bar");
assert(uri.getRawQuery() == "q=foo&bar");
assert(uri.toString() == "http://google.com/search?q=foo&bar#frag%20ment");
assert(uri.getPathEtc() == "/search?q=foo&bar#frag%20ment");
uri.setQuery("q=foo/bar");
assert(uri.getQuery() == "q=foo/bar");
assert(uri.getRawQuery() == "q=foo%2Fbar");
assert(uri.toString() == "http://google.com/search?q=foo%2Fbar#frag%20ment");
assert(uri.getPathEtc() == "/search?q=foo%2Fbar#frag%20ment");
uri.setQuery("q=goodbye cruel world");
assert(uri.getQuery() == "q=goodbye cruel world");
assert(uri.getRawQuery() == "q=goodbye%20cruel%20world");
@ -753,6 +766,15 @@ void URITest::testOther()
uri.addQueryParameter("pa=ra&m2", "val&ue");
assert(uri.getRawQuery() == "q=pony%7eride&pa%3Dra%26m1=&pa%3Dra%26m2=val%26ue");
assert(uri.getQuery() == "q=pony~ride&pa=ra&m1=&pa=ra&m2=val&ue");
uri = "http://google.com/search?q=hello+world#frag%20ment";
assert(uri.getHost() == "google.com");
assert(uri.getPath() == "/search");
assert(uri.getQuery() == "q=hello+world");
assert(uri.getRawQuery() == "q=hello+world");
assert(uri.getFragment() == "frag ment");
assert(uri.toString() == "http://google.com/search?q=hello+world#frag%20ment");
assert(uri.getPathEtc() == "/search?q=hello+world#frag%20ment");
}
@ -792,6 +814,40 @@ void URITest::testFromPath()
}
void URITest::testQueryParameters()
{
Poco::URI uri("http://google.com/search?q=hello+world&client=safari");
URI::QueryParameters params = uri.getQueryParameters();
assert (params.size() == 2);
assert (params[0].first == "q");
assert (params[0].second == "hello world");
assert (params[1].first == "client");
assert (params[1].second == "safari");
uri.setQueryParameters(params);
assert (uri.toString() == "http://google.com/search?q=hello%20world&client=safari");
uri = "http://google.com/search?q=&client&";
params = uri.getQueryParameters();
assert (params.size() == 2);
assert (params[0].first == "q");
assert (params[0].second == "");
assert (params[1].first == "client");
assert (params[1].second == "");
uri.setQueryParameters(params);
assert (uri.toString() == "http://google.com/search?q=&client=");
params[0].second = "foo/bar?";
uri.setQueryParameters(params);
assert (uri.toString() == "http://google.com/search?q=foo%2Fbar%3F&client=");
params[0].second = "foo&bar";
uri.setQueryParameters(params);
assert (uri.toString() == "http://google.com/search?q=foo%26bar&client=");
}
void URITest::setUp()
{
}
@ -816,6 +872,7 @@ CppUnit::Test* URITest::suite()
CppUnit_addTest(pSuite, URITest, testEncodeDecode);
CppUnit_addTest(pSuite, URITest, testOther);
CppUnit_addTest(pSuite, URITest, testFromPath);
CppUnit_addTest(pSuite, URITest, testQueryParameters);
return pSuite;
}

View File

@ -36,6 +36,7 @@ public:
void testEncodeDecode();
void testOther();
void testFromPath();
void testQueryParameters();
void setUp();
void tearDown();