Skip to content

Commit

Permalink
REST: Added iterateURLQueries() fn
Browse files Browse the repository at this point in the history
  • Loading branch information
snej committed Aug 29, 2024
1 parent 5be8e84 commit 3e0870a
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 27 deletions.
50 changes: 24 additions & 26 deletions REST/netUtils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,8 @@
#include "NumConversion.hh"
#include <cassert>
#include <ctime>
// 'digittoint' function
#include "StringUtil.hh"
#ifndef __APPLE__
# include "StringUtil.hh"
# include "PlatformIO.hh"
#endif

Expand Down Expand Up @@ -75,32 +74,31 @@ namespace litecore::REST {
return result;
}

string getURLQueryParam(slice queries, const char* name, char delimiter, size_t occurrence) {
auto data = (const char*)queries.buf;
size_t data_len = queries.size;
const char* end = data + data_len;

string dst;
if ( data == nullptr || name == nullptr || data_len == 0 ) { return dst; }
size_t name_len = strlen(name);

// data is "var1=val1&var2=val2...". Find variable first
for ( const char* p = data; p + name_len < end; p++ ) {
if ( (p == data || p[-1] == delimiter) && p[name_len] == '=' && !strncasecmp(name, p, name_len)
&& 0 == occurrence-- ) {
// Point p to variable value
p += name_len + 1;

// Point s to the end of the value
const char* s = (const char*)memchr(p, delimiter, (size_t)(end - p));
if ( s == nullptr ) { s = end; }
assert(s >= p);
bool iterateURLQueries(string_view queries, char delimiter, function_ref<bool(string_view,string_view)> callback) {
bool stop = false;
split(queries, string_view{&delimiter, 1}, [&](string_view query) {
if (!stop) {
string value;
if (auto eq = query.find('='); eq != string::npos) {
value = query.substr(eq + 1);
query = query.substr(0, eq);
}
stop = callback(query, value);
}
});
return stop;
}

// Decode variable into destination buffer
return URLDecode(slice(p, s - p), true);
string getURLQueryParam(slice queries, string_view name, char delimiter, size_t occurrence) {
string value;
iterateURLQueries(queries, delimiter, [&](string_view k, string_view v) -> bool {
if (name.size() == k.size() && 0 == strncasecmp(name.data(), k.data(), k.size()) && 0 == occurrence--) {
value = URLDecode(v);
return true; // stop iteration
}
}
return dst;
return false;
});
return value;
}

} // namespace litecore::REST
Expand Down
14 changes: 13 additions & 1 deletion REST/netUtils.hh
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//

#pragma once
#include "fleece/function_ref.hh"
#include "fleece/slice.hh"

namespace litecore::REST {
Expand All @@ -19,6 +20,17 @@ namespace litecore::REST {

std::string URLEncode(fleece::slice str);

std::string getURLQueryParam(fleece::slice queries, const char* name, char delimiter = '&', size_t occurrence = 0);
/// Gets a URL query parameter by name. The returned value is URL-decoded.
std::string getURLQueryParam(fleece::slice queries, std::string_view name, char delimiter = '&', size_t occurrence = 0);

/// Calls the callback with the name and (raw) value of each query parameter.
/// @param queries The query string (without the initial '?')
/// @param delimiter The character separating queries, usually '&'
/// @param callback A function that will be passed the name and (raw) value.
/// You need to call \ref URLDecode to decode the value.
/// Return `false` to continue the iteration, `true` to stop.
/// @returns true if the callback stopped the iteration, else false.
bool iterateURLQueries(std::string_view queries, char delimiter,
fleece::function_ref<bool(std::string_view,std::string_view)> callback);

} // namespace litecore::REST

0 comments on commit 3e0870a

Please sign in to comment.