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