Skip to content

Commit 0f7d2c3

Browse files
garethsbras0219-msft
authored andcommitted
Fix a regression in parsing an HTTP-Version string (#677)
* Fix a regression in parsing an HTTP-Version string, pulling the parsing code out into http_version::from_string; add extra unit tests * Restore EOL: Unix * Remove dependency on locale from http_version member functions. Prefer UTF-8.
1 parent a159e4e commit 0f7d2c3

File tree

4 files changed

+66
-11
lines changed

4 files changed

+66
-11
lines changed

Release/include/cpprest/http_msg.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,17 @@ struct http_version
5858
inline bool operator>=(const http_version& other) const { return !(*this < other); }
5959
inline bool operator>(const http_version& other) const { return !(*this < other || *this == other); }
6060
inline bool operator<=(const http_version& other) const { return *this < other || *this == other; }
61+
62+
/// <summary>
63+
/// Creates <c>http_version</c> from an HTTP-Version string, "HTTP" "/" 1*DIGIT "." 1*DIGIT.
64+
/// </summary>
65+
/// <returns>Returns a <c>http_version</c> of {0, 0} if not successful.</returns>
66+
static _ASYNCRTIMP http_version __cdecl from_string(const utility::string_t& http_version_string);
67+
68+
/// <summary>
69+
/// Returns the string representation of the <c>http_version</c>.
70+
/// </summary>
71+
_ASYNCRTIMP std::string to_utf8string() const;
6172
};
6273

6374
/// <summary>

Release/src/http/common/http_msg.cpp

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,35 @@ void parse_headers_string(_Inout_z_ utf16char *headersStr, http_headers &headers
254254

255255
}
256256

257+
http_version __cdecl http_version::from_string(const utility::string_t& http_version_string)
258+
{
259+
utility::istringstream_t str(http_version_string);
260+
str.imbue(std::locale::classic());
261+
262+
utility::string_t http; std::getline(str, http, _XPLATSTR('/'));
263+
unsigned int major = 0; str >> major;
264+
utility::char_t dot = _XPLATSTR('\0'); str >> dot;
265+
unsigned int minor = 0; str >> minor;
266+
267+
// check no failure, fully consumed, and correct fixed text
268+
if (!str.fail() && str.eof() && _XPLATSTR("HTTP") == http && _XPLATSTR('.') == dot)
269+
{
270+
return{ (uint8_t)major, (uint8_t)minor };
271+
}
272+
return{ 0, 0 };
273+
}
274+
275+
std::string http_version::to_utf8string() const
276+
{
277+
std::string ret;
278+
ret.reserve(8);
279+
ret.append("HTTP/");
280+
ret.append(std::to_string(static_cast<unsigned int>(major)));
281+
ret.append(".");
282+
ret.append(std::to_string(static_cast<unsigned int>(minor)));
283+
return ret;
284+
}
285+
257286
static const utility::char_t * stream_was_set_explicitly = _XPLATSTR("A stream was set on the message and extraction is not possible");
258287
static const utility::char_t * unsupported_charset = _XPLATSTR("Charset must be iso-8859-1, utf-8, utf-16, utf-16le, or utf-16be to be extracted.");
259288

@@ -1052,4 +1081,4 @@ const http_version http_versions::HTTP_1_1 = { 1, 1 };
10521081
#undef DAT
10531082
#endif
10541083
}} // namespace web::http
1055-
1084+

Release/src/http/listener/http_server_asio.cpp

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -659,16 +659,8 @@ will_deref_and_erase_t asio_server_connection::handle_http_line(const boost::sys
659659
std::string http_version = http_path_and_version.substr(http_path_and_version.size() - VersionPortionSize + 1, VersionPortionSize - 2);
660660

661661
auto m_request_impl = m_request._get_impl().get();
662-
web::http::http_version parsed_version = { 0, 0 };
663-
if (boost::starts_with(http_version, "HTTP/"))
664-
{
665-
std::istringstream version{ http_version.substr(5) };
666-
version >> parsed_version.major;
667-
char dot; version >> dot;
668-
version >> parsed_version.minor;
669-
670-
m_request_impl->_set_http_version(parsed_version);
671-
}
662+
web::http::http_version parsed_version = web::http::http_version::from_string(utility::conversions::to_string_t(http_version));
663+
m_request_impl->_set_http_version(parsed_version);
672664

673665
// if HTTP version is 1.0 then disable pipelining
674666
if (parsed_version == web::http::http_versions::HTTP_1_0)

Release/tests/functional/http/listener/request_handler_tests.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,29 @@ TEST_FIXTURE(uri_address, test_leaks)
450450

451451
TEST_FIXTURE(uri_address, http_version)
452452
{
453+
// formatting should succeed
454+
VERIFY_IS_TRUE("HTTP/0.9" == http_versions::HTTP_0_9.to_utf8string());
455+
VERIFY_IS_TRUE("HTTP/1.0" == http_versions::HTTP_1_0.to_utf8string());
456+
VERIFY_IS_TRUE("HTTP/1.1" == http_versions::HTTP_1_1.to_utf8string());
457+
VERIFY_IS_TRUE("HTTP/12.3" == (http_version{ 12, 3 }).to_utf8string());
458+
// parsing should succeed
459+
VERIFY_IS_TRUE(http_version::from_string(U("HTTP/0.9")) == http_versions::HTTP_0_9);
460+
VERIFY_IS_TRUE(http_version::from_string(U("HTTP/1.0")) == http_versions::HTTP_1_0);
461+
VERIFY_IS_TRUE(http_version::from_string(U("HTTP/1.1")) == http_versions::HTTP_1_1);
462+
VERIFY_IS_TRUE((http_version::from_string(U("HTTP/12.3")) == http_version{ 12, 3 }));
463+
// parsing should fail
464+
http_version unknown = { 0, 0 };
465+
VERIFY_IS_TRUE(http_version::from_string(U("http/12.3")) == unknown);
466+
VERIFY_IS_TRUE(http_version::from_string(U("HTTP/12.3foo")) == unknown);
467+
VERIFY_IS_TRUE(http_version::from_string(U("HTTP/12.")) == unknown);
468+
VERIFY_IS_TRUE(http_version::from_string(U("HTTP/12")) == unknown);
469+
VERIFY_IS_TRUE(http_version::from_string(U("HTTP/.3")) == unknown);
470+
VERIFY_IS_TRUE(http_version::from_string(U("HTTP/")) == unknown);
471+
VERIFY_IS_TRUE(http_version::from_string(U("HTTP")) == unknown);
472+
VERIFY_IS_TRUE(http_version::from_string(U("HTTP")) == unknown);
473+
VERIFY_IS_TRUE(http_version::from_string(U("foo")) == unknown);
474+
VERIFY_IS_TRUE(http_version::from_string(U("")) == unknown);
475+
453476
http_listener listener(U("http://localhost:45678/path1"));
454477
listener.open().wait();
455478

0 commit comments

Comments
 (0)