rippled
Loading...
Searching...
No Matches
StringUtilities.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2013 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <xrpl/basics/Blob.h>
21#include <xrpl/basics/StringUtilities.h>
22#include <xrpl/beast/core/LexicalCast.h>
23#include <xrpl/beast/net/IPEndpoint.h>
24
25#include <boost/algorithm/hex.hpp>
26#include <boost/algorithm/string/case_conv.hpp>
27#include <boost/algorithm/string/trim.hpp>
28#include <boost/regex/v5/regbase.hpp>
29#include <boost/regex/v5/regex.hpp>
30#include <boost/regex/v5/regex_fwd.hpp>
31#include <boost/regex/v5/regex_match.hpp>
32
33#include <cstdint>
34#include <iterator>
35#include <optional>
36#include <string>
37#include <string_view>
38
39namespace ripple {
40
42sqlBlobLiteral(Blob const& blob)
43{
45
46 j.reserve(blob.size() * 2 + 3);
47 j.push_back('X');
48 j.push_back('\'');
49 boost::algorithm::hex(blob.begin(), blob.end(), std::back_inserter(j));
50 j.push_back('\'');
51
52 return j;
53}
54
55bool
56parseUrl(parsedURL& pUrl, std::string const& strUrl)
57{
58 // scheme://username:password@hostname:port/rest
59 static boost::regex reUrl(
60 "(?i)\\`\\s*"
61 // required scheme
62 "([[:alpha:]][-+.[:alpha:][:digit:]]*?):"
63 // We choose to support only URIs whose `hier-part` has the form
64 // `"//" authority path-abempty`.
65 "//"
66 // optional userinfo
67 "(?:([^:@/]*?)(?::([^@/]*?))?@)?"
68 // optional host
69 "([[:digit:]:]*[[:digit:]]|\\[[^]]+\\]|[^:/?#]*?)"
70 // optional port
71 "(?::([[:digit:]]+))?"
72 // optional path
73 "(/.*)?"
74 "\\s*?\\'");
75 boost::smatch smMatch;
76
77 // Bail if there is no match.
78 try
79 {
80 if (!boost::regex_match(strUrl, smMatch, reUrl))
81 return false;
82 }
83 catch (...)
84 {
85 return false;
86 }
87
88 pUrl.scheme = smMatch[1];
89 boost::algorithm::to_lower(pUrl.scheme);
90 pUrl.username = smMatch[2];
91 pUrl.password = smMatch[3];
92 std::string const domain = smMatch[4];
93 // We need to use Endpoint to parse the domain to
94 // strip surrounding brackets from IPv6 addresses,
95 // e.g. [::1] => ::1.
96 auto const result = beast::IP::Endpoint::from_string_checked(domain);
97 pUrl.domain = result ? result->address().to_string() : domain;
98 std::string const port = smMatch[5];
99 if (!port.empty())
100 {
101 pUrl.port = beast::lexicalCast<std::uint16_t>(port);
102
103 // For inputs larger than 2^32-1 (65535), lexicalCast returns 0.
104 // parseUrl returns false for such inputs.
105 if (pUrl.port == 0)
106 {
107 return false;
108 }
109 }
110 pUrl.path = smMatch[6];
111
112 return true;
113}
114
117{
118 boost::trim(str);
119 return str;
120}
121
124{
125 std::uint64_t result;
126 if (beast::lexicalCastChecked(result, s))
127 return result;
128 return std::nullopt;
129}
130
131bool
133{
134 // The domain must be between 4 and 128 characters long
135 if (domain.size() < 4 || domain.size() > 128)
136 return false;
137
138 // This regular expression should do a decent job of weeding out
139 // obviously wrong domain names but it isn't perfect. It does not
140 // really support IDNs. If this turns out to be an issue, a more
141 // thorough regex can be used or this check can just be removed.
142 static boost::regex const re(
143 "^" // Beginning of line
144 "(" // Beginning of a segment
145 "(?!-)" // - must not begin with '-'
146 "[a-zA-Z0-9-]{1,63}" // - only alphanumeric and '-'
147 "(?<!-)" // - must not end with '-'
148 "\\." // segment separator
149 ")+" // 1 or more segments
150 "[A-Za-z]{2,63}" // TLD
151 "$" // End of line
152 ,
153 boost::regex_constants::optimize);
154
155 return boost::regex_match(domain.begin(), domain.end(), re);
156}
157
158} // 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:25
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