Skip to content

Commit ce96a31

Browse files
authored
Trim whitespace and nulls the same way. (#1233)
1 parent 2a8c17e commit ce96a31

File tree

3 files changed

+85
-56
lines changed

3 files changed

+85
-56
lines changed

Release/include/cpprest/asyncrt_utils.h

+20
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,26 @@ inline bool __cdecl is_alnum(Elem ch) CPPREST_NOEXCEPT
373373
return (uch <= static_cast<UElem>('z') && is_alnum(static_cast<unsigned char>(uch)));
374374
}
375375

376+
/// <summary>
377+
/// Our own implementation of whitespace test instead of std::isspace to avoid
378+
/// taking global lock for performance reasons.
379+
/// The following characters are considered whitespace:
380+
/// 0x09 == Horizontal Tab
381+
/// 0x0A == Line Feed
382+
/// 0x0B == Vertical Tab
383+
/// 0x0C == Form Feed
384+
/// 0x0D == Carrage Return
385+
/// 0x20 == Space
386+
/// </summary>
387+
template<class Elem>
388+
inline bool __cdecl is_space(Elem ch) CPPREST_NOEXCEPT
389+
{
390+
// assumes 'x' == L'x' for the ASCII range
391+
typedef typename std::make_unsigned<Elem>::type UElem;
392+
const auto uch = static_cast<UElem>(ch);
393+
return uch == 0x20u || (uch >= 0x09u && uch <= 0x0Du);
394+
}
395+
376396
/// <summary>
377397
/// Simplistic implementation of make_unique. A better implementation would be based on variadic templates
378398
/// and therefore not be compatible with Dev10.

Release/src/http/client/http_client_winhttp.cpp

+2-46
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "stdafx.h"
1616

1717
#include "../common/x509_cert_utilities.h"
18+
#include "../common/internal_http_helpers.h"
1819
#include "cpprest/http_headers.h"
1920
#include "http_client_impl.h"
2021
#include <Wincrypt.h>
@@ -99,51 +100,6 @@ static http::status_code parse_status_code(HINTERNET request_handle)
99100
return (unsigned short)_wtoi(buffer.c_str());
100101
}
101102

102-
// Helper function to trim leading and trailing null characters from a string.
103-
static void trim_nulls(utility::string_t& str)
104-
{
105-
if (str.empty())
106-
{
107-
return;
108-
}
109-
110-
auto first = str.begin();
111-
auto last = str.end();
112-
113-
if (*first)
114-
{
115-
--last;
116-
if (*last)
117-
{
118-
// no nulls to remove
119-
return;
120-
}
121-
122-
// nulls at the back to remove
123-
do
124-
{
125-
--last;
126-
} while (*last == utility::char_t {});
127-
++last;
128-
str.erase(last, str.end());
129-
return;
130-
}
131-
132-
// nulls at the front, and maybe the back, to remove
133-
first = std::find_if(str.begin(), last, [](const utility::char_t c) { return c != utility::char_t {}; });
134-
135-
if (first != last)
136-
{
137-
do
138-
{
139-
--last;
140-
} while (*last == utility::char_t {});
141-
++last;
142-
}
143-
144-
str.assign(first, last);
145-
}
146-
147103
// Helper function to get the reason phrase from a WinHTTP response.
148104
static utility::string_t parse_reason_phrase(HINTERNET request_handle)
149105
{
@@ -159,7 +115,7 @@ static utility::string_t parse_reason_phrase(HINTERNET request_handle)
159115
&length,
160116
WINHTTP_NO_HEADER_INDEX);
161117
// WinHTTP reports back the wrong length, trim any null characters.
162-
trim_nulls(phrase);
118+
::web::http::details::trim_nulls(phrase);
163119
return phrase;
164120
}
165121

Release/src/http/common/internal_http_helpers.h

+63-10
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#pragma once
77

8+
#include "cpprest/asyncrt_utils.h"
89
#include "cpprest/details/basic_types.h"
910
#include <string>
1011

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

22-
// simple helper functions to trim whitespace.
23+
template<class Char, class Fn>
24+
void trim_if(std::basic_string<Char>& str, Fn test)
25+
{
26+
if (str.empty())
27+
{
28+
return;
29+
}
30+
31+
auto first = str.begin();
32+
auto last = str.end();
33+
34+
if (test(*first))
35+
{
36+
// removals at the front, and maybe the back
37+
for (;;)
38+
{
39+
++first;
40+
if (first == last)
41+
{
42+
// all removals
43+
str.clear();
44+
return;
45+
}
46+
47+
if (!test(*first))
48+
{
49+
break;
50+
}
51+
}
52+
53+
do
54+
{
55+
--last;
56+
} while (test(*last));
57+
++last;
58+
str.assign(first, last);
59+
return;
60+
}
61+
62+
// no removals at the front, only maybe the back
63+
--last;
64+
if (!test(*last))
65+
{
66+
// no removals at all
67+
return;
68+
}
69+
70+
do
71+
{
72+
--last;
73+
} while (test(*last));
74+
++last;
75+
str.erase(last, str.end());
76+
}
77+
78+
template<class Char>
79+
void trim_nulls(std::basic_string<Char>& str)
80+
{
81+
trim_if(str, [](const Char c) { return c == Char {}; });
82+
}
83+
2384
template<class Char>
2485
void trim_whitespace(std::basic_string<Char>& str)
2586
{
26-
size_t index;
27-
// trim left whitespace
28-
for (index = 0; index < str.size() && isspace(str[index]); ++index)
29-
;
30-
str.erase(0, index);
31-
// trim right whitespace
32-
for (index = str.size(); index > 0 && isspace(str[index - 1]); --index)
33-
;
34-
str.erase(index);
87+
trim_if(str, [](const Char c) { return ::utility::details::is_space(c); });
3588
}
3689

3790
bool validate_method(const utility::string_t& method);

0 commit comments

Comments
 (0)