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 <string>
11 
12 #include "absl/container/flat_hash_map.h"
13 #include "absl/container/flat_hash_set.h"
14 #include "absl/strings/str_cat.h"
15 #include "absl/strings/str_replace.h"
16 #include "absl/strings/string_view.h"
17 #include "absl/types/optional.h"
18 #include "url/url_canon.h"
19 #include "url/url_util.h"
20 
21 namespace quiche {
22 
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)23 bool ExpandURITemplateImpl(
24     const std::string& uri_template,
25     const absl::flat_hash_map<std::string, std::string>& parameters,
26     std::string* target, absl::flat_hash_set<std::string>* vars_found) {
27   absl::flat_hash_set<std::string> found;
28   std::string result = uri_template;
29   for (const auto& pair : parameters) {
30     const std::string& name = pair.first;
31     const std::string& value = pair.second;
32     std::string name_input = absl::StrCat("{", name, "}");
33     url::RawCanonOutputT<char> canon_value;
34     url::EncodeURIComponent(value.c_str(), value.length(), &canon_value);
35     std::string encoded_value(canon_value.data(), canon_value.length());
36     int num_replaced =
37         absl::StrReplaceAll({{name_input, encoded_value}}, &result);
38     if (num_replaced > 0) {
39       found.insert(name);
40     }
41   }
42   // Remove any remaining variables that were not present in |parameters|.
43   while (true) {
44     size_t start = result.find('{');
45     if (start == std::string::npos) {
46       break;
47     }
48     size_t end = result.find('}');
49     if (end == std::string::npos || end <= start) {
50       return false;
51     }
52     result.erase(start, (end - start) + 1);
53   }
54   if (vars_found != nullptr) {
55     *vars_found = found;
56   }
57   *target = result;
58   return true;
59 }
60 
AsciiUrlDecodeImpl(absl::string_view input)61 absl::optional<std::string> AsciiUrlDecodeImpl(absl::string_view input) {
62   std::string input_encoded = std::string(input);
63   url::RawCanonOutputW<1024> canon_output;
64   url::DecodeURLEscapeSequences(input_encoded.c_str(), input_encoded.length(),
65                                 url::DecodeURLMode::kUTF8,
66                                 &canon_output);
67   std::string output;
68   output.reserve(canon_output.length());
69   for (int i = 0; i < canon_output.length(); i++) {
70     const uint16_t c = reinterpret_cast<uint16_t*>(canon_output.data())[i];
71     if (c > std::numeric_limits<signed char>::max()) {
72       return absl::nullopt;
73     }
74     output += static_cast<char>(c);
75   }
76   return output;
77 }
78 
79 }  // namespace quiche
80