Skip to content

Commit 83effe3

Browse files
committed
add URLSearchParams::to_raw_string() method
1 parent 2c8cfc8 commit 83effe3

File tree

6 files changed

+126
-0
lines changed

6 files changed

+126
-0
lines changed

include/ada/url_search_params-inl.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,23 @@ inline std::string url_search_params::to_string() const {
134134
return out;
135135
}
136136

137+
inline std::string url_search_params::to_raw_string() const {
138+
auto character_set = ada::character_sets::QUERY_PERCENT_ENCODE;
139+
std::string out{};
140+
for (size_t i = 0; i < params.size(); i++) {
141+
auto key = ada::unicode::percent_encode(params[i].first, character_set);
142+
auto value = ada::unicode::percent_encode(params[i].second, character_set);
143+
144+
if (i != 0) {
145+
out += "&";
146+
}
147+
out.append(key);
148+
out += "=";
149+
out.append(value);
150+
}
151+
return out;
152+
}
153+
137154
inline void url_search_params::set(const std::string_view key,
138155
const std::string_view value) {
139156
const auto find = [&key](const auto &param) { return param.first == key; };

include/ada/url_search_params.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,13 @@ struct url_search_params {
100100
*/
101101
inline std::string to_string() const;
102102

103+
/**
104+
* Returns a serialized query string without normalizing the key-value pairs.
105+
* Unlike to_string(), this method does not apply additional transformations
106+
* to the percent-encoded output.
107+
*/
108+
inline std::string to_raw_string() const;
109+
103110
/**
104111
* Returns a simple JS-style iterator over all of the keys in this
105112
* url_search_params. The keys in the iterator are not unique. The valid

include/ada_c.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ void ada_free_search_params(ada_url_search_params result);
130130
size_t ada_search_params_size(ada_url_search_params result);
131131
void ada_search_params_sort(ada_url_search_params result);
132132
ada_owned_string ada_search_params_to_string(ada_url_search_params result);
133+
ada_owned_string ada_search_params_to_raw_string(ada_url_search_params result);
133134

134135
void ada_search_params_append(ada_url_search_params result, const char* key,
135136
size_t key_length, const char* value,

src/ada_c.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,18 @@ ada_owned_string ada_search_params_to_string(ada_url_search_params result) {
487487
return owned;
488488
}
489489

490+
ada_owned_string ada_search_params_to_raw_string(ada_url_search_params result) {
491+
ada::result<ada::url_search_params>& r =
492+
*(ada::result<ada::url_search_params>*)result;
493+
if (!r) return ada_owned_string{nullptr, 0};
494+
std::string out = r->to_raw_string();
495+
ada_owned_string owned{};
496+
owned.length = out.size();
497+
owned.data = new char[owned.length];
498+
memcpy((void*)owned.data, out.data(), owned.length);
499+
return owned;
500+
}
501+
490502
size_t ada_search_params_size(ada_url_search_params result) {
491503
ada::result<ada::url_search_params>& r =
492504
*(ada::result<ada::url_search_params>*)result;

tests/ada_c.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,49 @@ TEST(ada_c, ada_url_search_params) {
357357
SUCCEED();
358358
}
359359

360+
TEST(ada_c, ada_search_params_to_raw_string) {
361+
std::string input("a=b c&d=e+f");
362+
auto out = ada_parse_search_params(input.c_str(), input.length());
363+
364+
// Note: + in input is decoded to space during parsing
365+
// to_string normalizes spaces to +
366+
ada_owned_string str = ada_search_params_to_string(out);
367+
ASSERT_EQ(convert_string(str), "a=b+c&d=e+f");
368+
ada_free_owned_string(str);
369+
370+
// to_raw_string preserves %20 encoding for spaces
371+
ada_owned_string raw_str = ada_search_params_to_raw_string(out);
372+
ASSERT_EQ(convert_string(raw_str), "a=b%20c&d=e%20f");
373+
ada_free_owned_string(raw_str);
374+
375+
ada_free_search_params(out);
376+
377+
SUCCEED();
378+
}
379+
380+
TEST(ada_c, ada_search_params_to_raw_string_remove_preserves_encoding) {
381+
// Test the exact scenario from the issue
382+
std::string input("a=%20&b=remove&c=2");
383+
auto params = ada_parse_search_params(input.c_str(), input.length());
384+
385+
// Remove parameter "b"
386+
ada_search_params_remove(params, "b", 1);
387+
388+
// to_string normalizes space to +
389+
ada_owned_string str = ada_search_params_to_string(params);
390+
ASSERT_EQ(convert_string(str), "a=+&c=2");
391+
ada_free_owned_string(str);
392+
393+
// to_raw_string preserves %20 encoding for spaces
394+
ada_owned_string raw_str = ada_search_params_to_raw_string(params);
395+
ASSERT_EQ(convert_string(raw_str), "a=%20&c=2");
396+
ada_free_owned_string(raw_str);
397+
398+
ada_free_search_params(params);
399+
400+
SUCCEED();
401+
}
402+
360403
TEST(ada_c, ada_get_version) {
361404
std::string_view raw = ada_get_version();
362405
ada_version_components parsed = ada_get_version_components();

tests/url_search_params.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,3 +448,49 @@ TEST(url_search_params, sort_unicode_code_units_edge_case) {
448448
ASSERT_EQ(keys.next(), "\xf0\x9f\x8c\x88\xef\xac\x83");
449449
SUCCEED();
450450
}
451+
452+
TEST(url_search_params, to_raw_string_no_normalization) {
453+
auto params = ada::url_search_params();
454+
params.append("a", "b c");
455+
// to_string normalizes space to +
456+
ASSERT_EQ(params.to_string(), "a=b+c");
457+
// to_raw_string preserves %20 encoding
458+
ASSERT_EQ(params.to_raw_string(), "a=b%20c");
459+
SUCCEED();
460+
}
461+
462+
TEST(url_search_params, to_raw_string_with_special_chars) {
463+
auto params = ada::url_search_params();
464+
params.append("key1", "value with spaces");
465+
params.append("key2", "another value");
466+
// to_string normalizes spaces to +
467+
ASSERT_EQ(params.to_string(), "key1=value+with+spaces&key2=another+value");
468+
// to_raw_string preserves %20 encoding
469+
ASSERT_EQ(params.to_raw_string(),
470+
"key1=value%20with%20spaces&key2=another%20value");
471+
SUCCEED();
472+
}
473+
474+
TEST(url_search_params, to_raw_string_with_accents) {
475+
auto params = ada::url_search_params();
476+
params.append("key1", "\u00E9t\u00E9");
477+
params.append("key2", "C\u00E9line Dion++");
478+
// Both should encode accents the same way
479+
// to_string normalizes spaces to +, to_raw_string uses %20
480+
// Note: + signs are not encoded by QUERY_PERCENT_ENCODE
481+
ASSERT_EQ(params.to_string(),
482+
"key1=%C3%A9t%C3%A9&key2=C%C3%A9line+Dion%2B%2B");
483+
ASSERT_EQ(params.to_raw_string(),
484+
"key1=%C3%A9t%C3%A9&key2=C%C3%A9line%20Dion++");
485+
SUCCEED();
486+
}
487+
488+
TEST(url_search_params, to_raw_string_empty_values) {
489+
auto params = ada::url_search_params();
490+
params.append("a", "");
491+
params.append("", "b");
492+
params.append("", "");
493+
ASSERT_EQ(params.to_raw_string(), "a=&=b&=");
494+
ASSERT_EQ(params.to_string(), "a=&=b&=");
495+
SUCCEED();
496+
}

0 commit comments

Comments
 (0)