Created Utility.hpp and moved some code into this file. Also improved parse_query_string.
This commit is contained in:
parent
62da9daf87
commit
ba4eec7ebe
6 changed files with 136 additions and 116 deletions
|
|
@ -49,4 +49,4 @@ endif()
|
||||||
enable_testing()
|
enable_testing()
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
|
|
||||||
install(FILES server_http.hpp client_http.hpp server_https.hpp client_https.hpp DESTINATION include/simple-web-server)
|
install(FILES server_http.hpp client_http.hpp server_https.hpp client_https.hpp utility.hpp DESTINATION include/simple-web-server)
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,14 @@
|
||||||
#ifndef CLIENT_HTTP_HPP
|
#ifndef CLIENT_HTTP_HPP
|
||||||
#define CLIENT_HTTP_HPP
|
#define CLIENT_HTTP_HPP
|
||||||
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include "utility.hpp"
|
||||||
|
|
||||||
#ifdef USE_STANDALONE_ASIO
|
#ifdef USE_STANDALONE_ASIO
|
||||||
#include <asio.hpp>
|
#include <asio.hpp>
|
||||||
#include <type_traits>
|
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
namespace SimpleWeb {
|
namespace SimpleWeb {
|
||||||
using error_code = std::error_code;
|
using error_code = std::error_code;
|
||||||
|
|
@ -31,38 +30,7 @@ namespace SimpleWeb {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
# ifndef CASE_INSENSITIVE_EQUAL_AND_HASH
|
|
||||||
# define CASE_INSENSITIVE_EQUAL_AND_HASH
|
|
||||||
namespace SimpleWeb {
|
namespace SimpleWeb {
|
||||||
inline bool case_insensitive_equal(const std::string &str1, const std::string &str2) {
|
|
||||||
return str1.size() == str2.size() &&
|
|
||||||
std::equal(str1.begin(), str1.end(), str2.begin(), [](char a, char b) {
|
|
||||||
return tolower(a) == tolower(b);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
class CaseInsensitiveEqual {
|
|
||||||
public:
|
|
||||||
bool operator()(const std::string &str1, const std::string &str2) const {
|
|
||||||
return case_insensitive_equal(str1, str2);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Based on https://stackoverflow.com/questions/2590677/how-do-i-combine-hash-values-in-c0x/2595226#2595226
|
|
||||||
class CaseInsensitiveHash {
|
|
||||||
public:
|
|
||||||
size_t operator()(const std::string &str) const {
|
|
||||||
size_t h = 0;
|
|
||||||
std::hash<int> hash;
|
|
||||||
for (auto c : str)
|
|
||||||
h ^= hash(tolower(c)) + 0x9e3779b9 + (h << 6) + (h >> 2);
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
namespace SimpleWeb {
|
|
||||||
using Header = std::unordered_multimap<std::string, std::string, CaseInsensitiveHash, CaseInsensitiveEqual>;
|
|
||||||
|
|
||||||
template <class socket_type>
|
template <class socket_type>
|
||||||
class Client;
|
class Client;
|
||||||
|
|
||||||
|
|
@ -77,7 +45,7 @@ namespace SimpleWeb {
|
||||||
|
|
||||||
std::istream content;
|
std::istream content;
|
||||||
|
|
||||||
Header header;
|
CaseInsensitiveMultimap header;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
asio::streambuf content_buffer;
|
asio::streambuf content_buffer;
|
||||||
|
|
@ -143,7 +111,7 @@ namespace SimpleWeb {
|
||||||
virtual ~ClientBase() {}
|
virtual ~ClientBase() {}
|
||||||
|
|
||||||
/// Synchronous request. The io_service is run within this function.
|
/// Synchronous request. The io_service is run within this function.
|
||||||
std::shared_ptr<Response> request(const std::string& method, const std::string& path=std::string("/"), string_view content="", const Header& header=Header()) {
|
std::shared_ptr<Response> request(const std::string& method, const std::string& path=std::string("/"), string_view content="", const CaseInsensitiveMultimap& header=CaseInsensitiveMultimap()) {
|
||||||
auto session=std::make_shared<Session>(io_service, get_connection(), create_request_header(method, path, header));
|
auto session=std::make_shared<Session>(io_service, get_connection(), create_request_header(method, path, header));
|
||||||
std::shared_ptr<Response> response;
|
std::shared_ptr<Response> response;
|
||||||
session->callback=[this, &response, session](const error_code &ec) {
|
session->callback=[this, &response, session](const error_code &ec) {
|
||||||
|
|
@ -170,7 +138,7 @@ namespace SimpleWeb {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Synchronous request. The io_service is run within this function.
|
/// Synchronous request. The io_service is run within this function.
|
||||||
std::shared_ptr<Response> request(const std::string& method, const std::string& path, std::iostream& content, const Header& header=Header()) {
|
std::shared_ptr<Response> request(const std::string& method, const std::string& path, std::iostream& content, const CaseInsensitiveMultimap& header=CaseInsensitiveMultimap()) {
|
||||||
auto session=std::make_shared<Session>(io_service, get_connection(), create_request_header(method, path, header));
|
auto session=std::make_shared<Session>(io_service, get_connection(), create_request_header(method, path, header));
|
||||||
std::shared_ptr<Response> response;
|
std::shared_ptr<Response> response;
|
||||||
session->callback=[this, &response, session](const error_code &ec) {
|
session->callback=[this, &response, session](const error_code &ec) {
|
||||||
|
|
@ -202,7 +170,7 @@ namespace SimpleWeb {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Asynchronous request where setting and/or running Client's io_service is required.
|
/// Asynchronous request where setting and/or running Client's io_service is required.
|
||||||
void request(const std::string &method, const std::string &path, string_view content, const Header& header,
|
void request(const std::string &method, const std::string &path, string_view content, const CaseInsensitiveMultimap& header,
|
||||||
std::function<void(std::shared_ptr<Response>, const error_code&)> &&request_callback_) {
|
std::function<void(std::shared_ptr<Response>, const error_code&)> &&request_callback_) {
|
||||||
auto session=std::make_shared<Session>(io_service, get_connection(), create_request_header(method, path, header));
|
auto session=std::make_shared<Session>(io_service, get_connection(), create_request_header(method, path, header));
|
||||||
auto request_callback=std::make_shared<std::function<void(std::shared_ptr<Response>, const error_code&)>>(std::move(request_callback_));
|
auto request_callback=std::make_shared<std::function<void(std::shared_ptr<Response>, const error_code&)>>(std::move(request_callback_));
|
||||||
|
|
@ -228,22 +196,22 @@ namespace SimpleWeb {
|
||||||
/// Asynchronous request where setting and/or running Client's io_service is required.
|
/// Asynchronous request where setting and/or running Client's io_service is required.
|
||||||
void request(const std::string &method, const std::string &path, string_view content,
|
void request(const std::string &method, const std::string &path, string_view content,
|
||||||
std::function<void(std::shared_ptr<Response>, const error_code&)> &&request_callback) {
|
std::function<void(std::shared_ptr<Response>, const error_code&)> &&request_callback) {
|
||||||
request(method, path, content, Header(), std::move(request_callback));
|
request(method, path, content, CaseInsensitiveMultimap(), std::move(request_callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Asynchronous request where setting and/or running Client's io_service is required.
|
/// Asynchronous request where setting and/or running Client's io_service is required.
|
||||||
void request(const std::string &method, const std::string &path,
|
void request(const std::string &method, const std::string &path,
|
||||||
std::function<void(std::shared_ptr<Response>, const error_code&)> &&request_callback) {
|
std::function<void(std::shared_ptr<Response>, const error_code&)> &&request_callback) {
|
||||||
request(method, path, std::string(), Header(), std::move(request_callback));
|
request(method, path, std::string(), CaseInsensitiveMultimap(), std::move(request_callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Asynchronous request where setting and/or running Client's io_service is required.
|
/// Asynchronous request where setting and/or running Client's io_service is required.
|
||||||
void request(const std::string &method, std::function<void(std::shared_ptr<Response>, const error_code&)> &&request_callback) {
|
void request(const std::string &method, std::function<void(std::shared_ptr<Response>, const error_code&)> &&request_callback) {
|
||||||
request(method, std::string("/"), std::string(), Header(), std::move(request_callback));
|
request(method, std::string("/"), std::string(), CaseInsensitiveMultimap(), std::move(request_callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Asynchronous request where setting and/or running Client's io_service is required.
|
/// Asynchronous request where setting and/or running Client's io_service is required.
|
||||||
void request(const std::string &method, const std::string &path, std::iostream& content, const Header& header,
|
void request(const std::string &method, const std::string &path, std::iostream& content, const CaseInsensitiveMultimap& header,
|
||||||
std::function<void(std::shared_ptr<Response>, const error_code&)> &&request_callback_) {
|
std::function<void(std::shared_ptr<Response>, const error_code&)> &&request_callback_) {
|
||||||
auto session=std::make_shared<Session>(io_service, get_connection(), create_request_header(method, path, header));
|
auto session=std::make_shared<Session>(io_service, get_connection(), create_request_header(method, path, header));
|
||||||
auto request_callback=std::make_shared<std::function<void(std::shared_ptr<Response>, const error_code&)>>(std::move(request_callback_));
|
auto request_callback=std::make_shared<std::function<void(std::shared_ptr<Response>, const error_code&)>>(std::move(request_callback_));
|
||||||
|
|
@ -274,7 +242,7 @@ namespace SimpleWeb {
|
||||||
/// Asynchronous request where setting and/or running Client's io_service is required.
|
/// Asynchronous request where setting and/or running Client's io_service is required.
|
||||||
void request(const std::string &method, const std::string &path, std::iostream& content,
|
void request(const std::string &method, const std::string &path, std::iostream& content,
|
||||||
std::function<void(std::shared_ptr<Response>, const error_code&)> &&request_callback) {
|
std::function<void(std::shared_ptr<Response>, const error_code&)> &&request_callback) {
|
||||||
request(method, path, content, Header(), std::move(request_callback));
|
request(method, path, content, CaseInsensitiveMultimap(), std::move(request_callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
@ -314,7 +282,7 @@ namespace SimpleWeb {
|
||||||
|
|
||||||
virtual std::shared_ptr<Connection> create_connection()=0;
|
virtual std::shared_ptr<Connection> create_connection()=0;
|
||||||
|
|
||||||
std::unique_ptr<asio::streambuf> create_request_header(const std::string& method, const std::string& path, const Header& header) const {
|
std::unique_ptr<asio::streambuf> create_request_header(const std::string& method, const std::string& path, const CaseInsensitiveMultimap& header) const {
|
||||||
auto corrected_path=path;
|
auto corrected_path=path;
|
||||||
if(corrected_path=="")
|
if(corrected_path=="")
|
||||||
corrected_path="/";
|
corrected_path="/";
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef CRYPTO_HPP
|
#ifndef SIMPLE_WEB_SERVER_CRYPTO_HPP
|
||||||
#define CRYPTO_HPP
|
#define SIMPLE_WEB_SERVER_CRYPTO_HPP
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
@ -216,5 +216,4 @@ namespace SimpleWeb {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif /* CRYPTO_HPP */
|
#endif /* SIMPLE_WEB_SERVER_CRYPTO_HPP */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,11 @@
|
||||||
#define SERVER_HTTP_HPP
|
#define SERVER_HTTP_HPP
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <unordered_map>
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include "utility.hpp"
|
||||||
|
|
||||||
#ifdef USE_STANDALONE_ASIO
|
#ifdef USE_STANDALONE_ASIO
|
||||||
#include <asio.hpp>
|
#include <asio.hpp>
|
||||||
|
|
@ -26,35 +26,6 @@ namespace SimpleWeb {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
# ifndef CASE_INSENSITIVE_EQUAL_AND_HASH
|
|
||||||
# define CASE_INSENSITIVE_EQUAL_AND_HASH
|
|
||||||
namespace SimpleWeb {
|
|
||||||
inline bool case_insensitive_equal(const std::string &str1, const std::string &str2) {
|
|
||||||
return str1.size() == str2.size() &&
|
|
||||||
std::equal(str1.begin(), str1.end(), str2.begin(), [](char a, char b) {
|
|
||||||
return tolower(a) == tolower(b);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
class CaseInsensitiveEqual {
|
|
||||||
public:
|
|
||||||
bool operator()(const std::string &str1, const std::string &str2) const {
|
|
||||||
return case_insensitive_equal(str1, str2);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Based on https://stackoverflow.com/questions/2590677/how-do-i-combine-hash-values-in-c0x/2595226#2595226
|
|
||||||
class CaseInsensitiveHash {
|
|
||||||
public:
|
|
||||||
size_t operator()(const std::string &str) const {
|
|
||||||
size_t h = 0;
|
|
||||||
std::hash<int> hash;
|
|
||||||
for (auto c : str)
|
|
||||||
h ^= hash(tolower(c)) + 0x9e3779b9 + (h << 6) + (h >> 2);
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
// Late 2017 TODO: remove the following checks and always use std::regex
|
// Late 2017 TODO: remove the following checks and always use std::regex
|
||||||
#ifdef USE_BOOST_REGEX
|
#ifdef USE_BOOST_REGEX
|
||||||
#include <boost/regex.hpp>
|
#include <boost/regex.hpp>
|
||||||
|
|
@ -68,17 +39,6 @@ namespace SimpleWeb {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// TODO when switching to c++14, use [[deprecated]] instead
|
|
||||||
#ifndef DEPRECATED
|
|
||||||
#ifdef __GNUC__
|
|
||||||
#define DEPRECATED __attribute__((deprecated))
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
#define DEPRECATED __declspec(deprecated)
|
|
||||||
#else
|
|
||||||
#define DEPRECATED
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace SimpleWeb {
|
namespace SimpleWeb {
|
||||||
template <class socket_type>
|
template <class socket_type>
|
||||||
class Server;
|
class Server;
|
||||||
|
|
@ -133,7 +93,7 @@ namespace SimpleWeb {
|
||||||
|
|
||||||
Content content;
|
Content content;
|
||||||
|
|
||||||
std::unordered_multimap<std::string, std::string, CaseInsensitiveHash, CaseInsensitiveEqual> header;
|
CaseInsensitiveMultimap header;
|
||||||
|
|
||||||
regex::smatch path_match;
|
regex::smatch path_match;
|
||||||
|
|
||||||
|
|
@ -141,32 +101,12 @@ namespace SimpleWeb {
|
||||||
unsigned short remote_endpoint_port;
|
unsigned short remote_endpoint_port;
|
||||||
|
|
||||||
/// Returns query keys with percent-decoded values.
|
/// Returns query keys with percent-decoded values.
|
||||||
std::unordered_multimap<std::string, std::string, CaseInsensitiveHash, CaseInsensitiveEqual> parse_query_string() {
|
CaseInsensitiveMultimap parse_query_string() {
|
||||||
std::unordered_multimap<std::string, std::string, CaseInsensitiveHash, CaseInsensitiveEqual> result;
|
auto pos = path.find('?');
|
||||||
auto qs_start_pos = path.find('?');
|
if (pos != std::string::npos && pos + 1 < path.size())
|
||||||
if (qs_start_pos != std::string::npos && qs_start_pos + 1 < path.size()) {
|
return SimpleWeb::parse_query_string(path.substr(pos + 1));
|
||||||
++qs_start_pos;
|
else
|
||||||
static regex::regex pattern("([\\w+%]+)=?([^&]*)");
|
return CaseInsensitiveMultimap();
|
||||||
int submatches[] = {1, 2};
|
|
||||||
auto it_begin = regex::sregex_token_iterator(path.begin() + qs_start_pos, path.end(), pattern, submatches);
|
|
||||||
auto it_end = regex::sregex_token_iterator();
|
|
||||||
for (auto it = it_begin; it != it_end; ++it) {
|
|
||||||
auto submatch1=it->str();
|
|
||||||
auto submatch2=(++it)->str();
|
|
||||||
auto query_it = result.emplace(submatch1, submatch2);
|
|
||||||
auto &value = query_it->second;
|
|
||||||
for (size_t c = 0; c < value.size(); ++c) {
|
|
||||||
if (value[c] == '+')
|
|
||||||
value[c] = ' ';
|
|
||||||
else if (value[c] == '%' && c + 2 < value.size()) {
|
|
||||||
auto hex = value.substr(c + 1, 2);
|
|
||||||
auto chr = static_cast<char>(std::strtol(hex.c_str(), nullptr, 16));
|
|
||||||
value.replace(c, 3, &chr, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,16 @@ int main() {
|
||||||
auto queries = request.parse_query_string();
|
auto queries = request.parse_query_string();
|
||||||
assert(queries.empty());
|
assert(queries.empty());
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
request.path = "/?=";
|
||||||
|
auto queries = request.parse_query_string();
|
||||||
|
assert(queries.empty());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
request.path = "/?=test";
|
||||||
|
auto queries = request.parse_query_string();
|
||||||
|
assert(queries.empty());
|
||||||
|
}
|
||||||
{
|
{
|
||||||
request.path = "/?a=1%202%20%203&b=3+4&c&d=æ%25ø%26å%3F";
|
request.path = "/?a=1%202%20%203&b=3+4&c&d=æ%25ø%26å%3F";
|
||||||
auto queries = request.parse_query_string();
|
auto queries = request.parse_query_string();
|
||||||
|
|
|
||||||
103
utility.hpp
Normal file
103
utility.hpp
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
#ifndef SIMPLE_WEB_SERVER_UTILITY_HPP
|
||||||
|
#define SIMPLE_WEB_SERVER_UTILITY_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
// TODO when switching to c++14, use [[deprecated]] instead
|
||||||
|
#ifndef DEPRECATED
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define DEPRECATED __attribute__((deprecated))
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define DEPRECATED __declspec(deprecated)
|
||||||
|
#else
|
||||||
|
#define DEPRECATED
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace SimpleWeb {
|
||||||
|
#ifndef CASE_INSENSITIVE_EQUAL_AND_HASH
|
||||||
|
#define CASE_INSENSITIVE_EQUAL_AND_HASH
|
||||||
|
inline bool case_insensitive_equal(const std::string &str1, const std::string &str2) {
|
||||||
|
return str1.size() == str2.size() &&
|
||||||
|
std::equal(str1.begin(), str1.end(), str2.begin(), [](char a, char b) {
|
||||||
|
return tolower(a) == tolower(b);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
class CaseInsensitiveEqual {
|
||||||
|
public:
|
||||||
|
bool operator()(const std::string &str1, const std::string &str2) const {
|
||||||
|
return case_insensitive_equal(str1, str2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Based on https://stackoverflow.com/questions/2590677/how-do-i-combine-hash-values-in-c0x/2595226#2595226
|
||||||
|
class CaseInsensitiveHash {
|
||||||
|
public:
|
||||||
|
size_t operator()(const std::string &str) const {
|
||||||
|
size_t h = 0;
|
||||||
|
std::hash<int> hash;
|
||||||
|
for(auto c : str)
|
||||||
|
h ^= hash(tolower(c)) + 0x9e3779b9 + (h << 6) + (h >> 2);
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef std::unordered_multimap<std::string, std::string, CaseInsensitiveHash, CaseInsensitiveEqual> CaseInsensitiveMultimap;
|
||||||
|
|
||||||
|
/// Percent encoding and decoding
|
||||||
|
class Percent {
|
||||||
|
public:
|
||||||
|
static std::string decode(const std::string &value) {
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
for(size_t i = 0; i < value.size(); ++i) {
|
||||||
|
auto &chr = value[i];
|
||||||
|
if(chr == '%' && i + 2 < value.size()) {
|
||||||
|
auto hex = value.substr(i + 1, 2);
|
||||||
|
auto decoded_chr = static_cast<char>(std::strtol(hex.c_str(), nullptr, 16));
|
||||||
|
result += decoded_chr;
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
else if(chr == '+')
|
||||||
|
result += ' ';
|
||||||
|
else
|
||||||
|
result += chr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Returns query keys with percent-decoded values.
|
||||||
|
inline CaseInsensitiveMultimap parse_query_string(const std::string &query_string) {
|
||||||
|
CaseInsensitiveMultimap result;
|
||||||
|
|
||||||
|
if(query_string.empty())
|
||||||
|
return result;
|
||||||
|
|
||||||
|
size_t parameter_pos = 0;
|
||||||
|
size_t parameter_end_pos = -1;
|
||||||
|
size_t value_pos = -1;
|
||||||
|
for(size_t c = 0; c < query_string.size() + 1; ++c) {
|
||||||
|
if(query_string[c] == '&' || c == query_string.size()) {
|
||||||
|
auto parameter = query_string.substr(parameter_pos, (parameter_end_pos == static_cast<size_t>(-1) ? c : parameter_end_pos) - parameter_pos);
|
||||||
|
if(!parameter.empty()) {
|
||||||
|
auto value = value_pos == static_cast<size_t>(-1) ? std::string() : query_string.substr(value_pos, c - value_pos);
|
||||||
|
result.emplace(std::move(parameter), Percent::decode(value));
|
||||||
|
}
|
||||||
|
parameter_pos = c + 1;
|
||||||
|
parameter_end_pos = -1;
|
||||||
|
value_pos = -1;
|
||||||
|
}
|
||||||
|
else if(query_string[c] == '=') {
|
||||||
|
parameter_end_pos = c;
|
||||||
|
value_pos = c + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
} // namespace SimpleWeb
|
||||||
|
|
||||||
|
#endif // SIMPLE_WEB_SERVER_UTILITY_HPP
|
||||||
Loading…
Add table
Add a link
Reference in a new issue