Compare commits

...

11 Commits

Author SHA1 Message Date
Benjamin Sergeant
f7a12f52f8 On error while doing a client handshake, additionally display port number next to the host name 2019-09-17 12:08:52 -07:00
Benjamin Sergeant
1be3b8f4b1 rename test file 2019-09-17 12:07:31 -07:00
Benjamin Sergeant
0b844d8361 make test target does not try to install anything into /usr/local 2019-09-12 11:45:31 -07:00
Benjamin Sergeant
57086e28d8 fix unittest warnings + remove trailing spaces 2019-09-12 11:43:52 -07:00
Benjamin Sergeant
a55d4cdb76 update pre-commit file 2019-09-10 22:18:16 -07:00
Benjamin Sergeant
40a45717db update clang format file 2019-09-10 22:17:08 -07:00
Benjamin Sergeant
e853d9ac60 build fixes 2019-09-10 14:05:07 -07:00
Benjamin Sergeant
4ec0d9b113 update appveyor file to new directory structure 2019-09-10 12:33:47 -07:00
Benjamin Sergeant
0fde169aa4 restructure project 2019-09-10 12:19:22 -07:00
Benjamin Sergeant
c09015e870 update ws CLI11 (our command line argument parsing library) to the latest, which fix a compiler bug about optional 2019-09-09 21:25:33 -07:00
Benjamin Sergeant
7bfa6e8478 improve some websocket error messages + add a utility function with unittest to parse status line and stop using scanf which triggers warnings on Windows 2019-09-09 21:23:57 -07:00
60 changed files with 3278 additions and 1007 deletions

View File

@@ -11,7 +11,7 @@ AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: InlineOnly
AllowShortFunctionsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: false
AlwaysBreakTemplateDeclarations: true
@@ -42,5 +42,6 @@ NamespaceIndentation: All
PenaltyReturnTypeOnItsOwnLine: 1000
PointerAlignment: Left
SpaceAfterTemplateKeyword: false
SpaceAfterCStyleCast: true
Standard: Cpp11
UseTab: Never

View File

@@ -5,8 +5,3 @@ repos:
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/pocc/pre-commit-hooks
rev: ''
hooks:
- id: clang-format

View File

@@ -12,8 +12,7 @@ set (CMAKE_CXX_STANDARD 14)
set (CXX_STANDARD_REQUIRED ON)
set (CMAKE_CXX_EXTENSIONS OFF)
# -Wshorten-64-to-32 does not work with clang
if (NOT WIN32)
if (UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic")
endif()
@@ -211,6 +210,15 @@ install(TARGETS ixwebsocket
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_PREFIX}/include/ixwebsocket/
)
if (USE_WS OR USE_TEST)
add_subdirectory(ixcore)
add_subdirectory(ixcrypto)
add_subdirectory(ixcobra)
if (USE_WS)
add_subdirectory(ws)
endif()
if (USE_TEST)
add_subdirectory(test)
endif()
endif()

View File

@@ -1 +1 @@
6.2.0
6.2.1

View File

@@ -9,13 +9,13 @@ install:
- cmd: call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat"
- vcpkg install zlib:x64-windows
- vcpkg install mbedtls:x64-windows
- cd test
- mkdir build
- cd build
- cmake -DCMAKE_TOOLCHAIN_FILE=c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake -DUSE_TLS=1 -G"NMake Makefiles" ..
- cmake -DCMAKE_TOOLCHAIN_FILE=c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake -DUSE_WS=1 -DUSE_TEST=1 -DUSE_TLS=1 -G"NMake Makefiles" ..
- nmake
- cd ..
- build\ixwebsocket_unittest.exe
- cd test
- ..\build\test\ixwebsocket_unittest.exe
cache: c:\tools\vcpkg\installed\

View File

@@ -1,9 +1,16 @@
# Changelog
All notable changes to this project will be documented in this file.
## [6.2.1] - 2019-09-17
- On error while doing a client handshake, additionally display port number next to the host name
## [6.2.0] - 2019-09-09
- websocket and http server: server does not close the bound client socket in many cases
- improve some websocket error messages
- add a utility function with unittest to parse status line and stop using scanf which triggers warnings on Windows
- update ws CLI11 (our command line argument parsing library) to the latest, which fix a compiler bug about optional
## [6.1.0] - 2019-09-08

View File

