diff --git a/CHANGELOG.md b/CHANGELOG.md index dc92e7a5..0e8fcf41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ HTTP: * Use message::need_eof in example servers * Use synchronous writes in chunk output example +WebSocket: + +* Fix utf8 validation for autobahn + API Changes: * Remove serializer::keep_alive diff --git a/include/boost/beast/websocket/detail/utf8_checker.hpp b/include/boost/beast/websocket/detail/utf8_checker.hpp index 08f35a6e..8db2f6c3 100644 --- a/include/boost/beast/websocket/detail/utf8_checker.hpp +++ b/include/boost/beast/websocket/detail/utf8_checker.hpp @@ -109,63 +109,62 @@ write(std::uint8_t const* in, std::size_t size) ++p; return true; } - if((p[0] & 0x60) == 0x40) + if((p[0] & 0xe0) == 0xc0) { - if((p[1] & 0xc0) != 0x80) + if( (p[1] & 0xc0) != 0x80 || + (p[0] & 0xfe) == 0xc0) // overlong return false; p += 2; return true; } if((p[0] & 0xf0) == 0xe0) { - if((p[1] & 0xc0) != 0x80 || - (p[2] & 0xc0) != 0x80 || - (p[0] == 224 && p[1] < 160) || - (p[0] == 237 && p[1] > 159)) - return false; + if( (p[1] & 0xc0) != 0x80 + || (p[2] & 0xc0) != 0x80 + || (p[0] == 0xe0 && (p[1] & 0xe0) == 0x80) // overlong + || (p[0] == 0xed && (p[1] & 0xe0) == 0xa0) // surrogate + //|| (p[0] == 0xef && p[1] == 0xbf && (p[2] & 0xfe) == 0xbe) // U+FFFE or U+FFFF + ) + return false; p += 3; return true; } if((p[0] & 0xf8) == 0xf0) { - if(p[0] > 244 || - (p[1] & 0xc0) != 0x80 || - (p[2] & 0xc0) != 0x80 || - (p[3] & 0xc0) != 0x80 || - (p[0] == 240 && p[1] < 144) || - (p[0] == 244 && p[1] > 143)) - return false; + if( (p[1] & 0xc0) != 0x80 + || (p[2] & 0xc0) != 0x80 + || (p[3] & 0xc0) != 0x80 + || (p[0] == 0xf0 && (p[1] & 0xf0) == 0x80) // overlong + || (p[0] == 0xf4 && p[1] > 0x8f) || p[0] > 0xf4 // > U+10FFFF + ) + return false; p += 4; return true; } return false; }; - auto const valid_have = + auto const fail_fast = [&]() { - if((cp_[0] & 0x60) == 0x40) - return cp_[0] <= 223; - if((cp_[0] & 0xf0) == 0xe0) + auto const n = p_ - cp_; + switch(n) { - if(p_ - cp_ > 1 && - ((cp_[1] & 0xc0) != 0x80 || - (cp_[0] == 224 && cp_[1] < 160) || - (cp_[0] == 237 && cp_[1] > 159))) - return false; - return true; + default: + BOOST_ASSERT(false); + BOOST_BEAST_FALLTHROUGH; + case 1: + cp_[1] = 0x81; + BOOST_BEAST_FALLTHROUGH; + case 2: + cp_[2] = 0x81; + BOOST_BEAST_FALLTHROUGH; + case 3: + cp_[3] = 0x81; + BOOST_BEAST_FALLTHROUGH; + break; } - if((cp_[0] & 0xf8) == 0xf0) - { - auto const n = p_ - cp_; - if(n > 2 && (cp_[2] & 0xc0) != 0x80) - return false; - if(n > 1 && - ((cp_[1] & 0xc0) != 0x80 || - (cp_[0] == 240 && cp_[1] < 144) || - (cp_[0] == 244 && cp_[1] > 143))) - return false; - } - return true; + std::uint8_t const* p = cp_; + return ! valid(p); }; auto const needed = [](std::uint8_t const v) @@ -207,7 +206,7 @@ write(std::uint8_t const* in, std::size_t size) // Do partial validation on the incomplete // code point, this is called "Fail fast" // in Autobahn|Testsuite parlance. - return valid_have(); + return ! fail_fast(); } // Complete code point, validate it @@ -320,7 +319,7 @@ tail: // Do partial validation on the incomplete // code point, this is called "Fail fast" // in Autobahn|Testsuite parlance. - return valid_have(); + return ! fail_fast(); } } return true; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 1248536a..82f02fb5 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -12,11 +12,11 @@ include_directories (./extras/include) include_directories (../subtree/unit_test/include) file (GLOB_RECURSE EXTRAS_INCLUDES - ${PROJECT_SOURCE_DIR}/test/extras/include/boost/beast/*.hpp - ${PROJECT_SOURCE_DIR}/test/extras/include/boost/beast/*.ipp - ${PROJECT_SOURCE_DIR}/subtree/unit_test/include/beast/*.hpp - ${PROJECT_SOURCE_DIR}/subtree/unit_test/include/beast/*.ipp -) + ${PROJECT_SOURCE_DIR}/test/extras/include/*.hpp + ${PROJECT_SOURCE_DIR}/test/extras/include/*.ipp + ${PROJECT_SOURCE_DIR}/subtree/unit_test/include/*.hpp + ${PROJECT_SOURCE_DIR}/subtree/unit_test/include/*.ipp + ) set (TEST_MAIN ${PROJECT_SOURCE_DIR}/subtree/unit_test/include/boost/beast/unit_test/main.cpp)