mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-11-24 14:26:09 +03:00
199 lines
6.1 KiB
C++
199 lines
6.1 KiB
C++
/*
|
|
* \copyright Copyright 2013 Google Inc. All Rights Reserved.
|
|
* \license @{
|
|
*
|
|
* 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.
|
|
*
|
|
* @}
|
|
*/
|
|
|
|
// Implementation of RFC 6570 based on (open source implementation) at
|
|
// java/com/google/api/client/http/UriTemplate.java
|
|
// The URI Template spec is at http://tools.ietf.org/html/rfc6570
|
|
// Templates up to level 3 are supported.
|
|
|
|
#include "net/third_party/uri_template/uri_template.h"
|
|
|
|
#include <set>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "base/strings/string_split.h"
|
|
#include "net/base/escape.h"
|
|
|
|
using std::string;
|
|
|
|
namespace uri_template {
|
|
|
|
namespace {
|
|
|
|
// The UriTemplateConfig is used to represent variable sections and to construct
|
|
// the expanded url.
|
|
struct UriTemplateConfig {
|
|
public:
|
|
UriTemplateConfig(const char* prefix,
|
|
const char* joiner,
|
|
bool requires_variable_assignment,
|
|
bool allow_reserved_expansion,
|
|
bool no_variable_assignment_if_empty = false)
|
|
: prefix_(prefix),
|
|
joiner_(joiner),
|
|
requires_variable_assignment_(requires_variable_assignment),
|
|
no_variable_assignment_if_empty_(no_variable_assignment_if_empty),
|
|
allow_reserved_expansion_(allow_reserved_expansion) {}
|
|
|
|
void AppendValue(const string& variable,
|
|
const string& value,
|
|
bool use_prefix,
|
|
string* target) const {
|
|
string joiner = use_prefix ? prefix_ : joiner_;
|
|
if (requires_variable_assignment_) {
|
|
if (value.empty() && no_variable_assignment_if_empty_) {
|
|
target->append(joiner + EscapedValue(variable));
|
|
} else {
|
|
target->append(joiner + EscapedValue(variable) + "=" +
|
|
EscapedValue(value));
|
|
}
|
|
} else {
|
|
target->append(joiner + EscapedValue(value));
|
|
}
|
|
}
|
|
|
|
private:
|
|
string EscapedValue(const string& value) const {
|
|
string escaped;
|
|
if (allow_reserved_expansion_) {
|
|
// Reserved expansion passes through reserved and pct-encoded characters.
|
|
escaped = net::EscapeExternalHandlerValue(value);
|
|
} else {
|
|
escaped = net::EscapeAllExceptUnreserved(value);
|
|
}
|
|
return escaped;
|
|
}
|
|
|
|
const char* prefix_;
|
|
const char* joiner_;
|
|
bool requires_variable_assignment_;
|
|
bool no_variable_assignment_if_empty_;
|
|
bool allow_reserved_expansion_;
|
|
};
|
|
|
|
// variable is an in-out argument. On input it is the content between the
|
|
// '{}' in the source. On result the control parameters are stripped off
|
|
// leaving just the comma-separated variable name(s) that we should try to
|
|
// resolve.
|
|
UriTemplateConfig MakeConfig(string* variable) {
|
|
switch (*variable->data()) {
|
|
// Reserved expansion.
|
|
case '+':
|
|
*variable = variable->substr(1);
|
|
return UriTemplateConfig("", ",", false, true);
|
|
|
|
// Fragment expansion.
|
|
case '#':
|
|
*variable = variable->substr(1);
|
|
return UriTemplateConfig("#", ",", false, true);
|
|
|
|
// Label with dot-prefix.
|
|
case '.':
|
|
*variable = variable->substr(1);
|
|
return UriTemplateConfig(".", ".", false, false);
|
|
|
|
// Path segment expansion.
|
|
case '/':
|
|
*variable = variable->substr(1);
|
|
return UriTemplateConfig("/", "/", false, false);
|
|
|
|
// Path segment parameter expansion.
|
|
case ';':
|
|
*variable = variable->substr(1);
|
|
return UriTemplateConfig(";", ";", true, false, true);
|
|
|
|
// Form-style query expansion.
|
|
case '?':
|
|
*variable = variable->substr(1);
|
|
return UriTemplateConfig("?", "&", true, false);
|
|
|
|
// Form-style query continuation.
|
|
case '&':
|
|
*variable = variable->substr(1);
|
|
return UriTemplateConfig("&", "&", true, false);
|
|
|
|
// Simple expansion.
|
|
default:
|
|
return UriTemplateConfig("", ",", false, false);
|
|
}
|
|
}
|
|
|
|
void ProcessVariableSection(
|
|
string* variable_section,
|
|
const std::unordered_map<string, string>& parameters,
|
|
string* target,
|
|
std::set<string>* vars_found) {
|
|
// Note that this function will modify the variable_section string to remove
|
|
// the decorators, leaving just comma-separated variable name(s).
|
|
UriTemplateConfig config = MakeConfig(variable_section);
|
|
std::vector<string> variables = base::SplitString(
|
|
*variable_section, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
|
|
bool first_var = true;
|
|
for (const string& variable : variables) {
|
|
auto found = parameters.find(variable);
|
|
if (found != parameters.end()) {
|
|
config.AppendValue(variable, found->second, first_var, target);
|
|
first_var = false;
|
|
if (vars_found) {
|
|
vars_found->insert(variable);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
bool Expand(const string& path_uri,
|
|
const std::unordered_map<string, string>& parameters,
|
|
string* target,
|
|
std::set<string>* vars_found) {
|
|
size_t cur = 0;
|
|
size_t length = path_uri.length();
|
|
while (cur < length) {
|
|
size_t open = path_uri.find('{', cur);
|
|
size_t close = path_uri.find('}', cur);
|
|
if (open == string::npos) {
|
|
if (close == string::npos) {
|
|
// No more variables to process.
|
|
target->append(path_uri.substr(cur).data(), path_uri.length() - cur);
|
|
return true;
|
|
} else {
|
|
// Template was malformed. Unexpected closing brace.
|
|
target->clear();
|
|
return false;
|
|
}
|
|
}
|
|
target->append(path_uri, cur, open - cur);
|
|
size_t next_open = path_uri.find('{', open + 1);
|
|
if (close == string::npos || close < open || next_open < close) {
|
|
// Template was malformed.
|
|
target->clear();
|
|
return false;
|
|
}
|
|
string variable_section(path_uri, open + 1, close - open - 1);
|
|
cur = close + 1;
|
|
|
|
ProcessVariableSection(&variable_section, parameters, target, vars_found);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
} // namespace uri_template
|