rippled
Loading...
Searching...
No Matches
StringUtilities.cpp
1#include <xrpl/basics/Blob.h>
2#include <xrpl/basics/StringUtilities.h>
3#include <xrpl/beast/core/LexicalCast.h>
4#include <xrpl/beast/net/IPEndpoint.h>
5
6#include <boost/algorithm/hex.hpp>
7#include <boost/algorithm/string/case_conv.hpp>
8#include <boost/algorithm/string/trim.hpp>
9#include <boost/regex/v5/regbase.hpp>
10#include <boost/regex/v5/regex.hpp>
11#include <boost/regex/v5/regex_fwd.hpp>
12#include <boost/regex/v5/regex_match.hpp>
13
14#include <cstdint>
15#include <iterator>
16#include <optional>
17#include <string>
18#include <string_view>
19
20namespace ripple {
21
23sqlBlobLiteral(Blob const& blob)
24{
26
27 j.reserve(blob.size() * 2 + 3);
28 j.push_back('X');
29 j.push_back('\'');
30 boost::algorithm::hex(blob.begin(), blob.end(), std::back_inserter(j));
31 j.push_back('\'');
32
33 return j;
34}
35
36bool
37parseUrl(parsedURL& pUrl, std::string const& strUrl)
38{
39 // scheme://username:password@hostname:port/rest
40 static boost::regex reUrl(
41 "(?i)\\`\\s*"
42 // required scheme
43 "([[:alpha:]][-+.[:alpha:][:digit:]]*?):"
44 // We choose to support only URIs whose `hier-part` has the form
45 // `"//" authority path-abempty`.
46 "//"
47 // optional userinfo
48 "(?:([^:@/]*?)(?::([^@/]*?))?@)?"
49 // optional host
50 "([[:digit:]:]*[[:digit:]]|\\[[^]]+\\]|[^:/?#]*?)"
51 // optional port
52 "(?::([[:digit:]]+))?"
53 // optional path
54 "(/.*)?"
55 "\\s*?\\'");
56 boost::smatch smMatch;
57
58 // Bail if there is no match.
59 try
60 {
61 if (!boost::regex_match(strUrl, smMatch, reUrl))
62 return false;
63 }
64 catch (...)
65 {
66 return false;
67 }
68
69 pUrl.scheme = smMatch[1];
70 boost::algorithm::to_lower(pUrl.scheme);
71 pUrl.username = smMatch[2];
72 pUrl.password = smMatch[3];
73 std::string const domain = smMatch[4];
74 // We need to use Endpoint to parse the domain to
75 // strip surrounding brackets from IPv6 addresses,
76 // e.g. [::1] => ::1.
77 auto const result = beast::IP::Endpoint::from_string_checked(domain);
78 pUrl.domain = result ? result->address().to_string() : domain;
79 std::string const port = smMatch[5];
80 if (!port.empty())
81 {
82 pUrl.port = beast::lexicalCast<std::uint16_t>(port);
83
84 // For inputs larger than 2^32-1 (65535), lexicalCast returns 0.
85 // parseUrl returns false for such inputs.
86 if (pUrl.port == 0)
87 {
88 return false;
89 }
90 }
91 pUrl.path = smMatch[6];
92
93 return true;
94}
95
98{
99 boost::trim(str);
100 return str;
101}
102
105{
106 std::uint64_t result;
107 if (beast::lexicalCastChecked(result, s))
108 return result;
109 return std::nullopt;
110}
111
112bool
114{
115 // The domain must be between 4 and 128 characters long
116 if (domain.size() < 4 || domain.size() > 128)
117 return false;
118
119 // This regular expression should do a decent job of weeding out
120 // obviously wrong domain names but it isn't perfect. It does not
121 // really support IDNs. If this turns out to be an issue, a more
122 // thorough regex can be used or this check can just be removed.
123 static boost::regex const re(
124 "^" // Beginning of line
125 "(" // Beginning of a segment
126 "(?!-)" // - must not begin with '-'
127 "[a-zA-Z0-9-]{1,63}" // - only alphanumeric and '-'
128 "(?<!-)" // - must not end with '-'
129 "\\." // segment separator
130 ")+" // 1 or more segments
131 "[A-Za-z]{2,63}" // TLD
132 "$" // End of line
133 ,
134 boost::regex_constants::optimize);
135
136 return boost::regex_match(domain.begin(), domain.end(), re);
137}
138
139} // namespace ripple
T back_inserter(T... args)
T begin(T... args)
static std::optional< Endpoint > from_string_checked(std::string const &s)
Create an Endpoint from a string.
T empty(T... args)
T end(T... args)
T is_same_v
bool lexicalCastChecked(Out &out, In in)
Intelligently convert from one type to another.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
std::string trim_whitespace(std::string str)
std::optional< std::uint64_t > to_uint64(std::string const &s)
bool parseUrl(parsedURL &pUrl, std::string const &strUrl)
std::string sqlBlobLiteral(Blob const &blob)
Format arbitrary binary data as an SQLite "blob literal".
bool isProperlyFormedTomlDomain(std::string_view domain)
Determines if the given string looks like a TOML-file hosting domain.
T push_back(T... args)
T reserve(T... args)
T size(T... args)
std::optional< std::uint16_t > port