-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update codebase from boost::string_view into std::string_view #4509
Changes from 2 commits
ba1da15
3850093
1141e0f
c966149
efaf7ae
92fda38
8c17a5c
eada2c3
4967121
6dbfd7f
e4015fd
be6e9be
9d9f40e
0c39f13
8da02e5
a433207
2cf0eb8
85e001d
88412ea
b780312
999d9c2
cee5ff8
ac77412
cfa960f
5313b13
204f9f4
d851b16
49968bf
a20907f
d3d309a
fcf1375
3cda316
ba99ab4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,13 +39,14 @@ doPing(RPC::JsonContext& context) | |
break; | ||
case Role::IDENTIFIED: | ||
ret[jss::role] = "identified"; | ||
ret[jss::username] = context.headers.user.to_string(); | ||
// Can I avoid making expensive copies for std::string? | ||
ret[jss::username] = std::string{context.headers.user}; | ||
if (context.headers.forwardedFor.size()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @scottschurr I couldn't think of a cheaper solution for this piece of code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At this level of the source code I'm not seeing Remember, there are lots of places that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I understand. I'm trying to port from this dependence on boost to std. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the clarification. I don't think there's currently any way to make this cheaper than what you have done here. The Alternatively, we could update the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok, thanks for the suggestions Scott! |
||
ret[jss::ip] = context.headers.forwardedFor.to_string(); | ||
ret[jss::ip] = std::string{context.headers.forwardedFor}; | ||
break; | ||
case Role::PROXY: | ||
ret[jss::role] = "proxied"; | ||
ret[jss::ip] = context.headers.forwardedFor.to_string(); | ||
ret[jss::ip] = std::string{context.headers.forwardedFor}; | ||
default:; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -96,7 +96,7 @@ requestRole( | |
Port const& port, | ||
Json::Value const& params, | ||
beast::IP::Endpoint const& remoteIp, | ||
boost::string_view const& user) | ||
std::string_view user) | ||
{ | ||
if (isAdmin(port, params, remoteIp.address())) | ||
return Role::ADMIN; | ||
|
@@ -142,8 +142,8 @@ requestInboundEndpoint( | |
Resource::Manager& manager, | ||
beast::IP::Endpoint const& remoteAddress, | ||
Role const& role, | ||
boost::string_view const& user, | ||
boost::string_view const& forwardedFor) | ||
std::string_view user, | ||
std::string_view forwardedFor) | ||
{ | ||
if (isUnlimited(role)) | ||
return manager.newUnlimitedEndpoint(remoteAddress); | ||
|
@@ -152,18 +152,18 @@ requestInboundEndpoint( | |
remoteAddress, role == Role::PROXY, forwardedFor); | ||
} | ||
|
||
static boost::string_view | ||
extractIpAddrFromField(boost::string_view field) | ||
static std::string_view | ||
extractIpAddrFromField(std::string_view field) | ||
{ | ||
// Lambda to trim leading and trailing spaces on the field. | ||
auto trim = [](boost::string_view str) -> boost::string_view { | ||
boost::string_view ret = str; | ||
auto trim = [](std::string_view str) -> std::string_view { | ||
std::string_view ret = str; | ||
|
||
// Only do the work if there's at least one leading space. | ||
if (!ret.empty() && ret.front() == ' ') | ||
{ | ||
std::size_t const firstNonSpace = ret.find_first_not_of(' '); | ||
if (firstNonSpace == boost::string_view::npos) | ||
if (firstNonSpace == std::string_view::npos) | ||
// We know there's at least one leading space. So if we got | ||
// npos, then it must be all spaces. Return empty string_view. | ||
return {}; | ||
|
@@ -178,7 +178,7 @@ extractIpAddrFromField(boost::string_view field) | |
c == ' ' || c == '\r' || c == '\n') | ||
{ | ||
std::size_t const lastNonSpace = ret.find_last_not_of(" \r\n"); | ||
if (lastNonSpace == boost::string_view::npos) | ||
if (lastNonSpace == std::string_view::npos) | ||
// We know there's at least one leading space. So if we | ||
// got npos, then it must be all spaces. | ||
return {}; | ||
|
@@ -189,7 +189,7 @@ extractIpAddrFromField(boost::string_view field) | |
return ret; | ||
}; | ||
|
||
boost::string_view ret = trim(field); | ||
std::string_view ret = trim(field); | ||
if (ret.empty()) | ||
return {}; | ||
|
||
|
@@ -251,13 +251,13 @@ extractIpAddrFromField(boost::string_view field) | |
|
||
// If there's a port appended to the IP address, strip that by | ||
// terminating at the colon. | ||
if (std::size_t colon = ret.find(':'); colon != boost::string_view::npos) | ||
if (std::size_t colon = ret.find(':'); colon != std::string_view::npos) | ||
ret = ret.substr(0, colon); | ||
|
||
return ret; | ||
} | ||
|
||
boost::string_view | ||
std::string_view | ||
forwardedFor(http_request_type const& request) | ||
{ | ||
// Look for the Forwarded field in the request. | ||
|
@@ -286,10 +286,9 @@ forwardedFor(http_request_type const& request) | |
|
||
// We found a "for=". Scan for the end of the IP address. | ||
std::size_t const pos = [&found, &it]() { | ||
std::size_t pos = | ||
boost::string_view(found, it->value().end() - found) | ||
.find_first_of(",;"); | ||
if (pos != boost::string_view::npos) | ||
std::size_t pos = std::string_view(found, it->value().end() - found) | ||
.find_first_of(",;"); | ||
if (pos != std::string_view::npos) | ||
return pos; | ||
|
||
return it->value().size() - forStr.size(); | ||
|
@@ -305,7 +304,10 @@ forwardedFor(http_request_type const& request) | |
std::size_t found = it->value().find(','); | ||
if (found == boost::string_view::npos) | ||
found = it->value().length(); | ||
return extractIpAddrFromField(it->value().substr(0, found)); | ||
// http_request_type has a dependency on boost. Explicitly convert such | ||
// boost::string_view into std::string_view | ||
return extractIpAddrFromField( | ||
std::string_view{it->value().substr(0, found).data(), found}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you're doing a bit more work than necessary here. Since the
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok, this makes sense 👍 |
||
} | ||
|
||
return {}; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -559,8 +559,9 @@ ServerHandlerImp::processSession( | |
[&] { | ||
auto const iter = session->request().find("X-User"); | ||
if (iter != session->request().end()) | ||
return iter->value(); | ||
return boost::beast::string_view{}; | ||
return std::string_view{ | ||
iter->value().data(), iter->value().length()}; | ||
return std::string_view{}; | ||
}()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you want you can remove the necessity of typing
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thank you very much Scott! this looks nicer 👍 |
||
|
||
if (beast::rfc2616::is_keep_alive(session->request())) | ||
|
@@ -592,8 +593,8 @@ ServerHandlerImp::processRequest( | |
beast::IP::Endpoint const& remoteIPAddress, | ||
Output&& output, | ||
std::shared_ptr<JobQueue::Coro> coro, | ||
boost::string_view forwardedFor, | ||
boost::string_view user) | ||
std::string_view forwardedFor, | ||
std::string_view user) | ||
{ | ||
auto rpcJ = app_.journal("RPC"); | ||
|
||
|
@@ -847,8 +848,14 @@ ServerHandlerImp::processRequest( | |
*/ | ||
if (role != Role::IDENTIFIED && role != Role::PROXY) | ||
{ | ||
forwardedFor.clear(); | ||
user.clear(); | ||
// Simulate the clearing of string_view through a swap. Is this a | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not comfortable with this method. Since these strings ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think you might be able to use use...
What do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes thanks, this looks much cleaner 👍 I'll incorporate this change. |
||
// good candidate for std::string_view? This is due to a discrepency | ||
// between boost::string_view versus std::string_view's APIs | ||
// forwardedFor.clear(); | ||
std::string_view empty_str; | ||
forwardedFor.swap(empty_str); | ||
// user.clear(); | ||
user.swap(empty_str); | ||
} | ||
|
||
JLOG(m_journal.debug()) << "Query: " << strMethod << params; | ||
|
thejohnfreeman marked this conversation as resolved.
Show resolved
Hide resolved
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd personally leave this alone. You're adding complexity for no real reason here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I leave type-deduction to auto, I'm not 100% sure if it is deduced as
std::string_view
. On line 1006, there is a comparison ofkey
withstd::string_view::npos
.My observation is that construction of
std::string_view
without the second length parameter results in garbage values at the end ofkey
. I'm not really sure why that's happening.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I sympathize with your position, @nbougalis. But
key
is passed toValidatorList::getAvailable()
, which accepts astd::string_view
. The conversion must happen somewhere.I think perhaps the conversion can be done a bit more cleanly like this:
Since the
auto
is gone we can always see what we're handling. And it limits the scope of theboost::string_view
as much as possible. But that doesn't remove the fundamental objection.FWIW, I have a theory regarding the garbage values at the end of
key
if the length parameter is omitted. Remember that astring_view
is a pointer and a length. There is no guarantee of a null termination to the string of characters contained by astring_view
. This is one of the things that can makestring_view
dangerous to use.If you construct a
string_view
with only achar*
, then thestring_view
constructor must determine the length of the string it represents. It does so by scanning for a null termination. Since the oldstring_view
you are using to construct the newstring_view
is not required to contain a null terminated string, the constructor of the newstring_view
may walk past the end of valid characters, potentially resulting in undefined behavior.For more details see the description of constructor 4 on this page: https://en.cppreference.com/w/cpp/string/basic_string_view/basic_string_view
The lesson from this is that the only situation where a
string_view
should be constructed with achar*
(and no length) is if you know thechar*
is a c-style string with a null termination.string_view
is often a nice optimization. But it's easy to mess up with it. We must handle the knife carefully.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i missed this comment, thanks for the explanation Scott! yes, that makes sense