@@ -59,6 +59,3 @@ app@ca2340eb9106:~$ ws --help
ws is a websocket tool
...
```

30
ixcobra/CMakeLists.txt Normal file
View File

@@ -0,0 +1,30 @@
#
# Author: Benjamin Sergeant
# Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
#
set (IXCOBRA_SOURCES
ixcobra/IXCobraConnection.cpp
ixcobra/IXCobraMetricsThreadedPublisher.cpp
ixcobra/IXCobraMetricsPublisher.cpp
)
set (IXCOBRA_HEADERS
ixcobra/IXCobraConnection.h
ixcobra/IXCobraMetricsThreadedPublisher.h
ixcobra/IXCobraMetricsPublisher.h
)
add_library(ixcobra STATIC
${IXCOBRA_SOURCES}
${IXCOBRA_HEADERS}
)
set(IXCOBRA_INCLUDE_DIRS
.
..
../ixcore
../ixcrypto
../third_party)
target_include_directories( ixcobra PUBLIC ${IXCOBRA_INCLUDE_DIRS} )

19
ixcore/CMakeLists.txt Normal file
View File

@@ -0,0 +1,19 @@
#
# Author: Benjamin Sergeant
# Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
#
set (IXCORE_SOURCES
ixcore/utils/IXCoreLogger.cpp
)
set (IXCORE_HEADERS
ixcore/utils/IXCoreLogger.h
)
add_library(ixcore STATIC
${IXCORE_SOURCES}
${IXCORE_HEADERS}
)
target_include_directories( ixcore PUBLIC . )

54
ixcrypto/CMakeLists.txt Normal file
View File

@@ -0,0 +1,54 @@
#
# Author: Benjamin Sergeant
# Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
#
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../CMake;${CMAKE_MODULE_PATH}")
set (IXCRYPTO_SOURCES
ixcrypto/IXHMac.cpp
ixcrypto/IXBase64.cpp
ixcrypto/IXUuid.cpp
ixcrypto/IXHash.cpp
)
set (IXCRYPTO_HEADERS
ixcrypto/IXHMac.h
ixcrypto/IXBase64.h
ixcrypto/IXUuid.h
ixcrypto/IXHash.h
)
add_library(ixcrypto STATIC
${IXCRYPTO_SOURCES}
${IXCRYPTO_HEADERS}
)
set(IXCRYPTO_INCLUDE_DIRS
.
../ixcore)
target_include_directories( ixcrypto PUBLIC ${IXCRYPTO_INCLUDE_DIRS} )
# hmac computation needs a crypto library
if (WIN32)
set(USE_MBED_TLS TRUE)
endif()
target_compile_definitions(ixcrypto PUBLIC IXCRYPTO_USE_TLS)
if (USE_MBED_TLS)
find_package(MbedTLS REQUIRED)
target_include_directories(ixcrypto PUBLIC ${MBEDTLS_INCLUDE_DIRS})
target_link_libraries(ixcrypto ${MBEDTLS_LIBRARIES})
target_compile_definitions(ixcrypto PUBLIC IXCRYPTO_USE_MBED_TLS)
elseif (APPLE)
elseif (WIN32)
else()
find_package(OpenSSL REQUIRED)
add_definitions(${OPENSSL_DEFINITIONS})
message(STATUS "OpenSSL: " ${OPENSSL_VERSION})
include_directories(${OPENSSL_INCLUDE_DIR})
target_link_libraries(ixcrypto ${OPENSSL_LIBRARIES})
target_compile_definitions(ixcrypto PUBLIC IXCRYPTO_USE_OPEN_SSL)
endif()

View File

@@ -7,12 +7,14 @@
#include "IXHMac.h"
#include "IXBase64.h"
#if defined(IXWEBSOCKET_USE_MBED_TLS)
#if defined(IXCRYPTO_USE_MBED_TLS)
# include <mbedtls/md.h>
#elif defined(__APPLE__)
# include <CommonCrypto/CommonHMAC.h>
#else
#elif defined(IXCRYPTO_USE_OPEN_SSL)
# include <openssl/hmac.h>
#else
# error "Unsupported configuration"
#endif
namespace ix
@@ -22,7 +24,7 @@ namespace ix
constexpr size_t hashSize = 16;
unsigned char hash[hashSize];
#if defined(IXWEBSOCKET_USE_MBED_TLS)
#if defined(IXCRYPTO_USE_MBED_TLS)
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_MD5),
(unsigned char *) key.c_str(), key.size(),
(unsigned char *) data.c_str(), data.size(),
@@ -32,11 +34,13 @@ namespace ix
key.c_str(), key.size(),
data.c_str(), data.size(),
&hash);
#else
#elif defined(IXCRYPTO_USE_OPEN_SSL)
HMAC(EVP_md5(),
key.c_str(), (int) key.size(),
(unsigned char *) data.c_str(), (int) data.size(),
(unsigned char *) hash, nullptr);
#else
# error "Unsupported configuration"
#endif
std::string hashString(reinterpret_cast<char*>(hash), hashSize);

View File

@@ -27,6 +27,36 @@ namespace ix
return out;
}
std::pair<std::string, int> Http::parseStatusLine(const std::string& line)
{
// Request-Line = Method SP Request-URI SP HTTP-Version CRLF
std::string token;
std::stringstream tokenStream(line);
std::vector<std::string> tokens;
// Split by ' '
while (std::getline(tokenStream, token, ' '))
{
tokens.push_back(token);
}
std::string httpVersion;
if (tokens.size() >= 1)
{
httpVersion = trim(tokens[0]);
}
int statusCode = -1;
if (tokens.size() >= 2)
{
std::stringstream ss;
ss << trim(tokens[1]);
ss >> statusCode;
}
return std::make_pair(httpVersion, statusCode);
}
std::tuple<std::string, std::string, std::string> Http::parseRequestLine(const std::string& line)
{
// Request-Line = Method SP Request-URI SP HTTP-Version CRLF

View File

@@ -115,6 +115,8 @@ namespace ix
std::shared_ptr<Socket> socket);
static bool sendResponse(HttpResponsePtr response, std::shared_ptr<Socket> socket);
static std::pair<std::string, int> parseStatusLine(
const std::string& line);
static std::tuple<std::string, std::string, std::string> parseRequestLine(
const std::string& line);
static std::string trim(const std::string& str);

View File

@@ -164,23 +164,26 @@ namespace ix
}
// Validate status
int status;
auto statusLine = Http::parseStatusLine(line);
std::string httpVersion = statusLine.first;
int status = statusLine.second;
// HTTP/1.0 is too old.
if (sscanf(line.c_str(), "HTTP/1.0 %d", &status) == 1)
if (httpVersion != "HTTP/1.1")
{
std::stringstream ss;
ss << "Server version is HTTP/1.0. Rejecting connection to " << host
ss << "Expecting HTTP/1.1, got " << httpVersion << ". "
<< "Rejecting connection to " << host << ":" << port
<< ", status: " << status
<< ", HTTP Status line: " << line;
return WebSocketInitResult(false, status, ss.str());
}
// We want an 101 HTTP status
if (sscanf(line.c_str(), "HTTP/1.1 %d", &status) != 1 || status != 101)
if (status != 101)
{
std::stringstream ss;
ss << "Got bad status connecting to " << host
ss << "Got bad status connecting to " << host << ":" << port
<< ", status: " << status
<< ", HTTP Status line: " << line;
return WebSocketInitResult(false, status, ss.str());
@@ -295,9 +298,15 @@ namespace ix
return sendErrorResponse(400, "Missing Sec-WebSocket-Key value");
}
if (headers.find("upgrade") == headers.end())
{
return sendErrorResponse(400, "Missing Upgrade header");
}
if (!insensitiveStringCompare(headers["upgrade"], "WebSocket"))
{
return sendErrorResponse(400, "Invalid or missing Upgrade header");
return sendErrorResponse(400, "Invalid Upgrade header, "
"need WebSocket, got " + headers["upgrade"]);
}
if (headers.find("sec-websocket-version") == headers.end())

View File

@@ -681,8 +681,12 @@ namespace ix
reason = WebSocketCloseConstants::kInvalidFramePayloadDataMessage;
}
//
// Validate close codes. Autobahn 7.9.*
// 1014, 1015 are debattable. The firefox MSDN has a description for them
// 1014, 1015 are debattable. The firefox MSDN has a description for them.
// Full list of status code and status range is defined in the dedicated
// RFC section at https://tools.ietf.org/html/rfc6455#page-45
//
if (code < 1000 || code == 1004 || code == 1006 ||
(code > 1013 && code < 3000))
{

View File

@@ -6,4 +6,4 @@
#pragma once
#define IX_WEBSOCKET_VERSION "6.2.0"
#define IX_WEBSOCKET_VERSION "6.2.1"

View File

@@ -9,7 +9,7 @@ install: brew
# on osx it is good practice to make /usr/local user writable
# sudo chown -R `whoami`/staff /usr/local
brew:
mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 .. ; make -j install)
mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 -DUSE_TEST=1 .. ; make -j install)
ws:
mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 -DUSE_MBED_TLS=1 .. ; make -j)
@@ -47,7 +47,7 @@ trail:
sh third_party/remote_trailing_whitespaces.sh
format:
find test ixwebsocket ws -name '*.cpp' -o -name '*.h' -exec clang-format -i {} \;
clang-format -i `find test ixwebsocket ws -name '*.cpp' -o -name '*.h'`
# That target is used to start a node server, but isn't required as we have
# a builtin C++ server started in the unittest now
@@ -58,7 +58,8 @@ test_server:
# env TEST=Websocket_chat make test
# env TEST=heartbeat make test
test:
python2.7 test/run.py
mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 -DUSE_TEST=1 .. ; make -j)
(cd test ; python2.7 run.py -r)
ws_test: ws
(cd ws ; env DEBUG=1 PATH=../ws/build:$$PATH bash test_ws.sh)

View File

@@ -15,8 +15,6 @@ if (MAC)
option(USE_TLS "Add TLS support" ON)
endif()
add_subdirectory(${PROJECT_SOURCE_DIR}/.. ixwebsocket)
set (WS ../ws)
include_directories(
@@ -36,17 +34,6 @@ set (SOURCES
../third_party/msgpack11/msgpack11.cpp
../third_party/jsoncpp/jsoncpp.cpp
${WS}/ixcore/utils/IXCoreLogger.cpp
${WS}/ixcrypto/IXBase64.cpp
${WS}/ixcrypto/IXHash.cpp
${WS}/ixcrypto/IXUuid.cpp
${WS}/ixcrypto/IXHMac.cpp
${WS}/ixcobra/IXCobraConnection.cpp
${WS}/ixcobra/IXCobraMetricsPublisher.cpp
${WS}/ixcobra/IXCobraMetricsThreadedPublisher.cpp
${WS}/snake/IXSnakeServer.cpp
${WS}/snake/IXSnakeProtocol.cpp
${WS}/snake/IXAppConfig.cpp
@@ -62,13 +49,14 @@ set (SOURCES
IXHttpClientTest.cpp
IXHttpServerTest.cpp
IXUnityBuildsTest.cpp
IXHttpTest.cpp
)
# Some unittest don't work on windows yet
if (UNIX)
list(APPEND SOURCES
IXDNSLookupTest.cpp
cmd_websocket_chat.cpp
IXWebSocketChatTest.cpp
IXWebSocketCloseTest.cpp
IXCobraChatTest.cpp
IXCobraMetricsPublisherTest.cpp
@@ -98,5 +86,9 @@ if (APPLE AND USE_TLS)
target_link_libraries(ixwebsocket_unittest "-framework foundation" "-framework security")
endif()
target_link_libraries(ixwebsocket_unittest ixcore)
target_link_libraries(ixwebsocket_unittest ixcrypto)
target_link_libraries(ixwebsocket_unittest ixcobra)
target_link_libraries(ixwebsocket_unittest ixwebsocket)
install(TARGETS ixwebsocket_unittest DESTINATION bin)

View File

@@ -309,6 +309,7 @@ TEST_CASE("Cobra_chat", "[cobra_chat]")
timeout -= 10;
if (timeout <= 0)
{
snakeServer.stop();
REQUIRE(false); // timeout
}
}
@@ -332,6 +333,7 @@ TEST_CASE("Cobra_chat", "[cobra_chat]")
timeout -= 10;
if (timeout <= 0)
{
snakeServer.stop();
REQUIRE(false); // timeout
}
}

View File

@@ -23,7 +23,6 @@ namespace ix
int getAnyFreePort()
{
int defaultPort = 8090;
int sockfd;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
@@ -89,5 +88,3 @@ namespace ix
return -1;
}
} // namespace ix

View File

@@ -28,7 +28,6 @@ namespace
void stop();
void stop(uint16_t code, const std::string& reason);
bool isReady() const;
void sendMessage(const std::string& text);
uint16_t getCloseCode();
const std::string& getCloseReason();
@@ -171,11 +170,6 @@ namespace
_webSocket.start();
}
void WebSocketClient::sendMessage(const std::string& text)
{
_webSocket.send(text);
}
bool startServer(ix::WebSocketServer& server,
uint16_t& receivedCloseCode,
std::string& receivedCloseReason,

View File

@@ -112,6 +112,8 @@ TEST_CASE("Websocket_server", "[websocket_server]")
auto lineResult = socket->readLine(isCancellationRequested);
auto lineValid = lineResult.first;
REQUIRE(lineValid);
auto line = lineResult.second;
int status = -1;
@@ -149,6 +151,8 @@ TEST_CASE("Websocket_server", "[websocket_server]")
auto lineResult = socket->readLine(isCancellationRequested);
auto lineValid = lineResult.first;
REQUIRE(lineValid);
auto line = lineResult.second;
int status = -1;
@@ -190,6 +194,8 @@ TEST_CASE("Websocket_server", "[websocket_server]")
auto lineResult = socket->readLine(isCancellationRequested);
auto lineValid = lineResult.first;
REQUIRE(lineValid);
auto line = lineResult.second;
int status = -1;

View File

@@ -350,10 +350,11 @@ def generateXmlOutput(results, xmlOutput, testRunName, runTime):
def run(testName, buildDir, sanitizer, xmlOutput,
testRunName, buildOnly, useLLDB, cpuCount):
testRunName, buildOnly, useLLDB, cpuCount, runOnly):
'''Main driver. Run cmake, compiles, execute and validate the testsuite.'''
# gen build files with CMake
if not runOnly:
runCMake(sanitizer, buildDir)
if platform.system() == 'Linux':
@@ -454,6 +455,8 @@ def main():
help='Validate XML output.')
parser.add_argument('--build_only', '-b', action='store_true',
help='Stop after building. Do not run the unittest.')
parser.add_argument('--run_only', '-r', action='store_true',
help='Only run the test, do not build anything.')
parser.add_argument('--output', '-o', help='Output XML file.')
parser.add_argument('--lldb', action='store_true',
help='Run the test through lldb.')
@@ -492,7 +495,7 @@ def main():
if platform.system() == 'Windows':
TEST_EXE_PATH = os.path.join(buildDir, BUILD_TYPE, 'ixwebsocket_unittest.exe')
else:
TEST_EXE_PATH = os.path.join(buildDir, 'ixwebsocket_unittest')
TEST_EXE_PATH = '../build/test/ixwebsocket_unittest'
if args.list:
# catch2 exit with a different error code when requesting the list of files
@@ -511,7 +514,7 @@ def main():
args.lldb = False
return run(args.test, buildDir, sanitizer, xmlOutput,
testRunName, args.build_only, args.lldb, args.cpu_count)
testRunName, args.build_only, args.lldb, args.cpu_count, args.run_only)
if __name__ == '__main__':

File diff suppressed because it is too large Load Diff

View File

@@ -4945,8 +4945,3 @@ std::ostream& operator<<(std::ostream& sout, Value const& root) {
// //////////////////////////////////////////////////////////////////////
// End of content of file: src/lib_json/json_writer.cpp
// //////////////////////////////////////////////////////////////////////

View File

@@ -41,4 +41,3 @@
[ ] Question
[ ] Enhancement
[ ] Bug

View File

@@ -120,4 +120,3 @@ In addition to providing options for testing client-side features, the `ssl_clie
* [`x509/crl_app.c`](x509/crl_app.c): loads and dumps a certificate revocation list (CRL).
* [`x509/req_app.c`](x509/req_app.c): loads and dumps a certificate signing request (CSR).

