Skip to content

Commit

Permalink
Trim whitespace and nulls the same way. (#1233)
Browse files Browse the repository at this point in the history
  • Loading branch information
BillyONeal authored Aug 28, 2019
1 parent 2a8c17e commit ce96a31
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 56 deletions.
20 changes: 20 additions & 0 deletions Release/include/cpprest/asyncrt_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,26 @@ inline bool __cdecl is_alnum(Elem ch) CPPREST_NOEXCEPT
return (uch <= static_cast<UElem>('z') && is_alnum(static_cast<unsigned char>(uch)));
}

/// <summary>
/// Our own implementation of whitespace test instead of std::isspace to avoid
/// taking global lock for performance reasons.
/// The following characters are considered whitespace:
/// 0x09 == Horizontal Tab
/// 0x0A == Line Feed
/// 0x0B == Vertical Tab
/// 0x0C == Form Feed
/// 0x0D == Carrage Return
/// 0x20 == Space
/// </summary>
template<class Elem>
inline bool __cdecl is_space(Elem ch) CPPREST_NOEXCEPT
{
// assumes 'x' == L'x' for the ASCII range
typedef typename std::make_unsigned<Elem>::type UElem;
const auto uch = static_cast<UElem>(ch);
return uch == 0x20u || (uch >= 0x09u && uch <= 0x0Du);
}

/// <summary>
/// Simplistic implementation of make_unique. A better implementation would be based on variadic templates
/// and therefore not be compatible with Dev10.
Expand Down
48 changes: 2 additions & 46 deletions Release/src/http/client/http_client_winhttp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "stdafx.h"

#include "../common/x509_cert_utilities.h"
#include "../common/internal_http_helpers.h"
#include "cpprest/http_headers.h"
#include "http_client_impl.h"
#include <Wincrypt.h>
Expand Down Expand Up @@ -99,51 +100,6 @@ static http::status_code parse_status_code(HINTERNET request_handle)
return (unsigned short)_wtoi(buffer.c_str());
}

// Helper function to trim leading and trailing null characters from a string.
static void trim_nulls(utility::string_t& str)
{
if (str.empty())
{
return;
}

auto first = str.begin();
auto last = str.end();

if (*first)
{
--last;
if (*last)
{
// no nulls to remove
return;
}

// nulls at the back to remove
do
{
--last;
} while (*last == utility::char_t {});
++last;
str.erase(last, str.end());
return;
}

// nulls at the front, and maybe the back, to remove
first = std::find_if(str.begin(), last, [](const utility::char_t c) { return c != utility::char_t {}; });

if (first != last)
{
do
{
--last;
} while (*last == utility::char_t {});
++last;
}

str.assign(first, last);
}

// Helper function to get the reason phrase from a WinHTTP response.
static utility::string_t parse_reason_phrase(HINTERNET request_handle)
{
Expand All @@ -159,7 +115,7 @@ static utility::string_t parse_reason_phrase(HINTERNET request_handle)
&length,
WINHTTP_NO_HEADER_INDEX);
// WinHTTP reports back the wrong length, trim any null characters.
trim_nulls(phrase);
::web::http::details::trim_nulls(phrase);
return phrase;
}

Expand Down
73 changes: 63 additions & 10 deletions Release/src/http/common/internal_http_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#pragma once

#include "cpprest/asyncrt_utils.h"
#include "cpprest/details/basic_types.h"
#include <string>

Expand All @@ -19,19 +20,71 @@ namespace details
/// </summary>
utility::string_t get_default_reason_phrase(status_code code);

// simple helper functions to trim whitespace.
template<class Char, class Fn>
void trim_if(std::basic_string<Char>& str, Fn test)
{
if (str.empty())
{
return;
}

auto first = str.begin();
auto last = str.end();

if (test(*first))
{
// removals at the front, and maybe the back
for (;;)
{
++first;
if (first == last)
{
// all removals
str.clear();
return;
}

if (!test(*first))
{
break;
}
}

do
{
--last;
} while (test(*last));
++last;
str.assign(first, last);
return;
}

// no removals at the front, only maybe the back
--last;
if (!test(*last))
{
// no removals at all
return;
}

do
{
--last;
} while (test(*last));
++last;
str.erase(last, str.end());
}

template<class Char>
void trim_nulls(std::basic_string<Char>& str)
{
trim_if(str, [](const Char c) { return c == Char {}; });
}

template<class Char>
void trim_whitespace(std::basic_string<Char>& str)
{
size_t index;
// trim left whitespace
for (index = 0; index < str.size() && isspace(str[index]); ++index)
;
str.erase(0, index);
// trim right whitespace
for (index = str.size(); index > 0 && isspace(str[index - 1]); --index)
;
str.erase(index);
trim_if(str, [](const Char c) { return ::utility::details::is_space(c); });
}

bool validate_method(const utility::string_t& method);
Expand Down

0 comments on commit ce96a31

Please sign in to comment.