Add QueryParser.h for decoding URI queries by key
This commit is contained in:
@@ -29,6 +29,7 @@
|
||||
|
||||
#include "BloomFilter.h"
|
||||
#include "ProxyParser.h"
|
||||
#include "QueryParser.h"
|
||||
|
||||
namespace uWS {
|
||||
|
||||
@@ -108,6 +109,7 @@ public:
|
||||
return std::string_view(headers->key.data(), headers->key.length());
|
||||
}
|
||||
|
||||
/* Returns the raw querystring as a whole, still encoded */
|
||||
std::string_view getQuery() {
|
||||
if (querySeparator < (int) headers->value.length()) {
|
||||
/* Strip the initial ? */
|
||||
@@ -117,6 +119,14 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/* Finds and decodes the URI component. */
|
||||
std::string_view getQuery(std::string_view key) {
|
||||
/* Raw querystring including initial '?' sign */
|
||||
std::string_view queryString = std::string_view(headers->value.data() + querySeparator, headers->value.length() - querySeparator);
|
||||
|
||||
return getDecodedQueryValue(key, queryString);
|
||||
}
|
||||
|
||||
void setParameters(std::pair<int, std::string_view *> parameters) {
|
||||
currentParameters = parameters;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Authored by Alex Hultman, 2018-2020.
|
||||
* Intellectual property of third-party.
|
||||
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* This module implements URI query parsing and retrieval of value given key */
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace uWS {
|
||||
|
||||
/* Takes raw query including initial '?' sign. Will inplace decode, so input will mutate */
|
||||
std::string_view getDecodedQueryValue(std::string_view key, std::string_view rawQuery) {
|
||||
|
||||
/* Can't have a value without a key */
|
||||
if (!key.length()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
/* Start with the whole querystring including initial '?' */
|
||||
std::string_view queryString = rawQuery;
|
||||
|
||||
/* List of key, value could be cached for repeated fetches similar to how headers are, todo! */
|
||||
while (queryString.length()) {
|
||||
/* Find boundaries of this statement */
|
||||
std::string_view statement = queryString.substr(1, queryString.find('&', 1) - 1);
|
||||
|
||||
/* Only bother if first char of key match (early exit) */
|
||||
if (statement.length() && statement[0] == key[0]) {
|
||||
/* Equal sign must be present and not in the end of statement */
|
||||
auto equality = statement.find('=');
|
||||
if (equality != std::string_view::npos && equality != statement.length() - 1) {
|
||||
|
||||
std::string_view statementKey = statement.substr(0, equality);
|
||||
std::string_view statementValue = statement.substr(equality + 1);
|
||||
|
||||
/* String comparison */
|
||||
if (key == statementKey) {
|
||||
|
||||
/* Decode value inplace, put null at end if before length of original */
|
||||
char *in = (char *) statementValue.data();
|
||||
|
||||
/* Write offset */
|
||||
int out = 0;
|
||||
|
||||
/* Walk over all chars until end or null char, decoding in place */
|
||||
for (int i = 0; in[i] && i < statementValue.length(); i++) {
|
||||
/* Only bother with '%' */
|
||||
if (in[i] == '%') {
|
||||
/* Do we have enough data for two bytes hex? */
|
||||
if (i + 2 >= statementValue.length()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
/* Two bytes hex */
|
||||
char hex1 = in[i + 1] - '0';
|
||||
if (hex1 > 9) {
|
||||
hex1 -= 7;
|
||||
}
|
||||
|
||||
char hex2 = in[i + 2] - '0';
|
||||
if (hex2 > 9) {
|
||||
hex2 -= 7;
|
||||
}
|
||||
|
||||
in[out] = hex1 * 16 + hex2;
|
||||
i += 2;
|
||||
} else {
|
||||
/* Is this even a rule? */
|
||||
if (in[i] == '+') {
|
||||
in[out] = ' ';
|
||||
} else {
|
||||
in[out] = in[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* We always only write one char */
|
||||
out++;
|
||||
}
|
||||
|
||||
/* If decoded string is shorter than original, put null char to stop next read */
|
||||
if (out < statementValue.length()) {
|
||||
in[out] = 0;
|
||||
}
|
||||
|
||||
return statementValue.substr(0, out);
|
||||
}
|
||||
} else {
|
||||
/* This querystring is invalid, cannot parse it */
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
queryString.remove_prefix(statement.length() + 1);
|
||||
}
|
||||
|
||||
/* Nothing found */
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user