View File

@@ -35,17 +35,6 @@ add_executable(ws
../third_party/jsoncpp/jsoncpp.cpp
${STATSD_CLIENT_SOURCES}
ixcore/utils/IXCoreLogger.cpp
ixcrypto/IXBase64.cpp
ixcrypto/IXHash.cpp
ixcrypto/IXUuid.cpp
ixcrypto/IXHMac.cpp
ixcobra/IXCobraConnection.cpp
ixcobra/IXCobraMetricsPublisher.cpp
ixcobra/IXCobraMetricsThreadedPublisher.cpp
snake/IXSnakeServer.cpp
snake/IXSnakeProtocol.cpp
snake/IXAppConfig.cpp
@@ -73,6 +62,9 @@ add_executable(ws
ws_autobahn.cpp
ws.cpp)
target_link_libraries(ws ixcore)
target_link_libraries(ws ixcrypto)
target_link_libraries(ws ixcobra)
target_link_libraries(ws ixwebsocket)
if(NOT APPLE AND NOT USE_MBED_TLS)

View File

@@ -21,12 +21,7 @@
//
//
// 2 Run the test server (using docker)
// docker run -it --rm \
// -v "${PWD}/config:/config" \
// -v "${PWD}/reports:/reports" \
// -p 9001:9001 \
// --name fuzzingserver \
// crossbario/autobahn-testsuite
// docker run -it --rm -v "${PWD}/config:/config" -v "${PWD}/reports:/reports" -p 9001:9001 --name fuzzingserver crossbario/autobahn-testsuite
//
// 3. Run this command
// ws autobahn -q --url ws://localhost:9001
@@ -315,4 +310,3 @@ namespace ix
return generateReport(url) ? 0 : 1;
}
}