1 // Copyright 2021 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "quiche_platform_impl/quiche_url_utils_impl.h"
6
7 #include <cstddef>
8 #include <cstdint>
9 #include <limits>
10 #include <optional>
11 #include <string>
12
13 #include "quiche_platform_impl/quiche_googleurl_impl.h"
14 #include "absl/container/flat_hash_map.h"
15 #include "absl/container/flat_hash_set.h"
16 #include "absl/strings/str_cat.h"
17 #include "absl/strings/str_replace.h"
18 #include "absl/strings/string_view.h"
19
20 namespace quiche {
21
ExpandURITemplateImpl(const std::string & uri_template,const absl::flat_hash_map<std::string,std::string> & parameters,std::string * target,absl::flat_hash_set<std::string> * vars_found)22 bool ExpandURITemplateImpl(
23 const std::string& uri_template,
24 const absl::flat_hash_map<std::string, std::string>& parameters,
25 std::string* target, absl::flat_hash_set<std::string>* vars_found) {
26 absl::flat_hash_set<std::string> found;
27 std::string result = uri_template;
28 for (const auto& pair : parameters) {
29 const std::string& name = pair.first;
30 const std::string& value = pair.second;
31 std::string name_input = absl::StrCat("{", name, "}");
32 url::RawCanonOutputT<char> canon_value;
33 url::EncodeURIComponent(value.c_str(), value.length(), &canon_value);
34 std::string encoded_value(canon_value.data(), canon_value.length());
35 int num_replaced =
36 absl::StrReplaceAll({{name_input, encoded_value}}, &result);
37 if (num_replaced > 0) {
38 found.insert(name);
39 }
40 }
41 // Remove any remaining variables that were not present in |parameters|.
42 while (true) {
43 size_t start = result.find('{');
44 if (start == std::string::npos) {
45 break;
46 }
47 size_t end = result.find('}');
48 if (end == std::string::npos || end <= start) {
49 return false;
50 }
51 result.erase(start, (end - start) + 1);
52 }
53 if (vars_found != nullptr) {
54 *vars_found = found;
55 }
56 *target = result;
57 return true;
58 }
59
AsciiUrlDecodeImpl(absl::string_view input)60 std::optional<std::string> AsciiUrlDecodeImpl(absl::string_view input) {
61 std::string input_encoded = std::string(input);
62 url::RawCanonOutputW<1024> canon_output;
63 url::DecodeURLEscapeSequences(input_encoded.c_str(), input_encoded.length(),
64 url::DecodeURLMode::kUTF8,
65 &canon_output);
66 std::string output;
67 output.reserve(canon_output.length());
68 for (int i = 0; i < canon_output.length(); i++) {
69 const uint16_t c = reinterpret_cast<uint16_t*>(canon_output.data())[i];
70 if (c > std::numeric_limits<signed char>::max()) {
71 return std::nullopt;
72 }
73 output += static_cast<char>(c);
74 }
75 return output;
76 }
77
78 } // namespace quiche
79