Kagome
Polkadot Runtime Engine in C++17
uri.cpp
Go to the documentation of this file.
1 
6 #include "common/uri.hpp"
7 
8 #include <algorithm>
9 
10 namespace kagome::common {
11 
12  std::string Uri::to_string() const {
13  std::string result;
14  if (not Schema.empty()) {
15  result += Schema;
16  result += ":";
17  }
18  if (not Host.empty()) {
19  if (not Schema.empty()) {
20  result += "//";
21  }
22  result += Host;
23  if (not Port.empty()) {
24  result += ":";
25  result += Port;
26  }
27  }
28  if (not Path.empty()) {
29  result += Path;
30  }
31  if (not Query.empty()) {
32  result += "?";
33  result += Query;
34  }
35  if (not Fragment.empty()) {
36  result += "#";
37  result += Fragment;
38  }
39  return result;
40  }
41 
42  Uri Uri::parse(std::string_view uri) {
43  Uri result;
44 
45  if (uri.empty()) {
46  return result;
47  }
48 
49  result.error_.reset();
50 
51  const auto uri_end = uri.cend();
52 
53  // Schema
54  const auto schema_begin = uri.cbegin();
55  auto schema_end = std::find(schema_begin, uri_end, ':');
56 
57  if (schema_end == uri_end or uri_end - schema_end <= 3
58  or std::string_view(schema_end, 3) != "://") {
59  schema_end = uri.cbegin();
60  }
61  result.Schema.assign(schema_begin, schema_end);
62 
63  if (std::find_if_not(
64  schema_begin, schema_end, [](auto ch) { return std::isalpha(ch); })
65  != schema_end) {
66  if (not result.error_.has_value()) {
67  result.error_.emplace("Invalid schema");
68  }
69  }
70 
71  // Host
72  const auto host_begin =
73  schema_end + (std::string_view(schema_end, 3) == "://" ? 3 : 0);
74  const auto host_end = std::find_if(host_begin, uri_end, [](auto ch) {
75  return ch == ':' or ch == '/' or ch == '?' or ch == '#';
76  });
77  result.Host.assign(host_begin, host_end);
78  if (std::find_if_not(
79  host_begin,
80  host_end,
81  [](auto ch) { return std::isalnum(ch) or ch == '.' or ch == '-'; })
82  != host_end
83  or host_begin == host_end) {
84  if (not result.error_.has_value()) {
85  result.error_.emplace("Invalid hostname");
86  }
87  }
88 
89  // Port
90  const auto port_begin = host_end + (*host_end == ':' ? 1 : 0);
91  const auto port_end = std::find_if(port_begin, uri_end, [](auto ch) {
92  return ch == '/' or ch == '?' or ch == '#';
93  });
94 
95  result.Port.assign(port_begin, port_end);
96 
97  if (std::find_if_not(
98  port_begin, port_end, [](auto ch) { return std::isdigit(ch); })
99  != port_end
100  or (result.Port.empty() and *host_end == ':') or (result.Port == "0")
101  or (result.Port.size() == 5 and result.Port > "65535")
102  or result.Port.size() > 5) {
103  if (not result.error_.has_value()) {
104  result.error_.emplace("Invalid port");
105  }
106  }
107 
108  // Path
109  const auto path_begin = port_end;
110  const auto path_end = std::find_if(
111  path_begin, uri_end, [](auto ch) { return ch == '?' or ch == '#'; });
112 
113  result.Path.assign(path_begin, path_end);
114 
115  // Query
116  const auto query_begin = path_end + (*path_end == '?' ? 1 : 0);
117  const auto query_end = std::find(query_begin, uri_end, '#');
118 
119  result.Query.assign(query_begin, query_end);
120 
121  // Fragment
122  const auto fragment_begin = query_end + (*query_end == '#' ? 1 : 0);
123  const auto fragment_end = uri_end;
124 
125  result.Fragment.assign(fragment_begin, fragment_end);
126 
127  return result;
128  }
129 } // namespace kagome::common
std::string to_string() const
Definition: uri.cpp:12
std::string Fragment
Definition: uri.hpp:22
std::string Schema
Definition: uri.hpp:17
static Uri parse(std::string_view uri)
Definition: uri.cpp:42
std::string Query
Definition: uri.hpp:21
std::string Host
Definition: uri.hpp:18
std::optional< std::string_view > error_
Definition: uri.hpp:33
std::string Port
Definition: uri.hpp:19
std::string Path
Definition: uri.hpp:20