diff --git a/client_http.hpp b/client_http.hpp index 2ad46c1..945b7a2 100644 --- a/client_http.hpp +++ b/client_http.hpp @@ -9,6 +9,53 @@ #include #include +namespace SimpleWeb { + class HeaderEndMatch { + int crlfcrlf = 0; + int lflf = 0; + + public: + std::pair, bool> operator()(asio::buffers_iterator begin, asio::buffers_iterator end) { + auto it = begin; + for(; it != end; ++it) { + if(*it == '\n') { + if(crlfcrlf == 1) + ++crlfcrlf; + else if(crlfcrlf == 2) + crlfcrlf = 0; + else if(crlfcrlf == 3) + return {++it, true}; + if(lflf == 0) + ++lflf; + else if(lflf == 1) + return {++it, true}; + } + else if(*it == '\r') { + if(crlfcrlf == 0) + ++crlfcrlf; + else if(crlfcrlf == 2) + ++crlfcrlf; + lflf = 0; + } + else { + crlfcrlf = 0; + lflf = 0; + } + } + return {it, false}; + } + }; +} // namespace SimpleWeb +#ifndef USE_STANDALONE_ASIO +namespace boost { +#endif + namespace asio { + template <> struct is_match_condition : public std::true_type {}; + } // namespace asio +#ifndef USE_STANDALONE_ASIO +} // namespace boost +#endif + namespace SimpleWeb { template class Client; @@ -468,7 +515,7 @@ namespace SimpleWeb { void read(const std::shared_ptr &session) { session->connection->set_timeout(); - asio::async_read_until(*session->connection->socket, session->response->streambuf, "\r\n\r\n", [this, session](const error_code &ec, std::size_t bytes_transferred) { + asio::async_read_until(*session->connection->socket, session->response->streambuf, HeaderEndMatch(), [this, session](const error_code &ec, std::size_t bytes_transferred) { session->connection->cancel_timeout(); auto lock = session->connection->handler_runner->continue_lock(); if(!lock) diff --git a/tests/io_test.cpp b/tests/io_test.cpp index c5efdb2..e29c30a 100644 --- a/tests/io_test.cpp +++ b/tests/io_test.cpp @@ -176,6 +176,14 @@ int main() { response->write("test"); }; + server.resource["^/non-standard-line-endings1$"]["GET"] = [](shared_ptr response, shared_ptr /*request*/) { + *response << "HTTP/1.1 200 OK\r\nname: value\n\n"; + }; + + server.resource["^/non-standard-line-endings2$"]["GET"] = [](shared_ptr response, shared_ptr /*request*/) { + *response << "HTTP/1.1 200 OK\nname: value\n\n"; + }; + thread server_thread([&server]() { // Start server server.start(); @@ -282,6 +290,26 @@ int main() { auto r = client.request("GET", "/session-close-without-correct-header"); ASSERT(r->content.string() == "test"); } + + // Test non-standard line endings + { + auto r = client.request("GET", "/non-standard-line-endings1"); + ASSERT(r->http_version == "1.1"); + ASSERT(r->status_code == "200 OK"); + ASSERT(r->header.size() == 1); + ASSERT(r->header.begin()->first == "name"); + ASSERT(r->header.begin()->second == "value"); + ASSERT(r->content.string().empty()); + } + { + auto r = client.request("GET", "/non-standard-line-endings2"); + ASSERT(r->http_version == "1.1"); + ASSERT(r->status_code == "200 OK"); + ASSERT(r->header.size() == 1); + ASSERT(r->header.begin()->first == "name"); + ASSERT(r->header.begin()->second == "value"); + ASSERT(r->content.string().empty()); + } } { HttpClient client("localhost:8080"); diff --git a/utility.hpp b/utility.hpp index d98ed41..9880822 100644 --- a/utility.hpp +++ b/utility.hpp @@ -283,7 +283,7 @@ namespace SimpleWeb { else return false; if((version_end + 1) < line.size()) - status_code = line.substr(version_end + 1, line.size() - (version_end + 1) - 1); + status_code = line.substr(version_end + 1, line.size() - (version_end + 1) - (line.back() == '\r' ? 1 : 0)); else return false;